The PIC16F877A PWM Module:
16F877a includes two PWM modules included in the CCP1,CCP2 modules (CCP stands for Capture-Compare-PWM), and there are 3 steps for using those modules:
- Set the desired CCP module to PWM mode.
- Setup The TIMER2 module, which controls the frequency and the base of your PWM signal.
- Set your duty cycle, rely on the equations below to select it properly.
To set The CCP1 module to PWM mode, we'll use the code line:
setup_ccp1(CCP_PWM);and the first step is done.
Now setting up Timer2 module using PIC-C is a bit easy, use the code line: setup_timer_2(divider,preload,postscalar).
the divider and the preload values determines the frequency of the PWM signal by the following function:
Signal Frequency = (Crystal/4) / (divider * (preload+1))
The divider takes the values : T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16.
the preload is 8Bits and takes the values 0-255
So let us say we have 4MHz crystal and we set Timer2 like this:
setup_timer_2( T2_DIV_BY_1, 255, 1);thus, our signal frequency is (4MHz/1)/(4 * 256) = 3.9KHz
Now the final step is to set your duty cycle using the function: set_pwm1_duty(duty_parameter);
to get the duty_parameter of your desired duty cycle, note the following:
the maximum value of duty_paramter (MAX) = ((preload+1)*4) -1
so in our case the maximum value is ((255+1)*4)-1 = 1023 and it represents a 100% duty cycle.
now if we need a duty cycle of 50% it would be 1023*0.5 = 512, and a duty cycle of 25% would be 1023*0.25 = 256, thus,
set_pwm1_duty(1023L); ---> 100% duty (Full Speed)
set_pwm1_duty(512L); ----> 50% duty
set_pwm1_duty(256L); ----> 25% duty
set_pwm1_duty(0); ----> 0% duty (OFF)
So this is the program to control the PWM driver, from the value of the temperature it will convert the value to the PWM driver
#include <16f877a.h>
#device adc=10 // Set ADC resolution to 10Bit
#fuses XT,NOLVP,NOWDT,NOPROTECT
#use delay(clock=4000000)
#include "LCD.c"
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_E PIN_D0
#define LCD_RS PIN_D1
#define LCD_RW PIN_D2
#define Wire1 PIN_B6
#define LOAD1 PIN_B5
#define LOAD3 PIN_B7
#define THRES1 28.0 // load switching threshold in Celsius
#define THRES2 36.0 // load switching in Celcius
#define THRES3 42.0 // load switching in Celcius
int16 digital_reading,duty_cycle=1023; // ADC resolution is 10Bit, an 8Bit integer is not enough to hold the reading
float temp;
void main()
{
/* ADC Initialization */
setup_adc(ADC_CLOCK_INTERNAL); // initialize ADC with a sampling rate of Crystal/4 MHz
setup_adc_ports(RA0_ANALOG); // set PIN_A0 as analog input channel
set_adc_channel(0); // point ADC to channel 0 for ADC reading
delay_ms(1); // ADC module is slow, needs some time to adjust.
/* Peripherals Configurations */
lcd_init(); // Turn LCD ON, along with other initialization commands
output_low(LOAD1); // the load is initially OFF
lcd_gotoxy(1,1); // point LCD cursor to col1 row1
lcd_putc("Temperature is:"); // print on LCD
/* PWM Configurations */
setup_timer_2(T2_DIV_BY_1,255,1); // Set PWM frequency
setup_ccp1(CCP_PWM); // Configure CCP1 to PWM mode
set_pwm1_duty(1023L); // default duty cycle = 100% (Full Speed)
while(1) // infinite loop
{
digital_reading = read_adc(); // capture current temperature reading
delay_us(100); // 0.1ms delay for ADC stabilization
temp = digital_reading * 0.4883; // convert reading to Celsius
lcd_gotoxy(1,2); // point LCD cursor to col1 row2
printf(lcd_putc,"%2.1f C",temp); // print value on LCD
if((temp>=THRES1)&&(temp<THRES2));
{
output_toggle(Wire1);
duty_cycle=437.5; // increase the duty cycle(70%)
set_pwm1_duty(duty_cycle); // set the duty cycle
}
if ((temp>=THRES2)&&(temp<=THRES3));
{
output_toggle(Wire1);
duty_cycle=531.25; // increase the duty cycle(850%)
set_pwm1_duty(duty_cycle); // set the duty cycle
}
if (temp>THRES3);
{
output_toggle(Wire1);
duty_cycle=625; // increase the duty cycle(100%)
set_pwm1_duty(duty_cycle); // set the duty cycle
}
delay_ms(100);
// 1 second delay between readings
}
}
however my program cant work because it cant match to the PWM program.







