Angry Badger
Member
Hi,
My first attempt at 'simple' pwm.
In the 16f1824 data sheet there is a table, shown below. If I understand it correctly it should be possible to get a 0 to 100% duty cycle, in 256 increments, using the values in the table. But using those values only gives me a 0 to 62.5% duty cycle. Reducing the value in PR2 from 0x65 to 0x3f does give 0 to 100% but at a higher frequency, 1.95KHz, vs the stated 1.22KHz.
The higher frequency isn't a problem but why doesn't the default PR2 value give the full range of period? I'm misunderstanding something or my code is wrong. Can you point me in the right direction?
View attachment 68959
Thanks in advance for any help.
My first attempt at 'simple' pwm.
In the 16f1824 data sheet there is a table, shown below. If I understand it correctly it should be possible to get a 0 to 100% duty cycle, in 256 increments, using the values in the table. But using those values only gives me a 0 to 62.5% duty cycle. Reducing the value in PR2 from 0x65 to 0x3f does give 0 to 100% but at a higher frequency, 1.95KHz, vs the stated 1.22KHz.
The higher frequency isn't a problem but why doesn't the default PR2 value give the full range of period? I'm misunderstanding something or my code is wrong. Can you point me in the right direction?
View attachment 68959
Code:
#include <xc.h>
/*------------------------------------------------------------------------*/
#pragma config FOSC = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = ON, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, CLKOUTEN = OFF, IESO = OFF, FCMEN = OFF
#pragma config WRT = OFF, PLLEN = OFF, STVREN = OFF, BORV = LO, LVP = OFF
/*------------------------------------------------------------------------*/
#define _XTAL_FREQ 8000000 /* Not using xtal, only to make delays work as
it won't compile without this */
/*------------------------------------------------------------------------*/
int x;
/*------------------------------------------------------------------------*/
void pwm_init (void);
/*------------------------------------------------------------------------*/
void main (void)
{
OSCCON = 0b01110010; // Fosc = 8MHz (Inst. clk = 2MHz)
TRISA = 0; // All outputs
TRISC = 0; // All outputs
ADCON0bits.ADON = 0; // No analog inputs
pwm_init(); // Set up the pwm
/********* Start of main program loop **********/
/* This gives 256 discrete periods but max 62.5% duty cycle when PR2 = 0x65
PWM f is 1.22KHz as per data sheet
Reducing PR2 to 0x3f gives 100% duty cycle but PWM f is then 1.95KHz */
while(1)
for(x = 0; x < 256; x++) // Increment the period
{
CCPR3L = ( x >> 2); // 6 MSBs
CCP3CON = (CCP3CON & ~0x30 | (x << 4)); // 2 LSBs
__delay_ms(100); // So incremental change in period can be viewed on scope
}
//********** End of main program loop ************
}
void pwm_init (void)
{
TRISAbits.TRISA2 = 1; // Disable pin output driver (CCP3)
//PR2 = 0x3f; // PWM f = 1.95kHz / 0 to 100% period
PR2 = 0x65; // PWM f = 1.22kHz / 0 to 62.5% period
CCP3CON = 0b00001100; // bit 7-6 Enhanced PWM bits (00 = single o/p)
// bit 5-4 Duty cycle LSBs
// bit 3-0 ECCPx mode select bits (11xx = PWM)
CCPR3L = 0b00000000; // Alters duty cycle
CCPTMRS0 = 0b11001111; // bit 5-4 CCP3 timer selection, 00 = TMR2
PIR1bits.TMR2IF = 0; // Clear the interrupt flag
T2CON = 0b00000110; // Postscaler = 0, prescaler = 16, timer = on
while (!PIR1bits.TMR2IF) // Wait until the Timer overflows and the
{} // TMRxIF bit of the PIRx register is set.
TRISAbits.TRISA2 = 0; // Enable the CCPx pin output driver by
// clearing the associated TRIS bit.
}
Thanks in advance for any help.