Modified phase table in stepper.cpp to enable stepping a bipolar motor using a twin H-bridge driver.
Fork of stepper by
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.
Revision 0:7b0c724fa658, committed 2014-08-23
- 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
