Link here

Example Stepper Motor Control Programs


Control Program in the C Language

// C Language demo for Stepper Motors using PowerIO Wildcard, V6 (for PDQ platform)
// DATE:        11/6/2009
 
// This file provides a demo program to control one or
// more stepper motors using a PDQ controller with one or two Power I/O Wildcards.
// Two steppers per Wildcard can be supported.
// The default implementation is two steppers, though 4 can be supported.
// At 1000 steps/sec, four steppers consume about 8% of the CPU time on a PDQ controller.
 
// 1000 TICKS/SECOND allows a maximum speed of 1000 steps per second
// if full stepping a motor (which may be too fast for the default motor shipped
// by Mosaic), or 1000 half steps per second if half stepping a motor.
// Driving 4 motors with TICKS_PER_SECOND = 1000 makes a worst-case demand
// of about 8% of the PDQ processor's time.
 
// This demo uses OC3 to make a 1 msec clock.  You may use any of the 8 output compares
// that are available; see the PDQ user guide for details.
 
// NOTE: make sure that MOTOR_0_1_MODULENUM and MOTOR_2_3_MODULENUM
// match the hardware jumpers on your PowerIO Wildcard(s)!
 
#include  <mosaic\allqed.h>    // include the standard library functions
#include "steppers.h"          // Include prebuilt driver
 
 
#define TCNTS_PER_MSEC 625
// 625 is the default number of tcounts per millisecond on the PDQ platforms;
// this corresponds to 1.6 microsec per tcount.
// NOTE: if your application calls ECTPrescaler to change the default system prescaler,
// change the value of TCNTS_PER_MSEC to reflect the change.
// See the glossary entry for ECTPrescaler for more details.
 
#define MSEC_PER_TICK 1    // for accuracy, this should divide evenly into 1000
 
#define TCNTS_PER_TICK ((int) (TCNTS_PER_MSEC * MSEC_PER_TICK))
    // must fit in 16 bits (<65535)
 
#define TICKS_PER_SECOND ((int) (1000 / MSEC_PER_TICK))
    // must agree with TCNTS_PER_TICK
 
// The following speeds are in steps/sec; the Init_Steppers function adjusts
// the values to be correct whether full stepping or half stepping.
// Similarly, the following accelerations/decelerations are in steps/sec/sec.
// But if you pass these parameters to a function directly, make sure
// to multiply by two if you are half stepping;
// see the call to Steps_At_Speed in the Revolutions function for an example.
// Note that you are free to specify different speeds and accelerations
// for each motor. You can mix and match by customizing InitSteppers().
 
#define MAX_STEPPERS 4     // NOTE: this can NOT exceed 4!
    // values in excess of 4 exceed the allocated data structures of the stepper driver.
 
// the following are in (half)steps/sec:
#define DEFAULT_JOG_START_SPEED 100    // no ramp-up or ramp-down needed
#define DEFAULT_STEADY_SPEED    500    // destination speed of a ramp-up
 
// the following are in (half)steps/sec/sec:
#define DEFAULT_ACCELERATION  2500        // used during ramp up
#define DEFAULT_DECELERATION  2500        // used during ramp down
 
 
// motor0 and motor1 are interfaced via one Power I/O Wildcard:
#define MOTOR_0_1_ADDRESS    0x00 // module offset 0 is the high-current output byte
#define MOTOR_0_1_MODULENUM 0x01 // modulenum = 1; MAKE SURE THIS MATCHES HARDWARE JUMPERS!
#define MOTOR_0_MASK        0x0F // motor0 is at bits 0-3
#define MOTOR_1_MASK        0xF0 // motor1 at bits 4-7
 
 
// motor2 and motor3 are interfaced via a second Power I/O Wildcard:
#define MOTOR_2_3_ADDRESS    0x00 // module offset 0 is the high-current output byte
#define MOTOR_2_3_MODULENUM 0x02 // modulenum = 2; MAKE SURE THIS MATCHES HARDWARE JUMPERS!
#define MOTOR_2_MASK        0x0F // motor2 is at bits 0-3
#define MOTOR_3_MASK        0xF0 // motor3 at bits 4-7
 
 
void OC3_Motor_Service(void)
// use OC3 as a periodic interrupt, based on TCNTS_PER_TICK
{     uint oc3_value;
     Call_Step_Manager();                            // invoke the stepper motor handler
     oc3_value = OCICRegRead(3);                    // use OC3, auto-clears irq flag
     OCRegWrite(oc3_value+TCNTS_PER_TICK, 3); // setup next interrupt; irq flag autocleared
}
 
MAKE_ISR(OC3_Motor_Service); // needed for Attach() to work
 
 
void Init_Stepper_IRQ(void)
{    ATTACH(OC3_Motor_Service, ECT3_ID);     // post the interrupt handler
    ECTClearInterruptFlag(3);    // clear irq flag
    OutputCompare(3);                // configure ect channel 3 as an output compare
    OCAction(OC_NO_ACTION, 3); // timer channel OC3 has no pin action on timer match
    ECTFastClear();                // auto-clear of the interrupt bit when register is accessed
    ECTInterruptEnable(3);        // enable local interrupt
    ENABLE_INTERRUPTS();            // globally enable interrupts
}
 
void Disable_Stepper_IRQ(void)
{    ECTInterruptDisable(3);        // locally disable
    ECTClearInterruptFlag(3);    // clear irq flag
}
 
void Init_Motor_0(int use_half_steps)
// use_half_steps is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
// Note that you should customize  this routine for your own application,
// setting the appropriate steady speed (typically the maximum speed
// at which no steps are lost), acceleration, and half/full step
// specification for each motor.
{    int speedfactor = 1;
    if(use_half_steps)
        speedfactor = 2;    // if halfstepping, multiply speeds & accel * 2
   Init_Stepper_Status(DEFAULT_JOG_START_SPEED * speedfactor,
        DEFAULT_STEADY_SPEED * speedfactor, DEFAULT_ACCELERATION * speedfactor,
        DEFAULT_DECELERATION * speedfactor,
        MOTOR_0_1_ADDRESS, MOTOR_0_1_MODULENUM, MOTOR_0_MASK, use_half_steps, 0);    // motor0
}
 
void Init_Motor_1(int use_half_steps)
// use_half_steps is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
// Note that you should customize  this routine for your own application,
// setting the appropriate steady speed (typically the maximum speed
// at which no steps are lost), acceleration, and half/full step
// specification for each motor.
{    int speedfactor = 1;
    if(use_half_steps)
        speedfactor = 2;    // if halfstepping, multiply speeds & accel * 2
   Init_Stepper_Status(DEFAULT_JOG_START_SPEED * speedfactor,
        DEFAULT_STEADY_SPEED * speedfactor, DEFAULT_ACCELERATION * speedfactor,
        DEFAULT_DECELERATION * speedfactor,
        MOTOR_0_1_ADDRESS, MOTOR_0_1_MODULENUM, MOTOR_1_MASK, use_half_steps, 1);    // motor1
}
 
void Init_Motor_2(int use_half_steps)
// use_half_steps is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
// Note that you should customize  this routine for your own application,
// setting the appropriate steady speed (typically the maximum speed
// at which no steps are lost), acceleration, and half/full step
// specification for each motor.
{    int speedfactor = 1;
    if(use_half_steps)
        speedfactor = 2;    // if halfstepping, multiply speeds & accel * 2
   Init_Stepper_Status(DEFAULT_JOG_START_SPEED * speedfactor,
        DEFAULT_STEADY_SPEED * speedfactor, DEFAULT_ACCELERATION * speedfactor,
        DEFAULT_DECELERATION * speedfactor,
        MOTOR_2_3_ADDRESS, MOTOR_2_3_MODULENUM, MOTOR_2_MASK, use_half_steps, 2);    // motor2
}
 
 
void Init_Motor_3(int use_half_steps)
// use_half_steps is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
// Note that you should customize  this routine for your own application,
// setting the appropriate steady speed (typically the maximum speed
// at which no steps are lost), acceleration, and half/full step
// specification for each motor.
{    int speedfactor = 1;
    if(use_half_steps)
        speedfactor = 2;    // if halfstepping, multiply speeds & accel * 2
   Init_Stepper_Status(DEFAULT_JOG_START_SPEED * speedfactor,
        DEFAULT_STEADY_SPEED * speedfactor, DEFAULT_ACCELERATION * speedfactor,
        DEFAULT_DECELERATION * speedfactor,
        MOTOR_2_3_ADDRESS, MOTOR_2_3_MODULENUM, MOTOR_3_MASK, use_half_steps, 3);    // motor3
}
 
_Q void Init_Steppers( int use_half_steps )
// use_half_steps is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
// This routine can be customized for your own application,
// setting the appropriate steady speed (typically the maximum speed
// at which no steps are lost), acceleration, and half/full step
// specification for each motor.  While this is coded so that all motors
// either halfstep or full step, you can halfstep some motors while
// full stepping others; simply modify the code to
// set &speedfactor to 1 or 2 and set the use_half_steps flag true or false as required.
{   int i;
     var_ticks_per_sec = TICKS_PER_SECOND;     // must init this global variable
    Disable_Stepper_IRQ();
    Zero_Stepper_Arrays();
    // initialize only the motors that are in use...
     Init_Motor_0(use_half_steps);
//     Init_Motor_1(use_half_steps);    // comment out this line if motor1 is not used
//     Init_Motor_2(use_half_steps);    // comment out this line if motor2 is not used
//     Init_Motor_3(use_half_steps);    // comment out this line if motor3 is not used
     for(i=0; i < MAX_STEPPERS; i++)
         Clear_Motor_Port(i);
             // must clear ALL ports before energizing any to handle port overlaps
     for(i=0; i < MAX_STEPPERS; i++)
         Energize_Stepper(i);
    Init_Stepper_IRQ();  // globally enables interrupts
}
 
#define HALFSTEPS_PER_REV ((uint) 400)
#define MAX_REV ((uint) 100)
// HALFSTEPS_PER_REV * MAX_REV must fit in a 16-bit value (< 65535)
 
 
_Q void Revolutions( int direction, uint num_revolutions )
// rotates stepper motor 0 in specified direction for the specified number of revolutions,
// up to a max of MAX_REV revolutions
{    uint numsteps = (MIN(num_revolutions,MAX_REV) * HALFSTEPS_PER_REV);
    *Step_Count(0) = (long) 0;
    Steps_At_Speed(direction, numsteps, DEFAULT_STEADY_SPEED*2, 0);
                // configure the interrupt routine to do specified action in background
    while(Motor_State(0)!= MOTOR_STOPPED)    // wait until motor stops
        Pause();            // give other tasks a chance to run while waiting
    MicrosecDelay(1000);  // wait one more tick to be sure step count is updated
    numsteps = ABS((int)*Step_Count(0));  // convert to unsigned (removes direction info)
    printf("\nMotor took %6u steps\n",numsteps);
}
 
 
_Q void Demo_Stepper( void ) // this is the stepper demo, spins motor ten revolutions
{    Init_Steppers(TRUE);    // init specified motors for half stepping
    Revolutions(CW,5);    // five clockwise revolutions
    Revolutions(CCW,5);    // five counter-clockwise revolutions
}
 
 
int main( void ) // calls the Stepper_Demo, spins motor ten revolutions
{    Demo_Stepper();
    return 0;
}

Control Program in the Forth Language

\ Forth demo for Stepper Motors using PowerIO Wildcard, V6 (for PDQ platform)
\ DATE:        11/6/2009
 
\ This file provides a demo program to control one or
\ more stepper motors using a PDQ controller with one or two Power I/O Wildcards.
\ Two steppers per Wildcard can be supported.
\ The default implementation is two steppers, though 4 can be supported.
\ At 1000 steps/sec, four steppers consume about 8% of the CPU time on a PDQ controller.
 
\ 1000 TICKS/SECOND allows a maximum speed of 1000 steps per second
\ if full stepping a motor (which may be too fast for the default motor shipped
\ by Mosaic), or 1000 half steps per second if half stepping a motor.
\ Driving 4 motors with TICKS_PER_SECOND = 1000 makes a worst-case demand
\ of about 8% of the PDQ processor's time.
 
\ This demo uses OC3 to make a 1 msec clock.  You may use any of the 8 output compares
\ that are available; see the PDQ user guide for details.
 
\ NOTE: make sure that MOTOR_0_1_MODULENUM and MOTOR_2_3_MODULENUM
\ match the hardware jumpers on your PowerIO Wildcard(s)!
 
 
ANEW stepdemo    \ marker for easy reloading
 
DECIMAL    \ interpret these numbers as decimal...
 
625  CONSTANT  TCNTS_PER_MSEC
\ 625 is the default number of tcounts per millisecond on the PDQ platforms;
\ this corresponds to 1.6 microsec per tcount.
\ NOTE: if your application calls ECT.Prescaler to change the default system prescaler,
\ change the value of TCNTS_PER_MSEC to reflect the change.
\ See the glossary entry for ECT.Prescaler for more details.
 
1 CONSTANT MSEC_PER_TICK    \ for accuracy, this should divide evenly into 1000
 
TCNTS_PER_MSEC MSEC_PER_TICK * CONSTANT  TCNTS_PER_TICK  \ must fit in 16 bits (<65535)
 
1000 MSEC_PER_TICK / CONSTANT TICKS_PER_SECOND \ must agree with TCNTS_PER_TICK
 
\ The following speeds are in steps/sec; the Init_Steppers function adjusts
\ the values to be correct whether full stepping or half stepping.
\ Similarly, the following accelerations/decelerations are in steps/sec/sec.
\ But if you pass these parameters to a function directly, make sure
\ to multiply by two if you are half stepping;
\ see the call to Steps_At_Speed in the Revolutions function for an example.
\ Note that you are free to specify different speeds and accelerations
\ for each motor. You can mix and match by customizing InitSteppers().
 
4 CONSTANT MAX_STEPPERS    \ NOTE: this can NOT exceed 4!
    \ values in excess of 4 exceed the allocated data structures of the stepper driver.
 
\ the following are in (half)steps/sec:
100    CONSTANT DEFAULT_JOG_START_SPEED    \ no ramp-up or ramp-down needed
500    CONSTANT DEFAULT_STEADY_SPEED       \ destination speed of a ramp-up
 
\ the following are in (half)steps/sec/sec:
2500 CONSTANT DEFAULT_ACCELERATION         \ used during ramp up
2500 CONSTANT DEFAULT_DECELERATION         \ used during ramp down
 
 
\ motor0 and motor1 are interfaced via one Power I/O Wildcard:
0x00 CONSTANT  MOTOR_0_1_ADDRESS    \ module offset 0 is the high-current output byte
0x01 CONSTANT  MOTOR_0_1_MODULENUM \ modulenum = 1; MAKE SURE THIS MATCHES HARDWARE JUMPERS!
0x0F CONSTANT  MOTOR_0_MASK        \ motor0 is at bits 0-3
0xF0 CONSTANT  MOTOR_1_MASK        \ motor1 at bits 4-7
 
 
\ motor2 and motor3 are interfaced via a second Power I/O Wildcard:
0x00 CONSTANT  MOTOR_2_3_ADDRESS    \ module offset 0 is the high-current output byte
0x02 CONSTANT  MOTOR_2_3_MODULENUM \ modulenum = 2; MAKE SURE THIS MATCHES HARDWARE JUMPERS!
0x0F CONSTANT  MOTOR_2_MASK    \ motor2 is at bits 0-3
0xF0 CONSTANT  MOTOR_3_MASK    \ motor3 at bits 4-7
 
: OC3_Motor_Service    ( -- )
\ use OC3 as a periodic interrupt, based on TCNTS_PER_TICK.
     Call_Step_Manager        \ invoke the stepper motor handler, treats Y nicely
     3 OC.IC.REG.READ                ( oc3.register -- ) \ auto-clears irq flag
     TCNTS_PER_TICK +                ( updated.oc3.reg.contents -- )
     3 OC.REG.WRITE                ( -- ) \ setup next interrupt; irq flag autocleared
;
 
: Init_Stepper_IRQ    ( -- )
    CFA.FOR OC3_Motor_Service ECT3.ID ATTACH
    3 ECT.CLEAR.INTERRUPT.FLAG          \ clear irq flag
    3 OUTPUT.COMPARE            \ configure ect channel 3 as an output compare
    OC.NO.ACTION 3             ( oc_action_id\channel_id -- )
    OC.ACTION                    ( -- ) \ timer channel OC3 has no pin action on timer match
    ECT.FAST.CLEAR                \ auto-clear of the interrupt bit when register is accessed
    3 ECT.INTERRUPT.ENABLE    \ locally enable
    ENABLE.INTERRUPTS
;
 
: Disable_Stepper_IRQ    ( -- )
     3 ECT.INTERRUPT.DISABLE        \ locally disable
    3 ECT.CLEAR.INTERRUPT.FLAG        \ clear irq flag
;
 
: Init_Motor_0    ( Half_Steps? -- )
\ Half_Steps? is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
\ Note that you should customize  this routine for your own application,
\ setting the appropriate steady speed (typically the maximum speed
\ at which no steps are lost), acceleration, and half/full step
\ specification for each motor.
     1 NEEDED
    DUP IF 2 ELSE 1 ENDIF         \ if halfstepping, multiply speeds & accel * 2
    LOCALS{ &speedfactor &half? }
    DEFAULT_JOG_START_SPEED &speedfactor *
    DEFAULT_STEADY_SPEED    &speedfactor *
    DEFAULT_ACCELERATION    &speedfactor *
    DEFAULT_DECELERATION    &speedfactor *
    MOTOR_0_1_ADDRESS MOTOR_0_1_MODULENUM MOTOR_0_MASK &half? 0    \ motor0
    Init_Stepper_Status
;
 
: Init_Motor_1    ( Half_Steps? -- )
\ Half_Steps? is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
\ Note that you should customize  this routine for your own application,
\ setting the appropriate steady speed (typically the maximum speed
\ at which no steps are lost), acceleration, and half/full step
\ specification for each motor.
     1 NEEDED
    DUP IF 2 ELSE 1 ENDIF         \ if halfstepping, multiply speeds & accel * 2
    LOCALS{ &speedfactor &half? }
    DEFAULT_JOG_START_SPEED &speedfactor *
    DEFAULT_STEADY_SPEED    &speedfactor *
    DEFAULT_ACCELERATION    &speedfactor *
    DEFAULT_DECELERATION    &speedfactor *
    MOTOR_0_1_ADDRESS MOTOR_0_1_MODULENUM MOTOR_1_MASK &half? 1    \ motor1
    Init_Stepper_Status
;
 
: Init_Motor_2    ( Half_Steps? -- )
\ Half_Steps? is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
\ Note that you should customize  this routine for your own application,
\ setting the appropriate steady speed (typically the maximum speed
\ at which no steps are lost), acceleration, and half/full step
\ specification for each motor.
     1 NEEDED
    DUP IF 2 ELSE 1 ENDIF         \ if halfstepping, multiply speeds & accel * 2
    LOCALS{ &speedfactor &half? }
    DEFAULT_JOG_START_SPEED &speedfactor *
    DEFAULT_STEADY_SPEED    &speedfactor *
    DEFAULT_ACCELERATION    &speedfactor *
    DEFAULT_DECELERATION    &speedfactor *
    MOTOR_2_3_ADDRESS MOTOR_2_3_MODULENUM MOTOR_2_MASK &half? 2    \ motor2
    Init_Stepper_Status
;
 
: Init_Motor_3    ( Half_Steps? -- )
\ Half_Steps? is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
\ Note that you should customize  this routine for your own application,
\ setting the appropriate steady speed (typically the maximum speed
\ at which no steps are lost), acceleration, and half/full step
\ specification for each motor.
     1 NEEDED
    DUP IF 2 ELSE 1 ENDIF         \ if halfstepping, multiply speeds & accel * 2
    LOCALS{ &speedfactor &half? }
    DEFAULT_JOG_START_SPEED &speedfactor *
    DEFAULT_STEADY_SPEED    &speedfactor *
    DEFAULT_ACCELERATION    &speedfactor *
    DEFAULT_DECELERATION    &speedfactor *
    MOTOR_2_3_ADDRESS MOTOR_2_3_MODULENUM MOTOR_3_MASK &half? 3    \ motor3
    Init_Stepper_Status
;
 
: Init_Steppers    ( Half_Steps? -- )
\ Half_Steps? is TRUE (nonzero) for half stepping, FALSE (=0) for full stepping.
\ This routine can be customized for your own application,
\ setting the appropriate steady speed (typically the maximum speed
\ at which no steps are lost), acceleration, and half/full step
\ specification for each motor.  While this is coded so that all motors
\ either halfstep or full step, you can halfstep some motors while
\ full stepping others; simply modify the code to
\ set &speedfactor to 1 or 2 and set the &half? flag true or false as required.
     1 NEEDED
    LOCALS{ &half? }
    TICKS_PER_SECOND var_ticks_per_sec !    \ must init this global variable
    Disable_Stepper_IRQ
    Zero_Stepper_Arrays
    \ initialize only the motors that are in use...
     &half? Init_Motor_0
\     &half? Init_Motor_1    \ comment out this line if motor1 is not used
\     &half? Init_Motor_2    \ comment out this line if motor2 is not used
\     &half? Init_Motor_3    \ comment out this line if motor3 is not used
 
    MAX_STEPPERS 4 UMIN 0
    DO    I Clear_Motor_Port
    LOOP      \ must clear ALL ports before energizing any to handle port overlaps!
    MAX_STEPPERS 4 UMIN 0
    DO    I Energize_Stepper
    LOOP
    Init_Stepper_IRQ    ( -- )  \ globally enables interrupts
;
 
400 CONSTANT HALFSTEPS_PER_REV
100 CONSTANT MAX_REV    \ HALFSTEPS_PER_REV * MAX_REV must fit in a 16-bit value (< 65535)
 
 
: Revolutions ( direction\num_revolutions -- )
\ rotates stepper motor 0 in specified direction for the specified number of revolutions,
\ up to a max of MAX_REV
    MAX_REV UMIN HALFSTEPS_PER_REV *
    LOCALS{ &rev_steps &direction }
    DIN 0 0 Step_Count 2!    \ store 32-bit zero into count
    &direction &rev_steps DEFAULT_STEADY_SPEED 2* 0 ( direction\numsteps\speed\motor_num -- )
    Steps_At_Speed \ configure the interrupt routine to do specified action in background
    BEGIN 0 Motor_State MOTOR_STOPPED =    \ wait until motor stops
            PAUSE                                    \ give other tasks a chance to run while waiting
    UNTIL
    1000 MICROSEC.DELAY    \ wait one more tick to ensure Step_Count is updated
    CR ." Motor took " 0 Step_Count 2@ DABS D. ."  steps."
;
 
: Demo_Stepper ( -- )
    TRUE Init_Steppers    \ init specified motors for half stepping
    CW 5 Revolutions        \ five clockwise revolutions
    CCW 5 Revolutions        \ five counter-clockwise revolutions
;
 
This page is about: Example Stepper Motor Control Programs – Control Program in C Language // C Language demo for Stepper Motors using PowerIO Wildcard, V6 (for PDQ platform) // DATE: 11/6/2009 // This file provides demo program to control one or // more stepper motors using PDQ controller with one or two Power …
 
 
Navigation