PWM:
The PWM mode generates a Pulse-Width Modulated signal on the CCPx pin. The duty cycle, period and resolution are determined by the following registers:
• PR2
• T2CON
• CCPRxL
• CCPxCON
In Pulse-Width Modulation (PWM) mode, the CCP module produces up to a 10-bit resolution PWM output on the CCPx pin. Since the CCPx pin is multiplexed with the PORT data latch, the TRIS for that pin must be cleared to enable the CCPx pin output driver.
• PR2
• T2CON
• CCPRxL
• CCPxCON
In Pulse-Width Modulation (PWM) mode, the CCP module produces up to a 10-bit resolution PWM output on the CCPx pin. Since the CCPx pin is multiplexed with the PORT data latch, the TRIS for that pin must be cleared to enable the CCPx pin output driver.
PWM Period:
The PWM period is specified by the PR2 register of Timer2. The PWM period can be calculated using the formula
PWM Period = [(PR2) + 1] • 4 • TOSC • (TMR2 Prescale Value)
Note: TOSC = 1/FOSC
Note: TOSC = 1/FOSC
When TMR2 is equal to PR2, the following three events occur on the next increment cycle:
• TMR2 is cleared
• The CCPx pin is set. (Exception: If the PWM duty cycle = 0%, the pin will not be set.)
• The PWM duty cycle is latched from CCPRxL into CCPRxH.
• TMR2 is cleared
• The CCPx pin is set. (Exception: If the PWM duty cycle = 0%, the pin will not be set.)
• The PWM duty cycle is latched from CCPRxL into CCPRxH.
PWM Duty Cycle:
The PWM duty cycle is specified by writing a 10-bit value to multiple registers: CCPRxL register and DCxB<1:0> bits of the CCPxCON register. The CCPRxL contains the eight MSbs and the DCxB<1:0> bits of the CCPxCON register contain the two LSbs. CCPRxL and DCxB<1:0> bits of the CCPxCON register can be written to at any time. The duty cycle
value is not latched into CCPRxH until after the period completes (i.e., a match between PR2 and TMR2 registers occurs). While using the PWM, the CCPRxH register is read-only.
The PWM duty cycle is specified by writing a 10-bit value to multiple registers: CCPRxL register and DCxB<1:0> bits of the CCPxCON register. The CCPRxL contains the eight MSbs and the DCxB<1:0> bits of the CCPxCON register contain the two LSbs. CCPRxL and DCxB<1:0> bits of the CCPxCON register can be written to at any time. The duty cycle
value is not latched into CCPRxH until after the period completes (i.e., a match between PR2 and TMR2 registers occurs). While using the PWM, the CCPRxH register is read-only.
Pulse Width = (CCPRxL:CCPxCON<5:4>) • TOSC • (TMR2 Prescale Value)
Duty Cycle Ratio (CCPRxL:CCPxCON<5:4>) / 4(PR2 + 1)
PWM Resolution:
The resolution determines the number of available duty cycles for a given period. For example, a 10-bit resolution will result in 1024 discrete duty cycles, whereas an 8-bit
resolution will result in 256 discrete duty cycles. The maximum PWM resolution is 10 bits when PR2 is 255.
resolution will result in 256 discrete duty cycles. The maximum PWM resolution is 10 bits when PR2 is 255.
Resolution = log[4(PR2 + 1)] / log(2) bits
Setup for PWM Operation:
The following steps should be taken when configuring the CCP module for PWM operation:
1. Disable the PWM pin (CCPx) output drivers as an input by setting the associated TRIS bit.
2. Set the PWM period by loading the PR2 register.
3. Configure the CCP module for the PWM mode by loading the CCPxCON register with the appropriate values.
4. Set the PWM duty cycle by loading the CCPRxL register and DCxB<1:0> bits of the CCPxCON register.
5. Configure and start Timer2:
• Clear the TMR2IF interrupt flag bit of the PIR1 register.
• Set the Timer2 prescale value by loading the T2CKPS bits of the T2CON register.
• Enable Timer2 by setting the TMR2ON bit of the T2CON register.
6. Enable PWM output after a new PWM cycle has started:
• Wait until Timer2 overflows (TMR2IF bit of the PIR1 register is set).
• Enable the CCPx pin output driver by clearing the associated TRIS bit.
1. Disable the PWM pin (CCPx) output drivers as an input by setting the associated TRIS bit.
2. Set the PWM period by loading the PR2 register.
3. Configure the CCP module for the PWM mode by loading the CCPxCON register with the appropriate values.
4. Set the PWM duty cycle by loading the CCPRxL register and DCxB<1:0> bits of the CCPxCON register.
5. Configure and start Timer2:
• Clear the TMR2IF interrupt flag bit of the PIR1 register.
• Set the Timer2 prescale value by loading the T2CKPS bits of the T2CON register.
• Enable Timer2 by setting the TMR2ON bit of the T2CON register.
6. Enable PWM output after a new PWM cycle has started:
• Wait until Timer2 overflows (TMR2IF bit of the PIR1 register is set).
• Enable the CCPx pin output driver by clearing the associated TRIS bit.
Note: This is only for 887. For Enhanced PWM Mode please refer to pic16F887 datasheet.
Lets do all this things in easy way by using in-build mikroc library for pwm.
Code:
Lets write the code to generate PWM on pins RC1 & RC2. And switches RA0-RA3 to increase/decrease PWM duty cycle.
unsigned short current_duty, current_duty1;
void InitMain() {
void InitMain() {
//using 887 and 8MHz xtal//////////////
ANSEL = 0; // Configure AN pins as digital
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
PORTA = 255;
TRISA = 255; // configure PORTA pins as input
PORTC = 0; // set PORTC to 0
TRISC = 0; // designate PORTC pins as output
PWM1_Init(1000); // Initialize PWM1 module at 1KHz
PWM2_Init(2000); // Initialize PWM2 module at 2KHz
}
void main() {
InitMain();
current_duty = 16; // initial value for current_duty
current_duty1 = 16; // initial value for current_duty1
PWM1_Start(); // start PWM1
PWM2_Start(); // start PWM2
PWM1_Set_Duty(current_duty); // Set current duty for PWM1
PWM2_Set_Duty(current_duty1); // Set current duty for PWM2
while (1) { // endless loop
if (RA0_bit) { // button on RA0 pressed
Delay_ms(40);
current_duty++; // increment current_duty
PWM1_Set_Duty(current_duty);
}
if (RA1_bit) { // button on RA1 pressed
Delay_ms(40);
current_duty--; // decrement current_duty
PWM1_Set_Duty(current_duty);
}
if (RA2_bit) { // button on RA2 pressed
Delay_ms(40);
current_duty1++; // increment current_duty1
PWM2_Set_Duty(current_duty1);
}
if (RA3_bit) { // button on RA3 pressed
Delay_ms(40);
current_duty1--; // decrement current_duty1
PWM2_Set_Duty(current_duty1);
}
Delay_ms(5); // slow down change pace a little
}
}
ANSEL = 0; // Configure AN pins as digital
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
PORTA = 255;
TRISA = 255; // configure PORTA pins as input
PORTC = 0; // set PORTC to 0
TRISC = 0; // designate PORTC pins as output
PWM1_Init(1000); // Initialize PWM1 module at 1KHz
PWM2_Init(2000); // Initialize PWM2 module at 2KHz
}
void main() {
InitMain();
current_duty = 16; // initial value for current_duty
current_duty1 = 16; // initial value for current_duty1
PWM1_Start(); // start PWM1
PWM2_Start(); // start PWM2
PWM1_Set_Duty(current_duty); // Set current duty for PWM1
PWM2_Set_Duty(current_duty1); // Set current duty for PWM2
while (1) { // endless loop
if (RA0_bit) { // button on RA0 pressed
Delay_ms(40);
current_duty++; // increment current_duty
PWM1_Set_Duty(current_duty);
}
if (RA1_bit) { // button on RA1 pressed
Delay_ms(40);
current_duty--; // decrement current_duty
PWM1_Set_Duty(current_duty);
}
if (RA2_bit) { // button on RA2 pressed
Delay_ms(40);
current_duty1++; // increment current_duty1
PWM2_Set_Duty(current_duty1);
}
if (RA3_bit) { // button on RA3 pressed
Delay_ms(40);
current_duty1--; // decrement current_duty1
PWM2_Set_Duty(current_duty1);
}
Delay_ms(5); // slow down change pace a little
}
}
PWM1_Init();Initializes the PWM module with duty ratio 0. Parameter
PWM1_Set_Duty(); Sets PWM duty ratio. Parameter freq
is a desired PWM frequency in Hz.duty
takes values from 0 to 255, where 0 is 0%, 127 is 50%, and 255 is 100% duty ratio. Other specific values for duty ratio can be calculated as (Percent*255)/100
.PWM1_Start(); Starts PWM.
Schematic:
hi, thanx for all the examples.
ReplyDeleteIm working on MikroC Pro For PIC v4.6 and I copy/paste your code and build it.
After that I exactly made the same schematic in ISIS and loaded the *.hex file in the PIC16f887.
Finally, I try to simulate all, but it doesn't do anything... :S
Have no idea what could be wrong, btw, this is my first attempt with PWM
Plz help.
Code is ok. I think problem is in proteus isis.
ReplyDeleteFor MikroC "RA2_bit" must be replaced with PORTA.F2 and "PWM1_Set_Duty" to "PWM1_Change_Duty" and with all of that isn't working in Proteus
ReplyDeleteYes; but the above code is written in MikroC Pro for PIC. During the session of this tutorial i tested the code in proteus, at that time it was running fine. I don't know why it is not working now. I think i have to write the new code in MPLAB.
ReplyDeleteThe code works fine now for me.. the problem was PROTEUS, must have a last version.
ReplyDeleteHI SIR I AM NEW WITH MICROCONTROLLER
ReplyDeleteTELL ME HOW TO CONVERT C PROGRAM INTO HEX CODE
if you wanna build the code use ctrl+F9. or you should read this first
ReplyDeletehttp://www.mikroe.com/eng/downloads/get/34/1st_project_c_pro_pic_v101.pdf
The codes looks fine to me. So I guess it's the problem with proteus.
ReplyDeleteHello i was just wondering if you have written the code for MPlab yet? I am currently working on a similar project however i must have a set frequency of 10KHz, also must be hooked up to a potentiometer. When the pot is at 0V i will get a duty cycle of 10%, and when the pot is set to 5V i will get a duty cycle of 95%. Everything in between having a linear relationship. I would greatly appreciate any help / tips! Thank you so much.
ReplyDeletehere is the sample code
ReplyDeletehttp://www.4shared.com/file/wKm4VAbD/pwm.html
change according to ur requirements.
Hey thank you for the code, it was a little help but the problem is i am using the PIC16F887 and that was written using another code & everything is using the pic18.h header file in the code you supplied
ReplyDeleteyup i know. you have to change it; i.e header file, some SFRs to make it compatible for ur controller.
ReplyDeleteIn MikroC Pro must enable the PWM library, in Proteus ISIS edit PIC Properties, change to 8Mhz the Processor Clock Frequency
ReplyDeleteis the PWM Library in mikroPro enabled by just calling the function PWM_init() first?
DeleteHi Dear, I need urgent help please . if i want to control the speed by one buttons how i can keep the last state of the button ?
ReplyDeleteSave the value of the button; i.e; say you have 5 steps for full speed means for each press of button the speed will increment about 20%. save value the of number of times button is pressed, compare it with stored value n update the speed.
DeleteFor decreasing; you can add 5 more stages means when the button is pressed for six times speed decreases 20% of the previous speed. But its not the good method.
The best way is to use a potentiometer connected to adc port, then code the speed level according to the adc values. in this you can easily increase or decrease speed with precision.
Salam Bhai i Want to ask that we are generating PWM PULSES Through Micro Controller but can we attach externel circuitary with it what will b effect and it is necessary for extarnel circutary ..... Kindly reply fasst as soon as posssible
ReplyDeleteWhat do you mean by "external circuitry"?
ReplyDeleteof course for driving motors we need inverter or h-bridge circuit; by controlling the pwms we can change the speed n direction(3-phase or dc motors) as well.
you are connected 17th and 16 th pin for PWM1 and PWM2 outputs.is it assigned some where in code or is thatthe pin for PWM timers
ReplyDeleteccpx pins are used to generate pwms, read datasheet for more info.
ReplyDeleteAll PWM modules use Timer2 for its operation, so you can not set different frequencies for different PWM modules....
ReplyDeleteDoesn't work:
PWM1_Init(1000); // Initialize PWM1 module at 1KHz
PWM2_Init(2000); // Initialize PWM2 module at 2KHz
Works:
PWM1_Init(1000); // Initialize PWM1 module at 1KHz
PWM2_Init(1000); // Initialize PWM2 module at 1KHz
Is there anyone can help me soon as possible by explaining how the duty cycle of PWM pulses affects the speed of the motor when used as gate signal to inverters or h-bridge circuits?
ReplyDeletein 1 wave cycle you ca convert it avrage dc voltage, longer high pulces and shorter low pulce in 1 wave cycle gives higher dc voltage hence moter will run faster as avrage dc voltage is higher and if high pulse is shorter then low pulse in 1 cycle then revimoter will run slower as avrage dc voltage will be lower
ReplyDeletei hope this answers good
Thank you, can you also help me the code to read an analog voltage and store it on a defined data type?
Delete