3-pin controlled H-bridges such as the L293 and the sn754410 are very powerful in that you can coast, brake, go forward, reverse and everything using three control pins one of which (the enable pin) is tied to the PWM signal. This makes it very easy to program. But these sort of chips have very low max PWM frequencies and/or are old, don't use MOSFETS or just suck down the power to drive their logic.
Bummer.
You could move to a larger bridge such as the MC33887 but they are 4-5 times the cost of the sn754410 and are still limited to 10 Khz PWM frequency. This and their physical size can also be a bummer if you just need to do small currents such as in a nanosumo. Also, ever try to hand solder the SOIC-54 pins?
The Vishay si9988 which is used in the extremely cool megabitty
is small and inexpensive but uses locked-anti phase PWM do do it's
thing. If you have teeny tiny coreless motors with very low inductance
like on a nanosumo this can be hard on your batteries. You could switch the
pins and alternate between drive and brake but that requires a motherboard
mod.
H-bridges such as the Vishay SI9986/87 are cool since it can do brake,
coast as well as the usual forward and reverse. However, it only has two
control pins. This makes it problematic trying to hook up a PWM pin to it.
We'd either need some form of additional bits of logic or have to use a
programming trick which uses up too many of the CPU's cycles.
This is where timers like those on the mega88 with dual compare units
and output pins come in handy. We can use those two pins to have our cake
and eat it too. Depending on whether we want coasting, braking,
proportional brake or proportional forward/reverse we set the pins up a
certain way.
The reason this is an issue is that, in effect, the PWM channel and
polarity will move from pin to pin based on the mode you want. Without
external logic it is hard to move the PWM signal to a different pin on the
hbridge. Until now.
To illustrate, let's take a look at the SI9986 chip. It has this sort
of logic table:
This chip can give us every function we want and 1 amp current
capability in an SO-8 package to boot! We just need to think about how to
interface to it.
If, for example, we want our PWM cycle to alternate between forward and
coast. So, when TCNTx is less than the OCx register we want a 0 and 1 on
the outputs. When TCNTx is greater than or equal to OCx we want hiz on the
outputs. Output B is easy since we can just leave a 1 on it in this mode.
Output A requires a little thought. We want the motor to drive forward
when we have a ZERO on the input instead of a 1 which is how we would
normally do it. However, that's no big deal. The mega88 allows us to
switch to INVERTED PWM by just twiddling the COMxy bits. Now it will be a
zero during the "drive" portion of the PWM cycle.
If we want to do the same thing but have the motor run in reverse we do
the same operation but swap function of the I/O pins. What that means is
that the pin we send PWM signal to will CHANGE when we reverse directions!
This is why we we need to do this with a timer that has dual outputs. We
will use the COMxy bits to alter what appears on the pins.
Here is the complete table of how to make it all work. "inv" means
inverted PWM (i.e. set on compare match and clear at top). "normal" means
what we normally expect to see with PWM (clear on compare match and set at
top).
One of the coolest things about this technique is that it doesn't
require funny code inside an interrupt to handle the pins. All you have to
do is adjust the COMxy values for the pins when you set the motor direction
and whether you want to brake/coast during the off cycle.
Go HERE to get
the source code for the setmotors function that does it all! Well, almost
all, I haven't bothered implementing locked anti-phase yet. The input pins
of the 9986 are hooked up to OC1A and OC1B.
Once the ports have been set up all that needs doing is setting the
duty cycle. The only difference here as well is that both OCRxy
must be set to the same value at the same time.
Some examples (assume 8 bit PWM):
will tell the left motor to drive forward during the "hi" part of the
duty cycle and coast when not.
This does the same but brakes instead of coasting when not driving
forward.
Locked anti-phase (if implemented) would just be enabled like so:
setmotors(FORWARD, REVERSE);
With OCR1A/B set to the halfway point the motor doesn't turn; at either
extreme the motor is full blast one way or the other.
WHAT WE GIVE IT | WHAT IT PUTS OUT | WHAT WE GET ON THE MOTOR
input A input B | output A output B |
-----------------+---------------------+--------------------------
0 0 | 0 0 | BRAKE
0 1 | 0 1 | FORWARD
1 0 | 1 0 | REVERSE
1 1 | hiz hiz | COAST
WE WANT | THEN DO THIS
----------------------------+-------------------------
when:
PWM ON PWM OFF | OCRxA OCRxB comments
----------------------------+-----------------------------
forward coast | 1 inv 0 = coast, 1+ = more drive
reverse coast | inv 1
forward brake | 0 normal
reverse brake | normal 0
brake coast | inv inv 0 = no brake, 1+ = more brake
forward reverse | normal inv locked antiphase
reverse forward | inv normal locked antiphase
setmotor(FORWARD, COAST);
OCR1A = 128;
ORC1B = 128;
setmotors(FORWARD, BRAKE);
OCR1A = 192;
ORC1B = 192;
to email Craig send to climber at shaw.ca (replace at with @ and
remove spaces).
Return to Craig's Electronics page.
Return to Craig's main page.
Last modified: June 12, 2007 - broke 2 drill bits today - THAT BITES