Stepper motor controller from analog input

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:

possible movements of a stepper from one position to another

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
'    attached to Analog input channel 0.  
'
'    This example doesn't correct for small fluctuations in the
'    analog input, and it doesn't error correct the stepper.
'  
'   By Tom Igoe, 31 oct 2005
'    updated 25 Oct. 2005   


 ' Define ADCIN parameters
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:
adcVar var word         ' analog in reading, 0 - 1023 
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[0] = %00001010
stepArray[1] = %00000110
stepArray[2] = %00000101
stepArray[3] = %00001001

gosub blink
Pause 1000

main:
    ' read analog in:   
    adcin 0, adcVar
    
    ' 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


blink:
    serout2 tx, inv9600, [10,13,10,13, "Start-----", 10, 13]
    for i = 0 to 2
        high LEDpin
        pause 200
        low LEDPin
        pause 200
    next
return