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.
stepper.cpp
- Committer:
- gregeric
- Date:
- 2014-12-23
- Revision:
- 7:9fc4b1be489c
- Parent:
- 6:ee6c96064559
- Child:
- 8:75fcbd49d49f
File content as of revision 7:9fc4b1be489c:
/* * 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" //uncomment one option //#define BIPOLAR_STEPPER_1PH //#define BIPOLAR_STEPPER_2PH #define BIPOLAR_STEPPER_12S //#define UNIPOLAR_STEPPER_1PH //#define UNIPOLAR_STEPPER_2PH //#define UNIPOLAR_STEPPER_12S /* * Firing sequence for bi-polar (4 wires) stepper (2x H-Bridge driver required eg L298) */ #ifdef BIPOLAR_STEPPER_1PH //single phase A+, B+, A-, B- //motor wiring on H-bridge: A A' B B' const uint8_t pase_cw[4][4] = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}}; #endif #ifdef BIPOLAR_STEPPER_2PH //double phase A+B+, A-B+, A-B-, A+B- const uint8_t pase_cw[4][4] = {{1, 0, 1, 0}, {0, 1, 1, 0}, {0, 1, 0, 1}, {1, 0, 0, 1}}; #endif #ifdef BIPOLAR_STEPPER_12S //half step A+B+, A+, A+B-, B-, A-B-, A-, A-B+, B+ const uint8_t pase_cw[8][4] = {{1, 0, 1, 0}, {1, 0, 0, 0}, {1, 0, 0, 1}, {0, 0, 0, 1}, {0, 1, 0, 1}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}}; #endif /* * Firing sequence for uni-polar (5+ wires) stepper (4x open-collector drivers required). */ #ifdef UNIPOLAR_STEPPER_1PH //motor wiring A+ B+ A- B- const uint8_t pase_cw[4][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; #endif #ifdef UNIPOLAR_STEPPER_2PH //motor wiring A+ B+ A- B- const uint8_t pase_cw[4][4] = {{1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}, {1, 0, 0, 1}}; #endif #ifdef UNIPOLAR_STEPPER_12S //motor wiring A+ B+ A- B- const uint8_t pase_cw[8][4] = {{1, 1, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}}; #endif 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; } // test for +ve, don't flip direction for stop command steps==0 else if (steps > 0) { 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 % (sizeof(pase_cw)/4) ); _xp = pase_cw[i][0]; _xn = pase_cw[i][1]; _yp = pase_cw[i][2]; _yn = pase_cw[i][3]; } void STEPPER::setup_mtr_drv_dt(Motor_Inf *mi, Motor_Control *mt) { busy_sm_drv = 1; //stop command, 0 step 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; } else init(); // already stopped, interpret as: release HOLD currents, power down coils, motor freewheeling. busy_sm_drv = 0; return; } //already travelling full speed, new step in same direction if ((mt->state == M_CONTINUE) && ( mt->direction == mi->direction)) { if (mi->total_step < MT_SLOP_STEP) { //step len shorter than ramp down ledn 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 { //already moving, reverse direction required if ((mt->state == M_CONTINUE) && ( mt->direction != mi->direction)) { mt->state = M_CHANGE; mt->change_cnt = 5; } else {//motor was at rest? //mt->motor_step = 0; // don't destroy knowledge of current phase 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; if (mt->up_cnt==0) mt->up_cnt=1; } 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: /* * continue to energize coils: hold current position _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; if (cntl.down_cnt==0) cntl.state=M_STOP; } else { cntl.state = M_CONTINUE; } } else { cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, cntl.direction); cntl.pls_width = pls_width[cntl.up_cnt_keep - cntl.up_cnt]; } } else { break; } } else { // 1st entry from M_STOP cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, cntl.direction); cntl.pls_width = pls_width[cntl.up_cnt_keep - cntl.up_cnt]; cntl.ongoing = 1; } break; case M_CONTINUE: cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, cntl.direction); 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 { cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, cntl.direction); cntl.pls_width = pls_width[cntl.down_cnt]; } } else { break; } } else { // 1st entry from M_UP or M_CONTINUE cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, cntl.direction); 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 { cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, D_CW); cntl.pls_width = pls_width[cntl.change_cnt]; } } else { break; } } else { // 1st entry cntl.motor_step+=inf.direction; set4ports(cntl.motor_step, D_CW); cntl.pls_width = pls_width[cntl.change_cnt]; cntl.ongoing = 1; } break; default : cntl.state = M_STOP; } }