PWM - Pulse Width Modulation

Intro

Servos require PWM outputs from the microcontroller to tell them what position to turn to. Many other control devices also use PWM as their inputs from the microcontroller. These devices expect a certain base period between pulses and use the duration of the pulse to control their behavior.

Many devices including most servos are pretty lenient about the base period, and will function pretty well with considerable fluctuation in the period. For those devices, simple software-based PWM works just fine. This is usually accomplished with a macro that sets the pin high, waits N cycles, then sets the pin low. This is then repeated in a loop of approximately the right period for the device. If this works for your application then it by far the easiest way to do it.

There are several things that can make this approach fail:

  • Main loop has large variations in time
  • Main loop takes longer than desired base period
  • Device is very sensitive to changes in base period. (One example of this is the Sabertooth motor controller running in R/C mode.)

For these situations, you will need to use the built-in interrupt driven PWM output of the atMega chip. On the Axon, you have access to 7 PWM outputs although you have to use up an additional timer to get to the 7th one, so the code below only deals with 6 outputs.

The idea is to set up the appropriate timers to a 20mS base period (50 Hz). This is the standard used by most hobby servos and the Sabertooth R/C. Then enable PWM on the pins you need. Then you can change the servo setting by just changing one variable. That pulse width will continue to be sent every 20mS until the variable is changed.

On the Axon, you have easy access to PWM on the following pins:

  • TIMER3: E3,E4,E5
  • TIMER4: H3,H4,H5

Example Code

Insert the code at the bottom of this page into your project, then you can do PWM on any or all of those 6 pins. For example if you wanted to use PWM on H3 and H4, you could do this:

// Initialize PWM functions on H3-5 with TIMER4
pwmInitH345();
// Start PWM on H3 and H4
pwmOnH3();
pwmOnH4();
// Change the pulse width sent to each pin
pwmSetH3(1500); // Send 1.5 mS pulses to H3
pwmSetH4(1000); // Send 1.0 mS pulses to H4
//
// your code here...
//
// Change the pulse width sent to each pin
pwmSetH3(1400); // Send 1.4 mS pulses to H3
pwmSetH4(1800); // Send 1.8 mS pulses to H4

Download

Download Axon Code