Hi, I'm trying to generate a half wave sinusoidal PWM signal but failing to get the right result. I've calculated values of duty cycle then loaded them sequentially into the CCPR1L (duty cycle reg). I've ran through debug and it seems to work in theory but when I run it in Proteus only the centre 20 values/pulses show with flat line for the rest of the signal. When I scroll back on the oscilloscope to the beginning it seems to start ok but once the DC starts to fall (maybe about ~231) it goes flat until the next cycle. I've tried with less values of sine, lower frequency but I'm sure I'm doing something stupid in the code. Would appreciate it if someone could have a look.
Code was compiled with MikroC, clock 20MHz, PWM Period 204uS, Target Frequency = 49*204E-6=10mS (half wave):
unsigned char sinedc[49]={ 0, 16, 32, 48, 64, 80, 95, 110,
124, 138, 151, 164, 176, 187, 198, 207,
216, 224, 231, 237, 243, 247, 250, 252,
253, 253, 252, 250, 247, 243, 237, 231,
224, 216, 208, 198, 187, 176, 164, 152,
138, 124, 110, 95, 80, 64, 49, 33,
17
};
unsigned char dctrans; //for int to char conversion
unsigned int a; //Loop counter
unsigned int di; //Number of divisions
void interrupt() //Interrupt Function
{
/*Create loop using counter. Reset counter after each cycle.
Use counter as pointer to values in char string.
*/
if(TMR2IF_bit==1) //At PWM period end
{
if(a>di) //when counter reaches end of string
{
a=0; //reset counter
}
else
{
dctrans=a; //converts int to char
CCPR1L = sinedc[dctrans]; //Loads values from sine char string
//to DC
a++; //increment counter
TMR2IF_bit = 0; //TMR2IF reset
}
}
}
void main() {
/*Set values for the counter (a), 0 to start and the number of divisions (di)
*/
/*DC Loading*/
a=0;
di=49;
/*Initialize Ports*/
TRISC = 0; //Set all Port C to outputs (O/Ps)
PORTC = 0; //Clear all Port C O/Ps
/*Initialize Interrupts*/
INTCON = 0b11000000; //<7> Global Intrpt En (GIE), <6> Perip.
//Intrpt En (PEIE)
PIE1 = 0b00000010; //<1> TMR2IE: TMR2/PR2 Match Intrpt En
TMR2IF_bit = 0; //Set TMR2/PR2 Match flag low
/*Initialize PWM*/
PR2 = 254; //Timer2 Period Register - Period of PWM (MAX 255)
CCP1CON = 0b00111100; //<5:4> DC LSBs, <3:2> PWM Mode
T2CON = 0b00000101; //<2> enables Timer2, <1:0> prescaler = 4
while(1);
}
Code was compiled with MikroC, clock 20MHz, PWM Period 204uS, Target Frequency = 49*204E-6=10mS (half wave):
unsigned char sinedc[49]={ 0, 16, 32, 48, 64, 80, 95, 110,
124, 138, 151, 164, 176, 187, 198, 207,
216, 224, 231, 237, 243, 247, 250, 252,
253, 253, 252, 250, 247, 243, 237, 231,
224, 216, 208, 198, 187, 176, 164, 152,
138, 124, 110, 95, 80, 64, 49, 33,
17
};
unsigned char dctrans; //for int to char conversion
unsigned int a; //Loop counter
unsigned int di; //Number of divisions
void interrupt() //Interrupt Function
{
/*Create loop using counter. Reset counter after each cycle.
Use counter as pointer to values in char string.
*/
if(TMR2IF_bit==1) //At PWM period end
{
if(a>di) //when counter reaches end of string
{
a=0; //reset counter
}
else
{
dctrans=a; //converts int to char
CCPR1L = sinedc[dctrans]; //Loads values from sine char string
//to DC
a++; //increment counter
TMR2IF_bit = 0; //TMR2IF reset
}
}
}
void main() {
/*Set values for the counter (a), 0 to start and the number of divisions (di)
*/
/*DC Loading*/
a=0;
di=49;
/*Initialize Ports*/
TRISC = 0; //Set all Port C to outputs (O/Ps)
PORTC = 0; //Clear all Port C O/Ps
/*Initialize Interrupts*/
INTCON = 0b11000000; //<7> Global Intrpt En (GIE), <6> Perip.
//Intrpt En (PEIE)
PIE1 = 0b00000010; //<1> TMR2IE: TMR2/PR2 Match Intrpt En
TMR2IF_bit = 0; //Set TMR2/PR2 Match flag low
/*Initialize PWM*/
PR2 = 254; //Timer2 Period Register - Period of PWM (MAX 255)
CCP1CON = 0b00111100; //<5:4> DC LSBs, <3:2> PWM Mode
T2CON = 0b00000101; //<2> enables Timer2, <1:0> prescaler = 4
while(1);
}