View previous topic :: View next topic |
Author |
Message |
GOBER
Joined: 22 Jul 2010 Posts: 41
|
Variable pulse-duty-cycle PWM |
Posted: Fri Jul 23, 2010 12:11 am |
|
|
Hello
I'm trying to implement a PWM at 4khz.
However, what I need mostly is to make each cycle of this pwm have a different duty cycle (in an attempt to generate a sine wave). Some people suggested that I use Timer 1 to generate interrupt every 4khz frequency and in the ISR I change the PWM duty cycle. I tried it but it is not working maybe because I did it wrong.
Can anybody suggest something or give me some code to do this. I'm using PIC16F877A. XT=8MHz (to get exact 4KHz PWM frequency). |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 23, 2010 12:25 am |
|
|
Change the duty cycle of the PWM inside an #int_timer2 interrupt routine.
Example:
http://www.ccsinfo.com/forum/viewtopic.php?t=41473&start=3
Get the duty cycle from a sine lookup table. Here are some CCS
example files that use sine lookup tables:
Quote: |
c:\program files\picc\examples\ex_dtmf.c
c:\program files\picc\examples\ex_sine.c
c:\program files\picc\examples\ex_usb_scope.c
|
|
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
|
Posted: Fri Jul 23, 2010 3:24 am |
|
|
It doesn't look that this is what i needed so to be more specific, here is a link on what i'm trying to do
www.pu.edu.pk/ceet/Pages/Prospectus.pdf
please PCM Programmer help me implement the idea in this article.
what i'm trying to do first is to generate the variable PWM duty cycle for the sine wave shownin the figure page 2 figure 3.
can this kind of figure be implemented in MCU
Thanks in Advance |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 23, 2010 9:43 pm |
|
|
I don't want to write your program for you. I suggest that you use
Google to search for code using these search terms:
Quote: |
pwm "sine wave" void main
|
Or you can search for CCS code with this:
Quote: |
pwm "sine wave" "#use delay"
|
But not all of the code will be certain to work correctly. You will have to test it. |
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
|
Posted: Sat Jul 24, 2010 12:30 am |
|
|
Ok PCM Programmer I wasn't really looking for someone to write me the code all I needed is some help and ideas. Anyway I re-arranged the code that you supplied and it is working fine for me now.
But I need to ask you two more questions
First is about the pwm resolution and what does it mean exactly.
What I understood it that it represents how many value of the duty cycle you can put in one period. However, when programming, I noticed that even if I have a 10-bit resolution, I can't go anywhere above the value of the PR2 register. For example, if I have a 10-bit resolution, I can choose one from the 65536 values of the duty cycle. However, if the PR2 is 126, say, any value above the 126 will result in a 100% duty cycle. So please explain it to me.
Second question is, do you only spend all your time in programming, as I see that you reply to all people in all domains, day and night. Really!!.
How come you have that passion and that time to do that man, knowing that I congratulate you and appreciate the enormous help you are providing, but I have the curiosity to ask you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
|
Posted: Tue Jul 27, 2010 1:48 am |
|
|
OK PCM Programmer, one more problem
here is my new problem
I'm using a crystal oscillator at 8MHz, and i wish to get a 4KHz pwm frequency. according to the wizard in CCS, it generated a code with PR2=124 and timer2 prescaler=4. at these frequencies, according to the resolution formula, i can get a 10-bit resolution. However, any value that i insert which is greater than the PR2 value results in a fault.
please explain this for me and how to manage the relationships between xt value and PWM frequency and resolution all together.
i tried 10000000000000 of examples that i did changing some value each time for the pr2, the PWM frequency and the prescaler.
All gave the same confusion
will you please remove the confusion and help me |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Tue Jul 27, 2010 1:56 am |
|
|
The maximum available PWM value, is always:
((PR2+1)*4)-1
So with PR2 at it's largest possible value (255), you get:
((255+1)*4)-1 = 1023
With your PR2 value (124), you will get 499. Just under 9 bits, not 10 bits.
Remember also, that the value fed into the set PWM duty function, _must_ be a 'long' integer, not a default 8bit integer, or you will lose two bits from the bottom of the allowable values.
Best Wishes |
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
|
Posted: Tue Jul 27, 2010 2:15 am |
|
|
Now this is something useful.
Thanks Ttelmah, but this means that there is something wrong with the formulas in the datasheets, or they are missing something. Would you mind writing the right ones for me. And if you may, please post some code that gives me the best resolution for a 4khz frequency of pwm, no matter what the xtal frequency is (you choose it).
Thanks in advance |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19551
|
|
Posted: Tue Jul 27, 2010 3:13 am |
|
|
No, the formulae in the data sheet are exactly right. I think you are misinterpreting them....
If you look at table 8.3 for example, you will see that the 'bit length' of the available range, is the bit length of the PR2 value, plus two bits. So it is only 10 bits, when PR2 contains a value 'filling' the 8bit range (0xFF). Anything less and the value drops.
Remember 'Fosc' feeding the PWM, is _after_ the prescaler.
In your case, Fosc, is 2MHz. So the formula gives:
log(2000000/4000)/log(2) = 8.96
Just under 9 bits.
Best Wishes |
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
|
Posted: Tue Jul 27, 2010 4:27 am |
|
|
Thanks Ttelmah this really explains what I was missing.
However, I need your help now in my program.
I'm trying to generate sine wave using pwm. This is the code I'm using. You will see that there is some time at the end of the cycle where the duty cycle suddenly becomes 100% (I think) and then falls back to zero and goes on correctly. Can you please take a look at it in Proteus and tell me what am I doing wrong.
Code: |
#include "D:\Projects\CCS C Software projects\Sine Wave Oscillator\Sine Wave Oscillator.h"
#define MAX_DUTY 501
int i=0;
long duty_cycle[21]={0,39,78,117,155,192,227,262,294,325,354,381,405,427,446,463,476,487,495,499,501};
#int_TIMER2
void TIMER2_isr(void)
{
static int8 increment = TRUE;
if(increment)
{
i++;
if(duty_cycle[i] == MAX_DUTY)
increment = FALSE;
}
else
{
i--;;
if(duty_cycle[i] == 0)
increment = TRUE;
}
set_pwm1_duty(duty_cycle[i]);
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_4,124,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
clear_interrupt(INT_TIMER2);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
duty_cycle = 0;
output_high(PIN_C0);
output_low(PIN_C1);
while(1);
}
|
The header file above include these:
Code: |
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES PUT //Power Up Timer
#FUSES PROTECT //Code protected from reads
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=8000000) |
|
|
|
RoGuE_StreaK
Joined: 02 Feb 2010 Posts: 73
|
|
Posted: Tue Jul 27, 2010 6:53 am |
|
|
Having done sound semi-successfully myself (see above link), can I suggest that you instead use timer0 for your frequency interrupt, to seperate it out from timer2 which effects your sample resolution?
Change timer2 so you get the resolution you need for your PWM, and let timer0 take care of when you index through your array.
You also want the frequency of the PWM to be much higher than that of your actual sound, otherwise you'll get a heap of ugly aliasing artefacts etc.
As an aside, your "increment" variable is a boolean, so only needs to be int1, not int8. And you've got double ";" after "i--" |
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
12f683 problem |
Posted: Mon Aug 09, 2010 4:22 am |
|
|
Ok after trying everything with PIC16F877A (as it was available to me), everything worked fine. Now I switched to PIC12F683 with the same program (of course I made the necessary changes). The results are totally wrong. My program is listed above. Can anybody try it on PIC12F683 and tell what's wrong. |
|
|
GOBER
Joined: 22 Jul 2010 Posts: 41
|
|
Posted: Mon Aug 09, 2010 5:24 am |
|
|
I also made this small test program.
Code: |
void main()
{
int i;
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_4,124,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_8MHZ);
for(i=0;i<100;i++)
{
set_pwm1_duty(i);
delay_ms(100);
}
}
|
It is not working. The pwm duty cycle won't change.
I used the wizard to start my project.
ccs version is 4.104 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
|