Stepper motor controller

This section describes my experiences in controlling a couple of stepper motors with a PIC 12c509 8-pin microcontroller.
There are two implementations here, one uses two push buttons to control run-stop and direction. The other uses an RS-223 interface.

Both implementations use essentially the same circuit and the same firmware to step the motor, although the serial interface has more scope for defining the number of steps and it can also define the speed of stepping.

Push button controller

This is a stepper motor controller using a 12c509 PIC and an octal driver to power the stepper motor. The motor is actuated by two push-buttons, one controls run-stop and the other controls the direction.
There is another implementation of this controller that uses an RS-232 interface. See here for details
The controller actually runs the motor in half-steps. This means you get double the number of steps per revolution. A (nominally) 7.5 degree motor like the one I have that should give 48 steps per revolution here runs in steps of 3.75 degrees and gives 96 steps per revolution.

The motor is approx 2.5 cm. in diameter and takes roughly 120 mA when free-running.

The step time of the motor is 10mSec, and this can be changed inside the source of the controller code.

It should be possible to run 2 motors off the octal driver, each with their own PIC - or even running a more powerful motor by paralleling the unused drivers. Each of the 8 drivers can supply 500mA (with a 25% duty cycle, I am running a 50% duty cycle, be aware!)

Enough talk, first the circuit then the code

O.k. some explainations
The Yellow A & B and Grey A & B refer to the colours of 4 of the 6 wires coming from the motor. I won't go into details about stepper motor design, there's lots of stuff on the web - some of it is even accurate!

The two Red wires are common, they go to the +12 Volt supply. Each of the 4 coils inside the motor are energised in sequence when a logic 1 is applied to one of the 4 inputs to the ULN 2803. This device contains 8 Darlington drivers which will allow current to pass through the coil and down to ground when the input is driven high.
The connection to pin 10 is for the flyback diodes inside the 2303.

By energising two of the coils at some times, the motor can be made to stop half-way between it's "normal" stopping points.


; control a small stepper motor with a 12c509

; There are two controls, run/stop and direction.
; The motor steps when the RUN button is depressed.
; If the DIRECTION button is pressed the direction
; of rotation is reversed.

; 
; Peter Lynch, 13 May 1998
; (this code is NOT certified Year 2000 compliant)

		LIST P=12c509
	
	include "\picde\P12c509.inc"

OPMASK	EQU	B'11000000'
BMASK	EQU	B'00101000'	; all bits output (except GP3 and 5)
                                ; GP3 controls run/stop
                                ; GP5 controls direction
	
RUN_BTN	EQU	3
DIR_BTN	EQU	5
	
DELAY1	EQU	0C
DELAY2	EQU	0D

INDEX	EQU	0E		; step index

	ORG 0
	
; start of main code

	MOVWF	OSCCAL
	
	MOVLW	OPMASK
	OPTION	
		
	MOVLW	BMASK
	TRIS	GPIO		
				

; now go into a loop, output the next bit pattern on
; GP0 - GP4 (GP3 is input only)

	CLRF	INDEX
NEXT

; check for the run/stop button

	BTFSS	GPIO, RUN_BTN
	GOTO	NEXT

	BTFSS	GPIO,DIR_BTN
	GOTO	CWISE
	
	INCF	INDEX, W
	GOTO	NEW_IDX
CWISE
	DECF	INDEX, W
NEW_IDX
	ANDLW	.7
	MOVWF	INDEX

; here W contains the index (either incremented or decremented, depending
; on the direction switch) into the array for the new stepper actuations

	CALL	STEP		; convert the index into a bit pattern
	MOVWF	GPIO
	CALL	DELAY
	
	GOTO	NEXT
	

; routine to get step index

STEP
	ADDWF	PCL, F
	RETLW	B'00000001'
	RETLW	B'00000101'
	RETLW	B'00000100'
	RETLW	B'00000110'
	RETLW	B'00000010'
	RETLW	B'00010010'
	RETLW	B'00010000'
	RETLW	B'00010001'
	
	
; routine to delay between steps

DELAY

	MOVLW	.10		; 10 mSec per step
	MOVWF	DELAY1
DEL_0
	MOVLW	.250		; 1 millisecond delay
	MOVWF	DELAY2
	
DEL_1	

	NOP
	DECFSZ	DELAY2, F
	GOTO	DEL_1

	DECFSZ	DELAY1, F
	GOTO	DEL_0
		
	RETURN
		
	END


Serial Port stepper

This is a stepper motor controller using a 12c509 PIC and an octal driver to power the stepper motor. The motor is controlled through an RS-232 serial interface running at 38400 Baud 8N1 (this is not settable).
The controller actually runs the motor in half-steps. This means you get double the number of steps per revolution. A (nominally) 7.5 degree motor like the one I have that should give 48 steps per revolution here runs in steps of 3.75 degrees and gives 96 steps per revolution.

The PIC takes a 12byte ASCII string that identifies the PIC (a sort of address byte) defiens the direction of motion and the number of steps to take. The string also defines the time delay between steps.
Since the command string contains an address character, it is possible to have many PICs hanging off the same serial line.

The motor I used has 6 connecting wires. Two are red two are yellow and the other two are grey. The two red wires are common supply and the yellow/grey wires go to individual coils within the motor. See any of the on-line texts about stepper motor operation for more details.

The PIC drives the motor through a Darlington driver I.C. This can switch up to 500mA per channel. The motor I used pulled 90mA through each coil. Since the software uses half-stepping there can be two coils energised.
If the motor stops in this position it gets quite warm!


This is a 12 byte ASCII string. 11 data bytes and a terminating linefeed
Here is an example

             A+00100:020

The first character (A) is the address/identifier. Only the PIC with a MY_ID (see the source code) that corresponds to this character will read the rest of the string
Hint: don't use numbers for the MY_ID. Don't use the characters + - or : either and really don't use a linefeed

The next character (+) defines the direction of rotation of the motor. If you wish the motor to step in the opposite direction, use a - here.

The next 5 characters are the number of steps to take. The code stores these internally as a 16 bit unsigned integer, so you can have up to 65535 steps per command. You must have 5 digits, pad the number with leading zeros as in the example above.

The next character is a delimiter between the step count and the step time. I put it in to make the strings easier to read

The next three characters are the time delay between steps. This is in milliseconds and can take a value from 2 up to 255. If you want longer delays, you will have to change the source. Internally this number is stored in a single byte (hence the limit).

The final character is a linefeed.
Note: not a carriage return, ASCII 10, 0x0A
When the PIC receives this it will start processing the rest of the stuff you typed.

If there is an error in the format of the command string, the PIC will abandon the command and go back to wait for a new one.
When the PIC is waiting for a MY_ID character, the LED will be lit.

Anyway, here's the circuit

and here's the code.
The BCD to binary routines came from the Microchip Databook. Everthing else is my original work

Ther serial input comes in to pin GP3. It is clamped to 5v to protect the PIC and current limited to protect the data source. It would be possible to run two motors off the same ULN2803 by having a second PIC (with a different MY_ID programmed in) connected to the low 4 inputs that are shown not-connected in the diagram.

Asynchronicity and Drift
The PIC is run using its internal RC oscillator. While I have found this is satisfactory in all the (10-ish) devices I have programmed so far, you should use the calibration value for your PIC.
The serial decoder samples once per bit, so if you are feeding data through a noisy line you may have problems.

The time delay for each step is coded accurately and runs exactly to the commanded time delay on a simulator. In real-life however you will get drift. I have found this to be up to 1%.
This means that a command like A+20000:050 that should complete in 20,000 * 50 = 1000 seconds could take 990 - 1010 seconds. If you want to run commands as fast as possible, you should use a program like this to find out how much oscillator inaccuracy is in your PIC.

Example code
I have been controlling these PICs through a serial port connected to a Linux box. This is the test-code I used to check the correct operation of the PIC firmware.