Low Frequency High Resolution Hardware PWM

General discussion on mikroBasic.
Post Reply
Author
Message
xor
Posts: 5465
Joined: 18 May 2005 00:59
Location: NYC
Contact:

Low Frequency High Resolution Hardware PWM

#1 Post by xor » 14 Dec 2007 06:44

The question has arisen in a couple of threads, one in mikroC and the other in mikroPascal, recently about getting low frequencies out of the PIC PWM module... that is, lower than is possible with the oscillators being implemented.

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... :D
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.
[color=darkred][b]xor[/b][/color]
[url=http://circuit-ed.com]CircuitED -[/url]

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#2 Post by jpc » 14 Dec 2007 08:06

very nice xor! you are not using any additional resources besides a little RAM

bruno
Posts: 767
Joined: 10 Sep 2005 02:10
Location: Lyon, France
Contact:

#3 Post by bruno » 14 Dec 2007 09:16

Xor you are cheating :arrow: the solution in original post was to supposed to be hardware only :mrgreen:
with a software PWM you can reach up to 65535 steps with almost the same code size and less RAM
Bruno
Bored with 7-segment ? Try the [url=http://www.micro-examples.com/public/microex-navig/doc/079-touchclock.html]TouchClock[/url]

shoaib392
Posts: 4
Joined: 04 Jun 2015 18:07

Re: Low Frequency High Resolution Hardware PWM

#4 Post by shoaib392 » 04 Jun 2015 18:24

PLZ translate the same code in C to run in MikroC

Post Reply

Return to “mikroBasic General”