Encoder Front Page
SRS Home | Front Page | Monthly Issue | Index
Search WWW Search seattlerobotics.org

Dual Stepper Motor Driver for a Robot Differential Drive


This article describes the hardware and the software used to control two stepper motors suitable for a robot differential drive.The circuit accepts two 2-bit words that command each of the motors to go forward, backward, hold a position, or to idle. It also provides an output signal when a step is being taken. It is a flexible design allowing for unipolar and bipolar motors and being microcontroller based the winding excitations, motor speed, control word format, and other parameters can be tailored in software. The software is provided in C and in assembly language.

Hardware Circuit

The circuit consists of three ICs, a PIC16F84 and either two L293D H-bridge drivers for bipolar steppers (shown in the figure below) or two ULN2803 for unipolar steppers. Aside from the power supplies, the only other components are a 4 MHz. resonator, a 10K pull-up resistor, and some connectors. In the current implementation a pack of 6 x 1.2V batteries, supplying 7.2V, is linearly regulated to 5V to supply the logic voltage and the raw unregulated power is applied to the 5V steppers. The 7.2V do not overdrive the motors due to the voltage-drop across the bipolar transistors in the drivers.

diagram.jpg (49775 bytes)

The control word is broken into two 2-bit control words: the two most significant bits of the control word which are bits 2 and 3 of PORTA control the left motor and the two least significant bits, bits 0 and 1 of PORTA, control the right motor. For the present control word values 00, 01, 10, and 11, the motors can be commanded to go forward, backward, hold a position, or to idle respectively. This sequence can be easily changed (see the software below).

As designed, the circuit provides the speed control; in particular, it does not require a periodic control pulse to step the motors. Rather, the circuit provides an output signal, on bit 4 of PORTA, when a step is taken. The main controller can monitor this signal to determine when the control word should be changed. For instance, to proceed forward a certain distance, the main processor calculates the number of steps necessary to achieve the goal and thus commands the motors forward. Once that number of steps is taken the command words can be changed to stop or redirect the motors. This task, of counting steps, can usually be relegated to a background task on most processors.


There are two versions of the software available; one is written in C2C, a C dialect, and the other in PICmicroŽ assembly language with the help of some macros that provide high level programming constructs

The main program simply repeatedly reads PORTA looking for an updated control word.This process is periodically interrupted by TMR0 whenever the motors require a new excitation; the task controlling the motors, which are excited only very periodically, in effect runs in the background.

The software allows for easy changes to the motor winding excitations, the control words, and the motor speed. The excitation table can be easily modified in content and in size thus allowing for half-stepping.The control words are simply an enumeration so that one can choose their own sequence. The speed can be changed by factors of two by changing the TMR0 prescaler. Finer changes can be made by changing the initial value of TMR0.

The software is presented below in pseudo-code.

EXCITATION_TABLE_SIZE = 4   // number of excitations in sequence     
TMR0_CNT_UP           = 100 // 256 - duration (motor speed)
// Motor states
RIGHT_FORWARD  = 0          // These can be re-ordered
RIGHT_HOLD     = 2
RIGHT_IDLE     = 3
LEFT_FORWARD   = 0           // Above states shifted 2 bits left (multiplied by 4)
LEFT_BACKWARD  = 4      
LEFT_HOLD      = 8 
LEFT_IDLE      = 12
leftExcitationCntr          // current left motor excitation number
rightExcitationCntr         // current right motor excitation number
motorState                   // 4 bit function word for both motors
excitations[] = {11000000b, // Excitation table - if the table is changed in size,
                 01100000b, // then the EXCITATION_TABLE_SIZE constant
                 00110000b, // must be changed
motorISR // Motor Interrupt Service Routine
   // Modifies global variables leftExcitationCntr and rightExcitationCntr as a function of motorState. 
   // It uses these counters as indices to read the motor excitation from the table and outputs it to PORTB.
   LocalVariables leftExcitation, rightExcitation
   if (motorState is RIGHT_FORWARD)
      if (rightExcitationCntr = EXCITATION_TABLE_SIZE-1)
         rightExcitationCntr = 0
         increment rightExcitationCntr
      rightExcitation = excitations[rightExcitationCntr]
   else if (motorState is RIGHT_BACKWARD)
      if (rightExcitationCntr = 0)
         rightExcitationCntr = EXCITATION_TABLE_SIZE-1
         decrement rightExcitationCntr
      rightExcitation = excitations[rightExcitationCntr]      
   else if (motorState is RIGHT_HOLD)
      rightExcitation = excitations[rightExcitationCntr]
   else // RIGHT_IDLE
      rightExcitation = 0
   shift rightExcitation 4 bits right
   if (motorState is LEFT_FORWARD)
      if (leftExcitationCntr = EXCITATION_TABLE_SIZE-1)
         leftExcitationCntr = 0
         increment leftExcitationCntr
      leftExcitation = excitations[leftExcitationCntr]       
   else if (motorState is LEFT_BACKWARD)
      if (leftExcitationCntr = 0)
         leftExcitationCntr = EXCITATION_TABLE_SIZE-1
         decrement leftExcitationCntr
      leftExcitation = excitations[leftExcitationCntr]           
   else if (motorState is LEFT_HOLD)
      leftExcitation = excitations[leftExcitationCntr]     
      leftExcitation = 0
   PORTB = leftExcitation + rightExcitation
end motorISR
interrupt  // Main interrupt service routine gets control when TMR0 overflows
   if (TMR0 overflowed causing an interrupt)
      bit 4 of PORTA = 1         // signal motor step on
      call motorISR              // call motor interrupt service routine
      bit 4 of PORTA = 0         // signal motor step off
      TMR0 = TMR0_CNT_UP;        // reset TMR0 to proper count
end interrupt
   set TMR0 prescaler = 64     // divides clock by value set
   bit 4 of PORTA = 0           // signal motor step off
   leftExcitationCntr  = 0
   rightExcitationCntr = 0
   TMR0 =  TMR0_CNT_UP;
   enable TMR0 interrupts
   while (1)                    // continuously update motorState (and wait
      motorState = PORTA        //   for a TMR0 interrupt)
end main


A general, albeit rudimentary, micro-controller based stepper motor driver has been designed and successfully built. Since only 124 of the 1024 words of PIC16F84 memory is currently being used (in the assembly version) features could be added such as acceleration and deceleration. All 13 I/O lines are currently being used and so additional external control signals may require a PICmicroŽ upgrade. The PIC16F876 with Pulse Width Modulation and Analog to Digital conversion may also allow a chopper-drive design.

Contacts and Links

Author: J.- L. (John) Girard
Website: John Girard's Embedded Systems

C2C C-compiler