I expanded the HexMotor.cc and HexMotor.h library today, so that I can use the same library with both my HexMotor board and the Adafruit Industries motor shield. The only differences from a user’s standpoint are

Declare an AdafruitMotorBoard instead of HexMotorBoard.

Use motors 1,2,3,4 instead of 0,1,2,3,4,5.

motor.release() works on the AdafruitMotorBoard, but is not usable on the HexMotorBoard, which only brakes when off.

I also figured out a way to get some debugging capability into the library, so that people could check that their configuration is consistent (though there is no way to check whether the jumpers and wiring are actually what the user says they are supposed to be). I can’t use “assert” statements the way I’m used to, so I did explicit if-statements and provided output through Serial.print() calls. This only works for tests that come after the Serial.begin() call, so I put the tests in the HexMotorBoard::setup() method, assuming that it would be called after Serial.begin() in setup().

The tests can be turned off by commenting out the #define HEX_MOTOR_DEBUG 1 line in the HexMotor.h file, reducing the size of the downloaded program by 860 bytes. Actually, almost everyone will have to turn the debugging off, since every run() command sends debugging output to the serial line, so the default is to have the debugging off.

The software library is pretty much done for controlling brushed motors, except for changing PWM frequency. Currently motors 0 and 1 (1 and 2 on the Adafruit board) run at 490Hz, while motors 2 and 3 (3 and 4 of the Adafruit board) run at 976.5Hz and motors 4 and 5 at 490Hz. I don’t want to mess with the PWM for motors 2 and 3, since that timer is also used for the delay() and millis() calls, so I probably want to change the PWM frequency for the other PWM pins.

Update 8 October 2011: Since I’ve just found out how to put source code into WordPress blogs, let me put the latest versions of HexMotor.h and HexMotor.cpp here:

// HexMotor.h
// copyright Kevin Karplus 8 August 2011
// Creative Commons license Attribution-NonCommercial
// http://creativecommons.org/licenses/by-nc/3.0/
#ifndef _HexMotor_h_
#define _HexMotor_h_
#include <inttypes.h>
#include <avr/io.h>
// Define HEX_MOTOR_DEBUG if you want to get error messages from setup() for erroneous setup.
// #define HEX_MOTOR_DEBUG 1
// Declaring a HexMotorBoard gives the jumperable configuration for the board.
// The relevant jumpers are which pins drive the motor speed inputs
// and whether the H-bridges are configured for lock antiphase or sign-magnitude.
//
// IN2 of the H-bridge is always connected to SIGN XOR MAG
//
// IN1 of the H-bridge can be connected to either SIGN or MAG.
// If IN1 is connected to SIGN, then the TLE-5206 H-bridge will
// be running in a sign magnitude mode, with the Speed pin low meaning BRAKE
// and Speed pin high meaning RUN (with the sign bit indicating which way to turn).
// If IN1 is connected to MAG, then the TLE-5206 H-bridge will
// be in lock antiphase, running if the SIGN bit is high and BRAKING if the SIGN bit is low.
// The MAG bit determines which way the motor runs.
// If the MAG bit is not a PWM output, then IN1 should be connected to MAG.
// Note: on the rev 1.3 boards, the silkscreen for the jumpers is misleading.
// The center of the 5 holes for header pins is MAG and the outer one is SIGN.
// The PWM frequency for all channels defaults to 1kHz (actually 16Mz/ 2^14 = 976.56Hz)
// Changes could be made in the HexMotorBoard::setup() routine if other PWM frequencies are needed.
class HexMotorBoard
{ protected:
uint8_t SpeedPins[6];
// which pins are connected to the "speed" (MAG) inputs of each H-bridge?
// Numbers 0-54 are for Arduino pins
// Numbers 0xA0..0xA7 are for the low byte of the serial output latch
// Numbers 0xA8..0xAF are for the high byte of the serial output latch
// (on rev2 or later)
// Number 0xFF means that the MAG bit is tied to +5V
//
// Note: all SpeedPins should be connected to something.
// Note: on Arduinos other than Mega, using the Servo library means that pins 9 and 10
// are not PWM pins. If used, they should be set up as ON/OFF pins.
enum{NOT_THERE, SIGN_MAG, ANTIPHASE, FORWARD_BACKWARD_BRAKE, ONE_BIT, ADAFRUIT} MotorMode[6]; // MotorMode[i] is
// NOT_THERE if motor_i is not usable on this board
// SIGN_MAG if IN1 of motor i is connected to SIGN, and MAG is assumed to be PWM
// ANTIPHASE if IN1 of motor i connected to MAG and MAG is a PWM bit
// FORWARD_BACKWARD_BRAKE if IN1 of motor i connected to MAG, but MAG is ON/OFF, not PWM.
// ONE_BIT if IN1 is connected to MAG, which is tied to +5v, so the
// the motor is always either running forward or backward, controlled by the SIGN bit
// ADAFRUIT if this is not a HexMotor board, but an Adafruit Motor shield
//
uint8_t LatchPin, ClockPin, DataPin;
// which Arduino pins are used for talking to the Hexmotor shift register?
uint16_t ShiftRegister; // the current or future contents of the HexMotor shift register
uint8_t Version; // which model of board is used
// set (or clear) a bit in the ShiftRegister corresponding to the specified motor
inline void set_signbit(uint8_t motor, bool value=1)
{ digitalWrite(0xA0+motor, value);
}
void serial_out(void); // transfer the shift register to the HexMotor board.
public:
HexMotorBoard(
const char *antis,
const uint8_t *pins=0, // defaults to {11, 3, 6, 5, 9,10}
uint8_t version=1,
uint8_t clock=4,
uint8_t data=8,
uint8_t latch=12);
// An array of pins is given to indicate where the MAG output for each motor goes.
// The 6 antis characters are
// '-' for NOT_THERE
// 'S' or 's' for SIGN_MAG (IN1==SIGN)
// 'A' or 'a' for ANTIPHASE (IN1==MAG)
// 'F' or 'f' for FORWARD_BACKWARD_BRAKE (IN1==MAG, but MAG is not PWM bit)
// 'O' or 'o' for ONE_BIT
// 'M' or 'm' for ADAFRUIT motor shield
// The version is the integer part of the board rev number (rev1.3 is 1, rev 2.3 is 2).
// This indicates, for example, whether the board has 8 or 16 bits of shift register.
// Use rev 0 to indicate an Adafruit motorshield.
// latch, data, and clock are Arduino pins that are used for the serial output to the shift register.
void setup(void);
// makes sure that PWM frequencies are appropriately set and turns all motors off.
// Should be called during the global setup() procedure.
// QUERY: should PWM frequency be settable here (or even as separate call?)
void digitalWrite(uint8_t pin, bool value); // write a single bit to a pin (using SpeedPins naming convention)
friend class HexMotor;
};
// Declaring an AdafruitMotorBoard sets up the HexMotorBoard interface for an AdaFruit Industries Motor Shield,
// rather than for a HexMotor board.
// The declaration has no parameters, as the AdaFruit motor shield is not configurable.
// For compatibility with the M1 through M4 labeling on the motor shield, motors 1 through 4 are used,
// rather than 0 through 3.
class AdafruitMotorBoard : public HexMotorBoard
{ protected:
typedef enum{FORWARD, BACKWARD, BRAKE} MotorDir;
void change_motor_bits(uint8_t motor, MotorDir control);
public:
AdafruitMotorBoard(void);
friend class HexMotor;
};
class HexMotor
{ protected:
uint8_t Motor;
HexMotorBoard* Board;
public:
HexMotor(HexMotorBoard &board, uint8_t motor_num);
void run(int speed);
// speed is between -256 (full reverse) and 255 (full forward)
// 0 is off (braking on HexMotor, released on Adafruit)
void brake(void);
void release(void); // Available on Adafruit Motor shield,
// but not on HexMotor boards rev1 or rev 2
// since the TLE-5206 chips do not have a Hi-Z output
};
#endif