Listing 3: Setting Up PWM.
Set up the motors and PWM and such.
DDRD |= (unsigned char)(1 <<PD5);
DDRD |= (unsigned char)(1 <<PD6);
TCCR0A = 0xF3;
TCCR0B = 0x03;
settings, if used.
OCR0A: Output Compare Register 2A. Match value
for PWM on OC2A pin.
OCR0B: Output Compare Register 2B. Match value
for PWM on OC2B pin.
DDRD: Data Direction Register PORTD. Set the
direction of data transfer for the pins on port B. In this
case, OC0A and OC0B are PD6 and PD5, respectively.
OCR0A = 0;
OCR0B = 0;
Setting Up the PWM // (#4)
needed to do was keep a 1 ms background tic, you could
set up the timer to interrupt at a 1 ms rate by choosing a
pre-scale value and match count that would cause the
interrupt every 1 ms. (Hint: 16 MHz/128 125 = 1 ms).
That wasn’t so hard, was it? The most difficult part of
this process is probably finding out how avr-gcc wants you
do set up interrupts (which I also showed you). But how did
I find the name of the interrupt so it would call the correct
ISR? Okay, you got me. That was really hard to find, so I
went to good ol’ Google, and it found www.nongnu.org/
which set me right up. Somewhere in the avr-gcc
documentation it says this. I was sure, but I didn’t find it
without Google! At least now you don’t have to search for it.
Using a Timer for PWM
Our first step has nothing to do with timers at all!
We’re going to turn off the comparator module on the
chip. This module deals with comparing analog voltages
and causing things to happen by comparing them. This
module defaults to on and will cause you no end of
headaches with your I/O if you don’t disable it!
Above we disabled the comparator module. This
assures us that our I/O pins are really digital. Now, we’ll
configure the registers above to PWM some motors. Since
we’re going to send a PWM signal out, we’ll need to deal
with the data direction registers, as well as the timer
registers. Listing 3 shows how to initialize all of the needed
Set the DDRD register for outputs on PD5 (OC0B) and
PD6 (OC0A). Set the fast PWM mode, clear the output on
match, count up from the bottom (0). Fast PWM will only
count up from 0, match (clear output), count the rest of
the period, then restart at 0 again with the output set to 1.
Set the prescale to 64 which on a 16 MHz part means the
clock will be 250 kHz divided by 256 (an eight-bit count)
which translates to a PWM rate of 977 Hz. Set both PWMs
to 0. We should always start out stopped, don’t you think?
At this point, all you need to set a motor speed is to
put a non-zero value into OCR0A or OCR0B, and the motor
will go that speed. This is simple motor speed control! If I
was going to use a PID algorithm, I would use the PWMs
on TMR1 which is 16 bits of resolution; this would give me
a smoother PID loop with more control. For simple motor
control, eight bits is plenty.
Wrap-Up for the ATmega168/328
ACSR = 0x80;
// turn off the comparator
This time, I’ll pick TMR0 for our PWM. In this series of
microcontrollers, a PWM block typically controls two PWM
output pins. In this case, our PWM outputs will be called
OC0A and OC0B, for Output Compare Zero A and Output
Compare Zero B. We’ll use similarly named registers in a
different way. In fact, we could just as easily have used
TMR2 or even TMR1 for PWM, but I thought that I’d
change it up a little. Yes, this is just an eight-bit PWM, but
for most of us, we use about three speeds: off, slow, and
fast. Eight bits does that just fine.
Using these techniques, you can build your next robot
with a background timer that you don’t need to pay
attention to — except to read it. I like to use a 32-bit
variable and either a 1 ms or 10 ms tic; these will last a
good long time. (Get out your calculators class! There will
be a quiz: How long will it take for a 32-bit counter to turn
over to zero when incremented every one millisecond?) You
should do some defensive programming, however, to make
sure you don’t roll over to zero between when you take a
time reading and wait for a certain period of time to pass.
When dealing with PWM, it is even simpler than setting up
a timer with an ISR. Now, go do it!
Timer0 PWM Registers
16 SERVO 12.2011
TCCR0A: Timer/Counter Control Register A. Configures
PWM configuration on OC0A/OC0B pins, if we use them
TCCR0B: Timer/Counter Control Register B. Configures
Timer 0 pre-scale settings and a little more of the PWM
Next Time, PIC Microcontrollers
I’ll be writing about a few different PIC micros and a
couple of different compilers next month. PICs are different
than the ATmega parts, but not more difficult to use. Well,
we’ve come to the end of another Mr. Roboto! Keep those
letters rolling in to email@example.com. SV