This program controls a stepper motor from an analog input. In testing it, I used a potentiometer, which gives a persistent value. An analog input that changes when it’s not contacted, like a SpectraSymbol linear or circular pot, wouldn’t work with this example.

Thanks to the Fall ’05 Wednesday morning class for the early experimentation on this code.

Written in PicBasic Pro, tested on a PIC18F252

To understand this example, consider four possible conditions: Either your new position is greater than or equal to than half a circle away from your old position, or it’s less than half a circle. In either case, you want to move the shortest possible distance, so you have to take different routes depending on which is true.

If the difference is greater than half a circle, and your new position is greater than the old one, then you move clockwise to get there fastest. If the new position is less than the old one, then you move counterclockwise to get there.

If the difference is less than half a circle, and your new position is greater than the old one, then you move counterclockwise to get there fastest. If the new position is less than the old one, then you move clockwise to get there.

If the distance is exactly half a circle, you can go either direction to get there, both are equidistant.

```'    Analog Stepper
'
'    Moves a stepper motor in response to a potentiometer
'
'    This example doesn't correct for small fluctuations in the
'
'   By Tom Igoe, 31 oct 2005
'    updated 25 Oct. 2005

DEFINE  ADC_BITS        10     ' Set number of bits in result
DEFINE  ADC_CLOCK       3         ' Set clock source (3=rc)
DEFINE  ADC_SAMPLEUS    50        ' Set sampling time in uS
TRISA = %11111111       ' Set PORTA to all input
ADCON1 = %10000010      ' Set PORTA analog and right justify result

'   serial pins and constants:
tx var portc.6
rx var portc.7
inv9600 con 16468
'   LED pin:
LEDPin var portb.0

' total number of steps:
totalSteps con 100
'   pause time between steps. Steppers have a minimum
'   pause time, usually one or two milliseconds.
pauseTime con 10

' set variables:
newPosition var byte    ' stepper position from adcVar, 0 - 100
oldPosition var byte    ' previous stepper position, 0 - 100
distance VAR BYTE       ' number of steps from old to new
steps VAR byte          ' counter for number of steps taken
stepArray VAR BYTE(4)   ' arry to hold step patterns
i var byte              ' counter for blink subroutine

clear                   ' set all variables to 0

TRISC = %11110000       ' set lower pins of port to output
PORTC = 255             ' set all pins of port high

'   Stepping patterns:
stepArray = %00001010
stepArray = %00000110
stepArray = %00000101
stepArray = %00001001

Pause 1000

main:

' convert to a range of 0 - 100
newPosition = (adcVar / 10) min totalSteps

' calculate number of steps from old to new:
distance = abs(newPosition - oldPosition)

' if we need to move:
if (distance <> 0) then
serout2 tx, inv9600, [dec oldposition, " ---> " , dec newPosition, _
"  Steps: ", DEC distance, 10, 13]
' the choice of direction is different depending
' on whether the difference is more than
' half a circle or less:
' If we're moving more than half a circle:
if (distance >= totalSteps / 2 ) then
if newPosition > oldPosition then
' move counterclockwise
gosub counterClockwise
else
' move clockwise
gosub clockwise
endif
' else we're moving less than half a circle:
else
if newPosition > oldPosition then
' move clockwise
gosub clockwise
else
' move counterclockwise
gosub counterCLockwise
endif
endif
' update oldPosition with most recent value:
oldPosition = newPosition
endif

GoTo main

clockwise:
steps = 0
while steps < distance
serout2 tx, inv9600, ["--> ", DEC steps, 10, 13]
PORTC = stepArray[steps //4]
steps = steps + 1
pause pauseTime
wend
return

counterClockwise:
steps = distance
while steps > 0
serout2 tx, inv9600, ["<-- ", DEC steps, 10, 13]
PORTC = stepArray[steps //4]
steps = steps - 1
pause pauseTime
wend
return