CS 273: The Miniboard Motor Controls

Motor Controller Hardware and Programming

Note: these notes only cover programming the motors on the miniboard. There's a good description of the theory of operation of an H-Bridge, written by Jim Brown of the Dallas Personal Robotics Group, at http://www.dprg.org/tutorials/1998-04a/. In this class we're more concerned with using them than with how they work, though.

The miniboard uses the eight-bit digital output port located at address $1004 to control the motors (and the associated LEDs)

This port is wired to the three chips to the right of the CPU chip on the board: four of the inverters on the 74HC04 hex NOT gate, and the two L293 dual H bridges.

Motors are Wired to Port B

The way it's connected is that the four high-order bits are used to turn one or more motors on or off, and the low-order four bits are used to select the corresponding motor's direction. So it looks like this:

$1004:
76543210

and the meanings of the bits (going left to right) are:

Bit 7:Motor 4 Enable
Bit 6:Motor 3 Enable
Bit 5:Motor 2 Enable
Bit 4:Motor 1 Enable
Bit 3:Motor 4 Direction
Bit 2:Motor 3 Direction
Bit 1:Motor 2 Direction
Bit 0:Motor 1 Direction

The motor output port header on the miniboard looks like this:

motor output header

There's a single piece of header strip with twelve connections. The first three are used for motor 1, the next for motor 2, the next for motor 3, and the last for motor 4. There are also two LEDs associated with each motor: turning a motor on in direction 0 also turns on its green LED, while turning it on in direction 1 also turns on its red LED. We actually only use the outer two motor pins for each motor: the middle pin is wired directly to the battery, so it always has +9 volts on it.

The way we control which motors are on (and off), and which direction they're turning is by turning bits on and off in the motor control register. So, if we were to execute the code

ldaa #%10000000
staa $1004

we would turn on motor 4, and the green motor 4 LED. At the same time, we'd be turning off motors 1 through 3.

The code

ldaa $%11001000

would turn on both motors 3 and 4; motor 4 would have its red LED turned on while motor 3 would have its green LED turned on. Motors 1 and 2 owuld be turned off.

Symbols

Trying to read those binary strings makes my eyes hurt. So, instead we can (and should) define symbols that will let us write more readable code. Here are some suggestions

The Motor Port

If we define

MOTORS equ $1004

then instead of writing

staa $1004

we can write

staa MOTORS

Similarly, we can define the meanings of all the bits with something like

ON4  equ %10000000
ON3  equ %01000000
ON2  equ %00100000
ON1  equ %00010000

RED4 equ %00001000
RED3 equ %00000100
RED2 equ %00000010
RED1 equ %00000001

Now those earlier examples turn into

ldaa #ON4
staa MOTORS

and

ldaa #ON4|ON3|RED4
staa MOTORS

which I, at least, find a lot easier to read!

Note on or'ing values together: In the example above, I used the "|" symbol to "or" the bits together. The "|" is the C "bitwise-or" operator, so it'll combine all the bits. You do need to remember that you can't have spaces in the expression (if you do, the assembler will assume the expression is over and won't include anything after it). The way I wrote it combines the bits together, and then says the whole thing is in immediate mode. I could have put #'s on all the others too, but that doesn't really matter.

More Advanced Motor Programming

The code I've given you so far for motor control requires you to construct the entire motor control word in the A accumulator, and write that out to the motor port. If you were to write something like

ldaa #ON4
staa MOTORS
ldaa #ON3
staa MOTORS

with the intent of turning on both motors, it wouldn't work: you'd be turning off motor 4 when you were turning on motor 3.

There are instructions that let you set and clear individual bits in the motor ports, however: the instructions are bset and bclr.

bset
This instruction is used to set a bit or bits in a memory location. You use it like this:
bset loc mask

What this does is to perform the logical OR of the old contents of the location and the mask: it sets the bits you specify.

So, for instance, if the value of memory location 01 is $aa, executing

bset 01 #$f0

will leave the four least-significant bits unchanged, but will set the most-significant four bits:

  10101010 old value of location 01, in binary
| 11110000 mask, in binary
  11111010 new value of location 01, in binary

So the new value of the memory location is $fa

bclr
This instruction is used to clear a bit or bits in a memory location. You use it like this:
bclr loc mask

What this one does is to perform a logical AND of the old contents of the location and the inverse of the mask: it clears the bits you specify.

So, to continue the example, if we were now to execute a

bclr 01 #$0f

we would clear the least-significant four bits, but leave the most-significant bits unchanged:

  11111010 old value of location 01, in binary
& 11110000 mask, in binary
  11110000 new value of location 01, in binary

So the new value of the memory location is $f0 (notice that the bits I set in the instruction are the ones that got cleared when the instruction was executed)

One problem with both of these instructions is that they only support direct and indexed addressing: they don't do extended, which is what we need to modify the motor port. The solution to this is another application of indexed addressing: we can point one of the index registers to the IO block, and use an offset from it to point to a particular device in the IO block. The code looks like this:

* establish symbols to work with the motors.
IO     equ  $1000
MOTORS equ  4
ON4    equ  %10000000
RED4   equ  %00001000

       org  EEPROM
start
       ldx  #IO           * point X index register at IO block

       bset MOTORS,x ON4  * turn motor 4 on
       bset MOTORS,x RED4 * turn it red

Of course, this example isn't complete: it only shows a couple of the symbols for the motor bits, and it only shows setting up the pointer to the IO block and turning on a motor. For that matter, the way it turns the motor on (and red) is less efficient than it could be; given the particular example, there is no particular reason not to have simply turned the motor on and red in a single instruction.

An implementation note: the way the HC11 implements these instructions is to read the old contents of the motor port, make the change, and write the new value out. That's why the simulator will ask you for an old value of the motor port whenever you use this instruction.


Last modified: Wed Oct 21 09:47:49 MDT 2009

Valid HTML 4.01 Transitional