I think I need an interrupt, but I'm not sure

#1
I am trying to build a program & hardware that will connect to my dslr to enable it to take a series of photos for image stacking with camera focus and image spacing controlled by a Picaxe.

Hardware is a NEMA 8 motor, Sparkfun stepper controller board, and a 20X2 board I've repurposed from an LDR audio preamp.

Below is the code that I have written so far that allows me to control the stepper from a Sony remote control. I'm not happy with it because stepper movement is not smooth and continuous and at maximum speed only perhaps half as fast as it would be if I fed the motor controller a continuous series of pulses.

There are certain requirements:

1. Must have a variable step rate that gives me granular control from single-steps at one end of the range to continuous, smooth high speed stepping at the other end of the range.
2. Must keep track of the total step count (in both directions) at all times (which, I believe, eliminates hpwm as an option here) to avoid overrunning the preset minimum and maximum stepper travel points.

Since the Picaxe is not multi-tasking, I have written the program make a finite number of steps per loop with the number of steps per loop increasing as the number of continuous loops increases (with the remote button held down). Letting go of the remote button resets the number of steps per loop back to a single step. This gives me a range of speeds from a single 1/16 step per loop at the beginning of a continuous press up to some user-definable large number of steps per loop after holding the remote button down for a while.

The problem is, the stepper motor movement is jerky because it's stopping at the end of each loop no matter how long I continuously hold the remote button because the program has to exit the loop to check if the move command is still valid.

If possible, I'd like to eliminate that problem, and I'm wondering if I could use an interrupt somehow to allow me to put the stepper into a continuous loop with gradually decreasing PAUSE periods between steps to give me the same control granularity but without the momentary stopping between finite sets of pulses and have it keep running until an interrupt happens (release of remote control button) stops the loop.

This is the program that currently works, but is not as smooth-running as I would like, just wondering if I could use an interrupt in lieu of exiting the stepper loop:

Code:
#Picaxe 20X2
#No_Data
#No_Table
SETFREQ m32

Main:

'Control Program Loop
DO

'    DO    'wait for command from IR
        DO : LOOP WHILE ptr = hserptr
        Cmd_Code = @ptrinc
'    LOOP UNTIL Cmd_Code <> 255


'Action

IF Cmd_Code = "J" OR Cmd_Code = "K" THEN

    IF Cmd_Code = "J" AND Count_Total < Upper_Limit THEN
        Direction = CCW
        HIGH DirectionPIN
    ELSEIF Cmd_Code = "K" AND Count_Total > 1 THEN
        Direction = CW
        LOW DirectionPIN
    ELSE
        SEROUT C.7,Baud,(254,192," LIMIT  ")
        GOTO EndCode
    ENDIF

    'if first command or position is close to a limit then reset # steps to zero
    IF Timer > 1 THEN
        Count_Target = 0
    ELSEIF Count_Total < Lower_Slowdown AND Direction = CW THEN
        Steps_Remaining = Count_Total - 1
        Count_Target = Count_Target + 1 MAX Steps_Remaining
    ELSEIF Count_Total > Upper_Slowdown AND Direction = CCW THEN
        Steps_Remaining = Upper_Limit - Count_Total - 1
        Count_Target = Count_Target + 1 MAX Steps_Remaining
    ELSE
        Count_Target = Count_Target + 1 MAX Max_Steps  'Set number of steps for this iteration based on duration of key press
    ENDIF
    
    'Do the Stepping
    Count_Stepped = 0
    DO
        PULSOUT C.1,1
        Inc Count_Stepped
    LOOP WHILE Count_Stepped < Count_Target
    
    'Calculate current position of stepper & send information to display
    IF Direction = CCW THEN
        Count_Total = Count_Total + Count_Stepped
    ELSE
        Count_Total = Count_Total - Count_Stepped
    ENDIF   
    SEROUT C.7,Baud,(254,192,"        ",#Count_Total,"-",#Count_Stepped," ")

    'cleanup
    GOTO EndCode
ENDIF


EndCode: 'Prepare for next command and loop to beginning
Timer = 0 'Reset Timer
ptr = hserptr 'clear queued commands to prevent runon
Cmd_Code = 255 'Put null in Cmd_Code   
LOOP ' return to Main
 

Attachments

Buzby

Senior Member
#2
My suggestion would be use a timed interrupt to do the pulsing, with the main loop doing the interface stuff.

MainLoop:
Read remote
Set countvalue
Loop

Interrupt: ( Triggered every 10mS maybe )
Get countvalue
Workout CCW/CW requirements
Send pulse if needed
Return

See 'settimer' and 'setint' in the manual.

Cheers,

Buzby
 
#3
Have made some progress by streamlining the code a bit -- ultimate speed is much faster and I get a significant period of slow movement followed by relatively rapid speed increase to a maximum which is very close to the maximum speed I've observed in a closed loop with no outside activity.

I need to stare at the suggested interrupt method for a while. Very rarely used interrupts and had to sweat a lot to make it work when I did try . . .


Code:
IF Cmd_Code = "J" OR Cmd_Code = "K" THEN

    IF Cmd_Code = "J" AND Count_Total < Upper_Limit THEN
        Direction = CCW
        HIGH DirectionPIN
        Steps_Remaining = Upper_Limit - Count_Total - 1
    ELSEIF Cmd_Code = "K" AND Count_Total > 1 THEN
        Direction = CW
        LOW DirectionPIN
        Steps_Remaining = Count_Total - 1
    ELSE
        SEROUT C.7,Baud,(254,192," LIMIT  ")
        GOTO EndCode
    ENDIF

    'set steps per loop
    IF Timer > 1 THEN
        Count_Target = 1
    ELSEIF Count_Target < 50 THEN
        Count_Target = Count_Target + 1
    ELSEIF Count_Target < 200 THEN
        Count_Target = Count_Target + 5
    ELSE
        Count_Target = Count_Target + 10
    ENDIF

    Count_Target = Count_Target MAX 300
    Count_Target = Count_Target MAX Steps_Remaining

    
    DoSteps:
    'Do the Stepping
    Count_Stepped = 0
    DO
        PULSOUT C.1,1
        Inc Count_Stepped
    LOOP WHILE Count_Stepped < Count_Target
    
    'Calculate current position of stepper & send information to display
    IF Direction = CCW THEN
        Count_Total = Count_Total + Count_Stepped
    ELSE
        Count_Total = Count_Total - Count_Stepped
    ENDIF   
    SEROUT C.7,Baud,(254,192,"     ",#Count_Total,"-",#Count_Stepped," ")

    'cleanup
    GOTO EndCode
ENDIF
 
#4
Further optimizing has gotten me pretty much where I want to be, I think I've got my answer, thanks to Buzby for the help understanding interrupts.
 
Top