![]() |
||||||||||||||||||
|
[?]
Subscribe To This Site
|
Custom Search
Readers
comments
|
|||||||||||||||||
PIC PWM InterruptHow to generate a PIC PWM using an interrupt. Some PIC Microcontrollers have built in PWM internal peripherals that are easy to set up and use and once initialized will continue running on their own. All you do is send data to the duty cycle register to change the pulse width. Sometimes you need a Pulse Width Modulation signal because either the device does not have an internal PWM peripheral or you need an extra one. This page shows you how to add a software controlled interrupt driven PWM signal. There are two methods presented - the first uses one timer and does not have as good performance as the second. The second uses two timers but has extremely good performance. Which one you use depends on
Single Timer method : PWM PIC Interrupt driven timerThe key to creating a PIC PWM is to use an interrupt from one of the timers which is used as the resolution timer for the PWM period. In the example below Timer 0 is used as the resolution timer and has a frequency of 33kHz or a period of 30us.Note:This is not the PWM frequency. It is just the period of one step of the pwm. Although 20 steps does not sound a lot if you use it as a light dimmer its more than enough. It depends on the application you are using. The final output has a frequency of: PIC PWM Interrupt: Frequency = (Timer Frequency/No. steps) so here Frequency = 1.65kHz Single Timer method : PIC PWM Interrupt - Timer initializationThis example is from a 16F88 running an internal oscillator at 8MHz.void init_timer (void) { // Timer 0 initialize OPTION_REG = 0x00 | (1<<7);// | (1<<3); // Timer 0 interrupt enable // Osc off, Internal clk, On, zero T0IF, // Enable global interrupts INTCON = (1<<T0IE) | (1<<GIE); } Single Timer method : PIC PWM InterruptHere is the code for the PIC PWM interrupt:void interrupt(void) { /////////////////////////////////////////////// // Timer 0 if (INTCON & (1<<T0IF) ) { // T0 overflowed ? INTCON &= ~(1<<T0IF); // clear timer0 overflow bit. TMR0 = 228; // 30us time++; do_pwm(); } } Single Timer method : PWM PIC Interrupt - pwm codeThis code is called from the interrupt to do the PWM action.void do_pwm(void) { if (time>20) time=0; if (time<pwm_val) setBit(PORTB,SOFT_PWM_PORTB_PIN); else resBit(PORTB,SOFT_PWM_PORTB_PIN); } There is a trade off between how much the microcontroller is asked to do outside the interrupt and the size of the interrupt (including called subroutines). As you must allow enough time between interrupts for the processor to do its 'main' job. The second method below shows use of two timers which reduces the processing burden. Double Timer method : PIC PWM Interrupt driven timerIf you have not got an internal PWM module then this method can give an accurate (high resolution) output without using up too much processor time.It works by using the first timer as the PWM frequency generator. This then loads up the second timer with a time that is the period of the required pulse width. It does this by calculating the number of timer clock cycles that result in the required period (which you set from within the program elsewhere). A timer usually generates an interrupt when it reaches zero (having passed through the highest value) so all you do is work out the period in timer clock cycles (n) and subtract this value from the largest value that the timer can have (max-n). So when the timer starts counting up from this value it rolls over to zero having counted n clock cycles. When the first timer interrupts you set the PWM output high and when the second timer interrupts you set the PWM output low. This creates a high resolution PWM PIC Interrupt driven signal without consuming processing power. Double Timer method : PIC PWM InterruptHere's the code for the PIC PWM Interrupt generator that implements the high resolution method using Timer 0 as the frequency generator (here 1/18ms) and Timer 1 as the period timer (resolution Fosc/4).Note: For different resolutions change the Timer 1 prescalers etc. This example is from an 12F675 running at 4MHz (internal). void interrupt(void) { unsigned int val; /////////////////////////////////////////////// // Timer 0 if (INTCON & (1<<T0IF) ) { // T0 overflowed ? INTCON &= ~(1<<T0IF); // clear timer0 overflow bit. // Fosc/4 x (Prescale) x (count to overflow) = repeat rate. // 1us x 128 x 140 = 18ms repeat rate. TMR0 = 256-143; // need 141 but looses TMR0 looses 2 so use 142 time++; // Count 18ms periods for general use. // Now set up timer1 as a 1 shot timer // Set overflow for Timer 1 val = 65535-servoVal; // Use these vars for reporting debug st_TMR1L = val & 0x00ff; st_TMR1H = (val & 0xff00)>>8; TMR1H = st_TMR1H; // set high 1st so does not overflow immediately TMR1L = st_TMR1L; st_val = val; // Enable Timer 1.- every Timer 0 interrupt or 18ms = 1 shot. PIE1 |= (1<<TMR1IE); GPIO |= (1<<SERVO_BIT); // Set Servo on } /////////////////////////////////////////////// // Timer 1 if (PIR1 & (1<<TMR1IF) ) { PIR1 &= ~(1<<TMR1IF); // Clear flag. GPIO &= ~(1<<SERVO_BIT); // Reset servo } INTCON |= (1<<T0IE); // Enable Timer 0. // Note GIE set by RETFIE instruction (see assembler output). } Note: This PIC PWM Interrupt code is from the 12F675 Servo Controller tutorial. For a rigorous and complete guide to interrupts buy my ebook : Jump from pic pwm interrupt to Best Microcontroller Projects Home Page.
|
||||||||||||||||||
|
||||||||||||||||||