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-21
- Revision:
- 4:5b596b405573
- Parent:
- 3:96bfb8b476f8
- Child:
- 5:f2bbcd06019e
File content as of revision 4:5b596b405573:
/*
* 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_2PH
/*
* 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_2PH
const uint8_t pase_cw[4][4] = {{1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}, {1, 0, 0, 1}};
#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;
} 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 % (sizeof(pase_cw)/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;
//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;
cntl.pls_width = pls_width[cntl.change_cnt];
cntl.ongoing = 1;
}
break;
default :
cntl.state = M_STOP;
}
}
