Multiple Software PWM

This program allows you to have MANY Pulse Width Modulation's being generated as an interrupt driven Background process with PicBasic Pro. It's a complete Re-Write of the original Multi-SPWM with new features added. So be sure to read this article before trying to use it.


  • Multiple Slow Speed PWM outputs simultaneously on 1 chip, limited only by the processor speed, and SPWM frequency/resolution configuration.
  • Works on just about any chip. 18F or 14-bit core's.
  • Each SPWM output can be assigned to ANY General I/O pin on any Port
  • PWM has a maximum resolution of 8-bit (0-255) 0=Always Low, 255=Always High, but lower resolutions are also available.
  • It's an Include file, for easy implementation in your program.
  • Some Error checking is built in, and supplies Messages detailing the problems. Although it won't find everything you can mess up.

As before:
The downside to this program is that it uses a lot of processor time. This leaves very little for the rest of the program. Depending on how it is configured, it may use 75% or more of the available processing time. The reason it uses so much is due to the large number of interrupts required.

For instance, with a Frequency of 100hz, and a resolution of 256, it takes 25,600 interrupts per second. With each output using around 11 instructions per interrupt, it adds up to about 281,600 instructions per second, per output. Yowsa !

Needless to say, you probably won't want to run this on a 4Mhz processor, although it is possible.

3 new features of this version are:

  • SPWM outputs are defined with a Macro instead of with individual DEFINE's. This allows more outputs to be used if desired, and makes things much easier to work with.
  • PWM resolution is no longer limited to 8-bit (256). If you only need 0-100%, you can simply specify the resolution with a DEFINE. This can GREATLY improve the performance by using MANY fewer interrupts.
  • It is written to work with the Instant Interrupt system, and will work with either the 18F or 14-bit versions.

Here is a sample program that shows the basics of how to use SPWM_INT.

; Initialize your hardware first


INCLUDE "DT_INTS-14.bas"            ; Base Interrupt System
INCLUDE "SPWM_INT.bas"              ; Software PWM module

DEFINE SPWM_FREQ  40                ; SPWM Frequency
DEFINE SPWM_RES   256               ; SPWM Resolution

DutyVars   VAR BYTE[3]              ; DutyCycle Variables
  DutyVar1 VAR DutyVars[0]          ; group them in an array for easy access
  DutyVar2 VAR DutyVars[1]          ; with FOR loops etc.
  DutyVar3 VAR DutyVars[2]

SPWM_LIST  macro                    ; Define Pin's to use for SPWM
     SPWM_PIN  PORTB, 0, _DutyVar1  ; and the associated DutyCycle variables
     SPWM_PIN  PORTB, 1, _DutyVar2  ; Notice the underscore before variables
     SPWM_PIN  PORTB, 2, _DutyVar3
  SPWM_INIT  SPWM_LIST              ; Initialize the Pins

INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
        INT_Handler   TMR1_INT,  SPWMhandler,  ASM,  yes
    INT_CREATE                      ; Creates the interrupt processor

@ INT_ENABLE  TMR1_INT              ; enable Timer 1 interrupts


RandVar   VAR WORD : RandVar = 12345
LoopCount VAR WORD

Main:                               ; Simple Demo to fade/flash some LED's
    DutyVar1 = 5                        ; Start with 3 LED's at different
    DutyVar2 = 50                       ; brightness
    DutyVar3 = 150
    PAUSE 3000

    FOR LoopCount = 1 TO 4              ; Reapeat 4 times
        FOR DutyVar1 = 0 TO 150         ; Fade LED1 UP
            PAUSE 10
            RANDOM  RandVar             
            DutyVar3 = RandVar & $3F    ; Give LED3 a random dutycycle
        NEXT DutyVar1

        FOR DutyVar1 = 150 TO 0 STEP -1 ; Fade LED1 Down
            PAUSE 10
            RANDOM  RandVar
            DutyVar2 = RandVar & $3F    ; Give LED2 a random dutycycle
        NEXT DutyVar1
    NEXT LoopCount     

This program will create 3 PWM channels on PORTB 0, 1, and 2. The PWM frequency is 40Hz, with a resolution of 256 (8-bit). All PWM channels automatically configure the pin as an output, and set the output to the LOW state. It will IDLE there until the Dutycycle is changed.

The Dutycycle can be changed at any time by simply changing the variable. The PWM output will be automatically updated (if necessary) on the next interrupt. There are no subroutines to call. It all "Just Happens".

DutyVar1 = 5 DutyVar2 = 50 DutyVar3 = 150

That's all there is to it.

Download the files here: (Right click and Save As) be sure to remove the .txt extension

SPWM_INT.bas ; Multiple software PWM's Include file.
Test_SPWM_INT.pbp ; Sample program for SPWM_INT

Page last modified on March 06, 2018, at 03:47 AM