|
|
View previous topic :: View next topic |
Author |
Message |
Skirmitt
Joined: 19 May 2009 Posts: 60
|
Generating a diesel sound with PIC 16F886 (WAVE to PWM) |
Posted: Tue May 19, 2009 3:34 am |
|
|
Hi,
I'm new to the board, have been reading in the past and found a lot of info to get me further but this time I need some more help.
I'm an RC model builder and for my truck I want to build a module wich generates a diesel sound. I found a http://www.enide.net/webcms/index.php?page=pcm2pwm website wich gives some source code to play wave files with a PIC. Looks pretty simple but I fail at converting the code for the CCS compiler. Can someone help me with this ?
I do have a small diesel engine sample that sounds good when played in a loop. I also found Romans converter to generate the codes to be programmed in the PIC. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Skirmitt
Joined: 19 May 2009 Posts: 60
|
|
Posted: Wed May 20, 2009 2:52 am |
|
|
I've never worked with timers or PWM before, that's the biggest problem.
Here's my code so far:
Code: |
#include <16F886.h>
#fuses HS,NOLVP,NOWDT
#use delay (clock=4000000)
const char okay[10]= {0x39, 0x26, 0x26, 0x26, 0x26, 0x51, 0x77, 0x8C, 0x7C, 0x85};
unsigned char sample;
volatile int wait;
void initPic(void)
{
// timer settings here ?
}
void interrupt hi_isr(void)
{
if(TMR2IF)
{
if(wait) wait--;
TMR2IF = 0;
}
}
void setPWM(unsigned char sample)
{
CCPR1L = sample >> 2;
DC1B1 = (sample&0x02)>>1;
DC1B0 = (sample&0x01);
}
void play(const char *sound, int size)
{
int i;
for(i=0; i<size; i++)
{
set_pwm1_duty(sound[i]); //setPWM(sound[i]);
wait=1;
while(wait);
}
}
void pause(int cycles)
{
setPWM(0);
wait=cycles;
while(wait);
}
void main(void)
{
initPic();
while(1)
{
wait=1;
while(wait);
play(okay, 10);
}
while(1);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 20, 2009 2:41 pm |
|
|
That code is written for an 18F1320 and uses the Hi-Tech compiler.
You're trying to use a 16F886 and CCS.
In his ok.h file, he has a large 'const' array of 5399 bytes.
http://www.enide.net/webcms/uploads/files/projects/pcm2pwm/ok.h
The CCS PCH compiler can accept this size of an array. The PCM
compiler (for the 16F886) can't do it directly. It has a size limit on 'const'
arrays of 256 bytes. There are work-arounds for this problem. See this
link:
http://www.ccsinfo.com/forum/viewtopic.php?t=36526
How important is it to you, to do this project with a 16F PIC ?
It would be easier to use an 18F (if you have the PCH compiler).
The main part of his code just requires translation from CCS.
http://www.enide.net/webcms/uploads/files/projects/pcm2pwm/happy.c
In Hi-Tech C, an 'int' is a 16-bit signed integer. So in CCS, you would
substituted 'signed long' or 'signed int16', wherever you see 'int' in his
code.
His code clearly states that he's running the PIC at 8 MHz, not at 4 MHz.
He is using the internal oscillator to do this, so the fuse would be INTRC_IO.
Hi-Tech C requires the programmer do low-level setup. His entire
setup routine can be written in CCS in a few lines. Example:
Code: | void init_PIC(void)
{
setup_timer_2(T2_DIV_BY_1, K_TMR2, 1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0L);
clear_interrupt(INT_TIMER2);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
} |
His setPWM() routine is really just setting the PWM duty cycle, which
can be done with one line in CCS. It's clear that he's using 10-bit PWM,
so the parameter must be cast to an int16 to force the compiler to use
that mode.
Code: | void setPWM(unsigned char sample)
{
set_pwm1_duty((int16)sample);
} |
His Timer2 interrupt routine must be written using CCS methods.
Code: |
#int_timer2
void hi_isr(void)
{
if(wait) wait--;
} |
Another important issue is that his play() routine expects a pointer to
a 'const' array. CCS can't do this. To fix this problem, you could just
take the "guts" of the play() routine and move it into the while(1) loop
in his main(). In other words, don't call the play() code as a function.
Just put the code into the main() loop, as inline code.
And remember to change all 'int' declarations to be 'signed int16',
or actually, just 'int16' would work, since I don't see any usage of
signed values in his code. |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Fri Oct 01, 2010 1:31 pm |
|
|
Hi,
I just finished a project that uses this method of generating sampled sounds. I used info found on the internet and ported the Hi-Tech code to CCS. The original source code has comments in Portuguese, amazing how helpful Google Translate can be!
Anyway, after finishing the project I stumbled upon this discussion. In the previous post PCM programmer states correctly that the original code uses 10 bit PWM and shows CCS code that makes this from an 8 bit value. What I did (not hampered by too much knowledge) is just use the 8 bit value from the array and set_pwm1_duty(value). I reasoned these are 8 bit values to begin with, so why would I change that into 10 bits then by shifting in a couple of MS zeros? The results were adequate so I did not think about that any more until now. I got interested and changed my code to the set_pwm1_duty((int16)value). The result was as expected, exactly the same sound, but a lot less louder. So I reverted to my old code.
Another thing of interest, I changed the sampling rate to 16KHz. I (obviously) had to resample the sounds and they became twice as big, but the quality is better and it gets rid of the annoying sampling frequency noise.
Hope someone can use this.
Paul |
|
|
Raulsoft
Joined: 28 Jan 2010 Posts: 6
|
|
Posted: Wed Jun 06, 2012 3:50 pm |
|
|
Woody wrote: | Hi,
I just finished a project that uses this method of generating sampled sounds. I used info found on the internet and ported the Hi-Tech code to CCS. The original source code has comments in Portuguese, amazing how helpful Google Translate can be!
Anyway, after finishing the project I stumbled upon this discussion. In the previous post PCM programmer states correctly that the original code uses 10 bit PWM and shows CCS code that makes this from an 8 bit value. What I did (not hampered by too much knowledge) is just use the 8 bit value from the array and set_pwm1_duty(value). I reasoned these are 8 bit values to begin with, so why would I change that into 10 bits then by shifting in a couple of MS zeros? The results were adequate so I did not think about that any more until now. I got interested and changed my code to the set_pwm1_duty((int16)value). The result was as expected, exactly the same sound, but a lot less louder. So I reverted to my old code.
Another thing of interest, I changed the sampling rate to 16KHz. I (obviously) had to resample the sounds and they became twice as big, but the quality is better and it gets rid of the annoying sampling frequency noise.
Hope someone can use this.
Paul |
Hello Paul.
Could you please send me the original link or source that thought he could find on the internet?
tanks |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|