In particular, the code below is a response to the recent mikroC "Brain Teaser" proposition. When will those C fellows ever come over to the dark side?
Below is an example of a technique whereby you can create just about any low frequency PWM with very high resolution that you can imagine. Nobody should again have to ask IF and HOW the hardware PWM module can do something ridiculously slow...
Cheers!
Code: Select all
program LowFreqPWM
'*******************************************************************
'***** *****
'***** PIC High Resolution Low Frequency Hardware PWM *****
'***** By Warren Schroeder; mikroBasic 6.0; Dec 13, 2007 *****
'***** Thanks! to Mike-K8LH for the inspiration. *****
'***** Exmample of 200Hz PWM @ 2500 Steps of Resolution *****
'***** *****
'*******************************************************************
'*******************************************************************
'***** *****
'***** The example below assumes an 8MHz Oscillator and *****
'***** will work on CCP1 and CCP2 of most any PIC. PIC *****
'***** PWM cannot function at very low frequencies without *****
'***** also using a lower frequency main oscillator value. *****
'***** For instance, 200Hz hardware PWM is not possible *****
'***** unless a main oscillator of less than 4MHz is used. *****
'***** This may not be practical or desirable. *****
'***** *****
'***** The idea is to use each PWM period coupled to the *****
'***** Timer2 Interrupt, which is fairly easy since Timer2 *****
'***** overflows at the start of each PWM duty cycle. *****
'***** By ganging the periods together the effect can be *****
'***** a very long period. Since period is the inverse *****
'***** of frequecy, ganged, or long, periods make lower *****
'***** frequencies.... our objective with this code. *****
'***** *****
'***** Setting the Timer2 Prescaler to 4, and the PR2 *****
'***** to 249, a PWM frequency of 2KHz with a 1000 step *****
'***** duty cycle resolution is achieved. By ignoring the *****
'***** lowest 2 bits of the 10-bit duty cycle registers, *****
'***** namely, CCP1CON <5:4>, 8-bits of duty cycle *****
'***** resolution can still be realized. In this case, *****
'***** 250 steps per period. That is done by keeping *****
'***** CCP1CON <5:4> clear and writing only to CCPR1L. *****
'***** *****
'***** By ganging 10- 2000Hz PWM periods, the result is *****
'***** a frequency of 200Hz and a possible 2500 steps of *****
'***** duty-cycle resolution. By using the full 10-bit *****
'***** capability of the PWM module it is possible to *****
'***** reach 10000 steps of resolution @ 200Hz. *****
'***** *****
'***** An interval counter is updated at each interrupt *****
'***** in order to track the duty cycle and new period. *****
'***** *****
'***** Enjoy the possibilities! *****
'***** *****
'***** xor *****
'***** *****
'*******************************************************************
symbol T2IF = PIR1.TMR2IF
symbol T2IE = PIE1.TMR2IE
symbol T2ON = T2CON.TMR2ON
dim interval_counter as char
dim dutycycle as integer
dim workcycle as integer
'*******************************************************************'
'***** ISR Manages Ganging PWM Periods And Extended Duty Cycle *****'
'*******************************************************************'
sub procedure interrupt
If interval_counter = 9 Then ' last interval..refresh dutycycle
workcycle = dutycycle
End If
If workcycle > 250 Then ' check intervals for on-off periods
CCPR1L = 250
Else
If workcycle > 0 Then
CCPR1L = workcycle
Else
CCPR1L = 0
End If
End If
workcycle = workcycle - 250
inc(interval_counter)
If interval_counter = 10 Then ' reset interval counter
interval_counter = 0
End If
T2IF = 0 ' clear interrupt flag
end sub
'*******************************************************************'
'***** Initialize CCP1 PWM Module and Timer2 Interrupts *****'
'*******************************************************************'
sub procedure pwmint_setup
TRISC.2 = 0 ' CCP1/RC2 is output
PR2 = 249 ' period register.. PWM-Res=1000
T2CON = 1 ' prescaler=4
CCPR1L = 0 ' 8-bit duty cycle register.. 0 is OFF
INTCON = 192 ' enable GIE and PEIE
T2IE = 1 ' enable Timer2 Interrupt
T2IF = 0 ' clear Timer2 interrupt Flag
T2ON = 1 ' turn Timer2 On
CCP1CON = 12 ' PWM mode
interval_counter = 0 ' start fresh
end sub
'*******************************************************************'
'***** All Your Code Goes In Here *****'
'*******************************************************************'
main:
pwmint_setup
Do
dutycycle = 1200 ' out of possible 2500
' your code
Loop Until 0=1
end.