Implementing PWM in software

Pulse Width Modulation (PWM) is a way of generating a square wave with varying duty cycle (aka pulse width). This is useful for many applications, including:

  • Dimming an LED

  • Setting a Servo Motor Position

  • Poor man’s DAC (with suitable low pass filter)

Most microcontrollers have Timer modules included. These are the most useful for generating PWM signals. Usually you can set the PWM frequency and pulse width. The nice thing about this hardware implementation is that once it’s configured then it doesn’t require any software interaction.

However, sometimes you need more PWM outputs than you have available timer outputs. In this case you need to implement PWM manually. The example below “fades up” an LED. Notice that this is a blocking function which means that no other code can be running at the same time. If you have a fast enough processor then a better way would be to use one timer interrupt to use for the delay. Implementation of that will be microcontroller specific. But here’s the manual version:

unsigned int onTime = 0; //periodsPerStep;
unsigned int offTime = 0; //PWM_PERIOD - onTime;

#define PWM_PERIOD 0xFF //period for PWM wavelength - 0xFF = 8kHz or so
#define CROSSFADE_STEPS 0xFF //how many intervals of intensity. 16 looks choppy
#define PERIODS_PER_STEP 0x3F//0x7F //how much time to wait at each intensity interval: 0xFF = 6 secs

unsigned int perStepInterval = PWM_PERIOD / CROSSFADE_STEPS;

for (int step = 0; step < CROSSFADE_STEPS; step++)
{
onTime = perStepInterval * step;
offTime = PWM_PERIOD - onTime;

//PWM periods:
for (int periodCounter = 0; periodCounter < PERIODS_PER_STEP; periodCounter++)
{
P1OUT = 0x01; 
for (unsigned int counter = 0; counter < onTime; counter++) ; //on interval

P1OUT = 0x00;
for (unsigned int counter = 0; counter < offTime; counter++) ; //off interval
}
}
Derek Smith