Modified phase table in stepper.cpp to enable stepping a bipolar motor using a twin H-bridge driver.

Fork of stepper by Kenji Arai

Corrected single-stepping, now walking up or down just one phase table. Compile-time options for driving bipolar motor in any of single-phase, two-phase, or half-stepping. Coils remain engaged at end of specifed movement command - de-energize coils by issuing a motor.move(0) while already stopped.

Files at this revision

API Documentation at this revision

Comitter:
kenjiArai
Date:
Sat Aug 23 06:34:07 2014 +0000
Child:
1:94f55ebfe2db
Commit message:
1st release version: Stepper Motor driver Library only for uni-polar type using 4 ports and Ticker

Changed in this revision

stepper.cpp Show annotated file Show diff for this revision Revisions of this file
stepper.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stepper.cpp	Sat Aug 23 06:34:07 2014 +0000
@@ -0,0 +1,236 @@
+/*
+ * mbed library program 
+ *      Stepping Motor
+ *
+ * Copyright (c) 2014 Kenji Arai / JH1PJL
+ *  http://www.page.sannet.ne.jp/kenjia/index.html
+ *  http://mbed.org/users/kenjiArai/
+ *      Created: August    20th, 2014
+ *      Revised: August    23rd, 2014
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include    "mbed.h"
+#include    "stepper.h"
+
+const uint8_t pase_cw[4][4]  = {{1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}, {1, 0, 0, 1}};
+const uint8_t pase_ccw[4][4] = {{1, 1, 0, 0}, {1, 0, 0, 1}, {0, 0, 1, 1}, {0, 1, 1, 0}};
+extern uint8_t pls_width[];
+
+STEPPER::STEPPER (PinName xp, PinName xn, PinName yp, PinName yn):
+                   _xp(xp), _xn(xn), _yp(yp), _yn(yn) {
+    init();
+}
+
+void STEPPER::move (int32_t steps){
+    if (steps < 0){
+        inf.direction = D_CCW;
+        steps = -steps;
+    } else {
+        inf.direction = D_CW;
+    }   
+    inf.total_step = steps;
+    setup_mtr_drv_dt(&inf, &cntl);
+}
+
+void STEPPER::set_max_speed (uint32_t time_base_us){
+    if (time_base_us < (MT_PLS_WIDTH_MIN * 1000)){
+        time_base_us = (MT_PLS_WIDTH_MIN * 1000);
+    }
+    _smdrv.attach_us(this, &STEPPER::millisec_inteval, time_base_us);
+}
+
+uint8_t STEPPER::status (void){
+    return cntl.state;
+}
+
+void STEPPER::init(void){
+    busy_sm_drv = 0;
+    _xp = 0;
+    _xn = 0;
+    _yp = 0;
+    _yn = 0;
+}
+
+void STEPPER::set4ports (uint32_t step, int8_t dir){
+uint8_t i;
+
+    i = (uint8_t)(step % 4);
+    if (dir == D_CW) {
+        _xp = pase_cw[i][0];
+        _xn = pase_cw[i][1];
+        _yp = pase_cw[i][2];
+        _yn = pase_cw[i][3];
+    } else {
+        _xp = pase_ccw[i][0];
+        _xn = pase_ccw[i][1];
+        _yp = pase_ccw[i][2];
+        _yn = pase_ccw[i][3];
+    }
+}
+
+void STEPPER::setup_mtr_drv_dt(Motor_Inf *mi, Motor_Control *mt){
+    busy_sm_drv = 1;
+    if (mi->total_step == 0){
+        if (mt->state != M_STOP){
+            mt->state = M_CHANGE;
+            mt->change_cnt = 5;
+            mt->pls_width = 0;
+            mt->ongoing = 0;
+            mt->up_cnt = 0;
+            mt->up_cnt_keep = 0;
+            mt->down_cnt = 0;
+            mt->continue_cnt = 0;
+        }
+        busy_sm_drv = 0;
+        return;
+    }
+    if ((mt->state == M_CONTINUE) && ( mt->direction == mi->direction)){
+        if (mi->total_step < MT_SLOP_STEP){
+            mt->up_cnt = 0;
+            mt->up_cnt_keep = 0;
+            mt->down_cnt = mi->total_step;
+            mt->continue_cnt = 0;
+            mt->state = M_DOWN;
+            mt->ongoing = 0;
+        } else {
+            mt->up_cnt = 0;
+            mt->up_cnt_keep = 0;
+            mt->down_cnt = MT_SLOP_STEP -1;
+            mt->continue_cnt = mi->total_step - (MT_SLOP_STEP - 1);
+        }
+    } else {
+        if ((mt->state == M_CONTINUE) && ( mt->direction != mi->direction)){
+            mt->state = M_CHANGE;
+            mt->change_cnt = 5;
+        } else {
+            mt->motor_step = 0;
+            mt->state = M_UP;        
+        }
+        mt->pls_width = 0;
+        mt->ongoing = 0; 
+        mt->direction = mi->direction;
+        if (mi->total_step < MT_MIN_STEP){
+            if (mi->total_step == MT_MIN_STEP - 1){
+                mt->up_cnt = MT_SLOP_STEP;
+            } else {
+                mt->up_cnt = mi->total_step / 2;
+            }
+            mt->up_cnt_keep = mt->up_cnt;
+            mt->down_cnt = mi->total_step - mt->up_cnt;
+            mt->continue_cnt = 0;
+        } else {
+            mt->up_cnt = MT_SLOP_STEP;
+            mt->up_cnt_keep = mt->up_cnt;
+            mt->down_cnt = MT_SLOP_STEP -1 ;
+            mt->continue_cnt = mi->total_step - MT_SLOP_STEP - (MT_SLOP_STEP - 1);
+        }
+    }
+    busy_sm_drv = 0;
+}
+
+void STEPPER::millisec_inteval() {
+    if (busy_sm_drv == 1){ return;}
+    switch (cntl.state){
+    case M_STOP:
+        _xp = 0;
+        _xn = 0;
+        _yp = 0;
+        _yn = 0;
+        break;
+    case M_UP:
+        if (cntl.ongoing){
+            if (--cntl.pls_width == 0){
+                if (--cntl.up_cnt == 0){
+                    cntl.ongoing = 0;
+                    if (cntl.continue_cnt == 0){
+                        cntl.state = M_DOWN;
+                    } else {
+                        cntl.state = M_CONTINUE;
+                    }
+                } else {
+                    set4ports(cntl.motor_step, cntl.direction);
+                    cntl.motor_step++;
+                    cntl.pls_width = pls_width[cntl.up_cnt_keep - cntl.up_cnt];
+                }
+            } else {
+                break;
+            }
+        } else {    // 1st entry from M_STOP
+            set4ports(cntl.motor_step, cntl.direction);
+            cntl.motor_step++;
+            cntl.pls_width = pls_width[cntl.up_cnt_keep - cntl.up_cnt];
+            cntl.ongoing = 1;
+        }
+        break;
+    case M_CONTINUE:
+        set4ports(cntl.motor_step, cntl.direction);
+        cntl.motor_step++;
+        if (--cntl.continue_cnt == 0){
+            cntl.ongoing = 0;
+            cntl.state = M_DOWN;
+        }
+        break;
+    case M_DOWN:
+        if (cntl.ongoing){
+            if (--cntl.pls_width == 0){
+                if (--cntl.down_cnt == 0){
+                    cntl.ongoing = 0;
+                    cntl.state = M_STOP;
+                }else {
+                    set4ports(cntl.motor_step, cntl.direction);
+                    cntl.motor_step++;
+                    cntl.pls_width = pls_width[cntl.down_cnt];
+                }
+            } else {
+                break;
+            }
+        } else {    // 1st entry from M_UP or M_CONTINUE
+            set4ports(cntl.motor_step, cntl.direction);
+            cntl.motor_step++;
+            cntl.pls_width = pls_width[cntl.down_cnt];
+            cntl.ongoing = 1;
+        }
+        break;
+    case M_CHANGE:
+        if (cntl.ongoing){
+            if (--cntl.pls_width == 0){
+                if (--cntl.change_cnt == 0){
+                    cntl.ongoing = 0;
+                    if (cntl.up_cnt == 0){
+                        cntl.state = M_STOP;
+                    } else {
+                        cntl.state = M_UP;
+                    }
+                }else {
+                    if (cntl.direction == D_CW){
+                        set4ports(cntl.motor_step, D_CCW);
+                    } else {
+                        set4ports(cntl.motor_step, D_CW);
+                    }
+                    cntl.motor_step++;
+                    cntl.pls_width = pls_width[cntl.change_cnt];
+                }
+            } else {
+                break;
+            }
+        } else {    // 1st entry
+            if (cntl.direction == D_CW){
+                set4ports(cntl.motor_step, D_CCW);
+            } else {
+                set4ports(cntl.motor_step, D_CW);
+            }
+            cntl.motor_step++;
+            cntl.pls_width = pls_width[cntl.change_cnt];
+            cntl.ongoing = 1;
+        }
+        break;
+    default :
+        cntl.state = M_STOP;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stepper.h	Sat Aug 23 06:34:07 2014 +0000
@@ -0,0 +1,127 @@
+/*
+ * mbed library program 
+ *      Stepping Motor
+ *
+ * Copyright (c) 2014 Kenji Arai / JH1PJL
+ *  http://www.page.sannet.ne.jp/kenjia/index.html
+ *  http://mbed.org/users/kenjiArai/
+ *      Created: August    20th, 2014
+ *      Revised: August    23rd, 2014
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef        MBED_STEPPER
+#define        MBED_STEPPER
+
+#include "mbed.h"
+
+#define MT_SLOP_STEP            10
+#define MT_MIN_STEP             (MT_SLOP_STEP+MT_SLOP_STEP)
+#define MT_PLS_WIDTH_MIN        2      // 2mS
+
+/** Bipolar Type Stepping Motor Driver using 4 Outputs(DigitalOut) with timer interrupt(Ticker)
+ *
+ * Driver circuit: Low side driver (4ch for one Stepper) e.g. TD62003AP
+ *  CAUTION: This is only for Unipolar Type Stepping Motor!
+ *           Cannot use for Bipolar Type
+ *      Plese refer http://en.wikipedia.org/wiki/Stepper_motor
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "stepper.h"
+ *
+ * #define TIMEBASE  15000      // 15mS
+ *
+ * STEPPER sm(D5, D4, D3, D2);
+ *
+ * uint8_t pls_width[10] = {5, 4, 3, 2, 1, 1, 1, 1, 1, 1 };
+ *
+ * int main() {
+ *   sm_r.set_max_speed(TIMEBASE);
+ *   sm.move(+100);
+ *   while (sm.status){ ;}
+ *   sm.move(-1000);
+ *   wait(10);
+ *   sm.move(0);
+ *   while(true){;}
+ * }
+ * @endcode
+ */
+
+class STEPPER {
+public:
+    // Please copy following part in to your main.cpp
+    /** pulse width definition -> Use for start and stop phase
+      *  = data * TIMEBASE -> e.g following data = 5 then 5*15000/1000 = 75mS
+      */
+    //uint8_t pls_width[MT_SLOP_STEP] = {5, 4, 3, 2, 1, 1, 1, 1, 1, 1 };
+
+    /** Motor Status */
+    enum MOTOR_STATE { M_STOP = 0, M_UP, M_CONTINUE, M_DOWN, M_CHANGE, M_UNKOWN = 0xff};
+    
+    /** Configure data pin
+      * @param data SDA and SCL pins
+      */
+    STEPPER (PinName xp, PinName xn, PinName yp, PinName yn);
+
+    /** Move steps
+      * @param number of steps
+      * @return none
+      */
+    void move (int32_t steps);
+
+    /** Set time period (max speed of stepper)
+      * @param time: e.g. 10mS(=10000) -> 100 PPS(Puls per Sec)
+      * @return none
+      */
+    void set_max_speed (uint32_t time_base_us);
+
+    /** Check status
+      * @param none
+      * @return running(= 1), stopped(= 0)
+      */
+    uint8_t status (void);
+
+protected:
+    // Rotation Direction
+    enum { D_CCW = -1, D_UNKOWN = 0, D_CW = 1};
+    
+    typedef struct{
+        int8_t direction;
+        uint32_t total_step;
+    } Motor_Inf;
+    
+    typedef struct{
+        uint8_t  state;
+        int8_t   direction;
+        uint8_t  up_cnt;
+        uint8_t  up_cnt_keep;
+        uint8_t  down_cnt;
+        uint8_t  change_cnt;
+        uint8_t  pls_width;
+        uint8_t  ongoing;
+        uint32_t continue_cnt;
+        uint32_t motor_step;  
+    } Motor_Control;
+
+    DigitalOut _xp, _xn, _yp, _yn;
+    Ticker _smdrv;
+    
+    void init();
+    void set4ports (uint32_t step, int8_t dir);
+    void setup_mtr_drv_dt(Motor_Inf *mi, Motor_Control *mt);
+    void millisec_inteval();
+
+private:
+    uint8_t busy_sm_drv;
+    Motor_Inf inf;   
+    Motor_Control cntl;
+
+};
+   
+#endif  //  MBED_STEPPER