# Slow speed Software PWM

Slow speed Software PWM (with PicBasic Pro) by Darrel Taylor

I wrote this program in response to this request from "The List". Hi, is there some way to output a 30 Hz - 250 Hz HPWM with 16F876 at 20MHZ ?

I have no idea what it could be used for, but if your looking for Slow Speed PWM, this might help. If your looking for pulses in the range of 1-2 ms at a fixed frequency of 50 Hz, for controlling Servo Motors try the PWPS (Pulse Width Position Servo) program instead.

The problem, is that the Hardware PWM is limited by a minimum frequency. In the case above, 1221hz is the lowest frequency available for HPWM. This limitation is due to the use of Timer2 with the Capture/Compare module. Timer 2 is an 8 bit timer with a maximum prescaler of 1:16 Let's take a look at the math.

@ 20 Mhz, the prescaler is fed with FOSC/4 or 5 Mhz, so each clock pulse is 0.0000002 sec. (1/5,000,000) or .2 us With a maximum prescaler of 1:16 Timer2 will be clocked every 3.2 us (.2 us * 16) Since Timer2 is an 8bit timer, the maximum count is 255 plus 1 to overflow the timer. Therefore, the maximum period is (3.2 us * 256) or 819.2 us, which gives us 1220.7 Hz (1/0.0008192) The integer math of PICs then limits it to 1221 Hz

@ 4 Mhz you can get as low as 245 Hz, but at 40 Mhz it goes up to 2442 Hz.

At first I thought that we could switch over to Timer1 which is a 16 bit timer to gain some Low Freq Response, but then figured out that the CCP modules are only 8 bit as well, so there's no difference in the final result. Although the CCP is capable of 10 bit PWM, it's really only 8 bits, with the upper bits controlling the prescaler, and since we've already taken the maximum prescaler into account it doesn't help at all.

There is a method where you can use the 16-bit "Compare" mode of the CCP module to do the job. The CCP would constantly monitor Timer1 for a match and then generate an interrupt. You would then change the compare value to the other half of the cycle, and wait for the next interrupt (rinse and repeat). This method would need to use both the CCP module and a Timer (1 or 3). But since it can be accomplished with just the Timer by itself, I figured it would be better to save the CCP module for other uses, like a separate HPWM at a different frequency.

This program will produce PWM signals in the following ranges, depending on OSC frequencies of:

 OSC Mhz Min Freq Hz Max Freq Hz 4 16 350 8 16 660 10 17 700 20 17 1400 40 20 2700

Other crystal frequencies will produce ranges proportional to the listed values. All valid PBP crystal frequencies are supported. This pretty much covers all the frequencies that the HPWM misses. Unless you need less than 16hz, which is also possible, but I didn't think there would be a need for that low of freq.

DutyCycle ranges from 0-100% at all frequencies. Where 0 is always off, and 100 is always on.

Here is a simple test program.

```'****************************************************************
'*  Name    : TestSSPWM.PBP                                     *
'*  Author  : Darrel Taylor                                     *
'*  Date    : 5/12/2003                                         *
'*  Version : 1.0                                               *
'****************************************************************
define OSC 4

clear
' ---- SPWM  Slow Software Pulse Width Modulation --------------
SPWMpin       var PORTB.0         ' Output Pin for SSPWM
Include "SSPWM.INC"               ' Output Pin must be Defined before Include file
' Include file must be after the Clear statement

Freq = 30                         ' Set Frequency of SSPWM (word)
DutyCycle = 10                    ' Set Duty Cycle of SSPWM (byte) 0-100
gosub StartSPWM                   ' Start SSPWM @ Freq/DutyCycle

Loop:
pause 100
goto Loop

end
'****************************************************************
```

You can change the PWM rate or frequency at any time with the following commands.

```Freq = 30                         ' Set Frequency of SSPWM (word)
DutyCycle = 50                    ' Set Duty Cycle of SSPWM (byte) 0-100
gosub SetSPWM
```