I was having trouble getting a stepper motor to function using the example in the Web IDE using the <stepper.h> library. I was using a ROHS 28BYJ-48 motor and a ULN2003 driver board and an external 5v power supply to drive the board. Spent quite a lot of time on it to no avail. So I pulled all the spec sheets for the motor and driver board (btw there's a lot of mis-documentation out there on these components) and created my own sketch for stepper motor control. I thought others might be having the same trouble and would benefit from my sketch. I've attached it here.
Step_motor_self_Continuos.ino (12.9 KB)
/*
Tom Gee Feb 22, 2022
This Sketch allows coninuous control of a 4 phase (unipolar) stepper motor (Rohs 28BYJ-48).
The Rohs 28BYJ-48 has a gear reduction ratio of 64:1 and 32 steps (64 half steps) per stepper rotor revolution
so steps per motor output shaft rev = 32 x 64 = 2048
Sending a serial command of '+' will increase the speed of the motor by 1 rpm
Sending a serial command of '-' will decrease the speed of the motro by 1 rpm
Sending a serail command of 'f' will cause the motor to rotate in the CW direction
Sending a serail command of 'r' will cause the motor to rotate in the CWW direction
Sending a serail command of 's' will cause the motor to stop
Sending any serail command other than the ones above will start the motor again
Serial window must be set to NO LINE ENDING for this to work!
Commands will be responded to within 1 stator revolution.
Max RPM is 18, beyond that the stator will not respond and the motor will stall
A speed increase button will ground D3. Pressing this button will increase the speed of the motor by 1 RPM. Holding this button will increase the speed at a rate of 2 RPM/sec
A speed decrease button will ground D4. Pressing this button will decrease the speed of the motor by 1 RPM. Holding this button will decrease the speed at a rate of 2 RPM/sec
A Reverse button will ground D5. Pressing this will cause the motor to reverse direction. It only acts on rising (actually falling as they're pulled to ground) edges
A Stop button will ground D6. Pressing this will cause the motor to stop. It only acts on rising (actually falling as they're pulled to ground) edges
Pressing any button while the motor is stopped will resume it in the direction and speed last assigned
*/
const int ph1 = 8; //These are the inputs for the 4 phases of the stepper motor
const int ph2 = 9;
const int ph3 = 10;
const int ph4 = 11;
const int stepsPerRev = 2048; //Number of steps for one revolution of the motor output shaft
const int revLmt = 640; // This can be modified to stop the motor are this many output shaft revolutions
const int spdButtonUp = 3; //Speed up button. Grounding this input will increase the motor speed by RPMstep (1) RPM. Note Clipped at 18 RPM
const int spdButtonDn = 4; //Speed down button. Grounding this input will decrease the motor speed by RPMstep (1) RPM. Note Clipped at 1 RPM
const int revButton = 5; //Reverse Button. Grounding this input will cause the motor to reverse directions
const int stopButton = 6; //Stop Button. Grounding this input will cause the motor to stop or start depending on the previous state.
int timeBTWsteps; //Time between steps in MicroSeconds. Calcuated based on RPM
int RPM = 17; //Motor output shaft desired speed
int revs = 0; // Number of output shaft revolutions since last change in direction or stopped state
int incByte = 0; //Register to hold the incoming byte from the serial port
int RPMstep = 1; //Size of the RPM step during incrementing or decrementing motor speed
bool CCW = false; //Motor direction. False = CW. True = CCW. Intialized to CW.
bool CCWlst = false; //Motor direction during last software loop
bool stop = false; //Stop cammand. False = stopped. True = Run. Intialized to Run
bool spdTmrlth = false; //used to latch Speed timer. False = unlatched. True = Latched. Intialized to unlatched
bool stpBut = false; //state of the stop button
bool stpButLst = false; // state of the stop button on last software loop. Used to only act on rising edge of button press
bool revBut = false; // state of the Reverse button
bool revButLst = false; //state of the reverse button on last loop. Used to only act on rising edge of button press
int steps = 0; //Number of steps made by the motor. Resets on a full revolution
unsigned long spdTmr = 0; //timer parameters used during a speed button press to allow incrementing/decementing on a button hold
unsigned long spdTmrNew = 0;
unsigned long spdTmrOld = 0;
void setup() {
Serial.begin(9600);
pinMode(ph1, OUTPUT);
digitalWrite(ph1, HIGH);
pinMode(ph2, OUTPUT);
digitalWrite(ph2, HIGH);
pinMode(ph3, OUTPUT);
digitalWrite(ph3, HIGH);
pinMode(ph4, OUTPUT);
digitalWrite(ph4, HIGH);
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev;
pinMode(spdButtonUp, INPUT_PULLUP);
pinMode(spdButtonDn, INPUT_PULLUP);
pinMode(revButton, INPUT_PULLUP);
pinMode(stopButton, INPUT_PULLUP);
}
void loop() {
if (Serial.available() > 0) { //controls motor thru the serial port
incByte = Serial.read();
if (incByte == '+') {
RPM = RPM + RPMstep;
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev;
incByte = 0;
stop = false;
Serial.print("RPM = ");
Serial.println(RPM);
Serial.print("Time btw steps = ");
Serial.println(timeBTWsteps);
}
else if (incByte == '-') {
RPM = RPM - RPMstep;
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev;
incByte = 0;
stop = false;
Serial.print("RPM = ");
Serial.println(RPM);
Serial.print("Time btw steps = ");
Serial.println(timeBTWsteps);
}
else if (incByte == 'r') {
CCW = true;
incByte = 0;
stop = false;
}
else if (incByte == 'f') {
CCW = false;
incByte = 0;
stop = false;
}
else if (incByte == 's') {
incByte = 0;
stop = true;
}
else {
stop = false;
steps = 0;
revs = 0;
}
}
if (digitalRead(spdButtonUp) == LOW) { //controls motor thru button presses
spdTmrNew = millis(); //start timer
if ((spdTmrNew - spdTmrOld) > 1000) { //first time thru set TmrOld to valid value
spdTmrOld = spdTmrNew;
}
spdTmr = spdTmr + (spdTmrNew - spdTmrOld); //Increment timer will button pressed
spdTmrOld = spdTmrNew;
if (spdTmr < 100 && spdTmrlth == false) { //increment spd on a single push, but only on rising edge
spdTmrlth = true;
if (RPM <= 17) { //increment RPM if less than 18
RPM = RPM + RPMstep;
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev; //recalculate time between steps based on ne RPM
stop = false;
Serial.print("RPM = "); //acknowlegde RPM change and report time between steps
Serial.println(RPM);
Serial.print("Time btw steps = ");
Serial.println(timeBTWsteps);
}
else {
RPM = 18; //Limit RPM to a max of 18
Serial.println("RPM at upper limit 18 RPM"); //Acknowledge limit reached
}
}
else if (spdTmr > 500) { //increment RPM by RPM step every 0.5 sec if button is held
spdTmr = 0;
spdTmrOld = 0;
if (RPM <= 17) {
RPM = RPM + RPMstep;
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev;
stop = false;
Serial.print("RPM = ");
Serial.println(RPM);
Serial.print("Time btw steps = ");
Serial.println(timeBTWsteps);
}
else {
RPM = 18; //Limit RPM to a Max of 18
Serial.println("RPM at upper limit 18 RPM");
}
}
}
else if (digitalRead(spdButtonDn) == LOW) { //if Up Button not pressed, check down button
spdTmrNew = millis();
if ((spdTmrNew - spdTmrOld) > 1000) {
spdTmrOld = spdTmrNew;
}
spdTmr = spdTmr + (spdTmrNew - spdTmrOld);
spdTmrOld = spdTmrNew;
if (spdTmr < 100 && spdTmrlth == false) { //decrement RPM on short button press. Only acts on rising edge
spdTmrlth = true;
if (RPM > 1) {
RPM = RPM - RPMstep; //decrement RPM
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev;
stop = false;
Serial.print("RPM = ");
Serial.println(RPM);
Serial.print("Time btw steps = ");
Serial.println(timeBTWsteps);
}
else {
RPM = 1; //limit Min RPM to 1
Serial.println("RPM at lower limit 1 RPM");
}
}
else if (spdTmr > 500) { //decrement RPM by RPMstep every 0.5 sec if button held.
spdTmr = 0;
spdTmrOld = 0;
if (RPM > 1) {
RPM = RPM - RPMstep;
timeBTWsteps = 60000000 / RPM / 2 / stepsPerRev;
stop = false;
Serial.print("RPM = ");
Serial.println(RPM);
Serial.print("Time btw steps = ");
Serial.println(timeBTWsteps);
}
else {
RPM = 1; //limit Min RPM to 1
Serial.println("RPM at lower limit 1 RPM");
}
}
}
else { //Hold timers in reset when button not pressed
spdTmr = 0;
spdTmrNew = 0;
spdTmrOld = 0;
spdTmrlth = false;
}
if (digitalRead(revButton) == LOW && revButLst == false) { //Reverse motor direction when button pressed. Only acts on rising edge
revBut = true;
CCW = !CCW;
stop = false;
Serial.println("Reverse button pressed");
}
else if (digitalRead(revButton) == HIGH) {
revBut = false;
}
revButLst = revBut;
if (digitalRead(stopButton) == LOW && stpButLst == false) { //Stop motor or start motor on button press. Only acts on rising edge
stpBut = true;
stop = !stop;
Serial.println("Stop button pressed");
}
else if (digitalRead(stopButton) == HIGH) {
stpBut = false;
}
stpButLst = stpBut;
if (CCW == false && stop == false) { //Execute a complete set of 8 half steps in the forward direction if CCW = false and Stop not commanded
if (CCWlst == true) { //reset steps and revs on a motor direction change
steps = 0;
revs = 0;
}
digitalWrite(ph1, HIGH);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, LOW);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, HIGH);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, LOW);
digitalWrite(ph4, LOW);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
digitalWrite(ph1, HIGH);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, LOW);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, HIGH);
digitalWrite(ph2, LOW);
digitalWrite(ph3, LOW);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
digitalWrite(ph1, HIGH);
digitalWrite(ph2, LOW);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, LOW);
digitalWrite(ph2, LOW);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
digitalWrite(ph1, LOW);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, LOW);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, LOW);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
}
if (CCW == true && stop == false) { //Execute a full set of 8 half steps in the reverse direction if CCW = true and Stop not commanded
if (CCWlst == false) {
steps = 0;
revs = 0;
}
digitalWrite(ph1, LOW);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, LOW);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, LOW);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
digitalWrite(ph1, LOW);
digitalWrite(ph2, LOW);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, HIGH);
digitalWrite(ph2, LOW);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
digitalWrite(ph1, HIGH);
digitalWrite(ph2, LOW);
digitalWrite(ph3, LOW);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, HIGH);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, LOW);
digitalWrite(ph4, HIGH);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
digitalWrite(ph1, HIGH);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, LOW);
digitalWrite(ph4, LOW);
delayMicroseconds(timeBTWsteps);
digitalWrite(ph1, HIGH);
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, LOW);
delayMicroseconds(timeBTWsteps);
steps = steps + 1;
}
if (revs == revLmt) { //Stop the motor when revLmt is reached
stop = true;
}
if (stop == true) { //Reset steps when motor is stopped
steps = 0;
digitalWrite(ph1, HIGH); //set all phases high to prevent over heating a coil
digitalWrite(ph2, HIGH);
digitalWrite(ph3, HIGH);
digitalWrite(ph4, HIGH);
}
if (steps >= stepsPerRev) { //Acknowledge when a revolution is complete and provide count
Serial.print("steps = ");
Serial.println(steps);
steps = 0;
revs = revs + 1;
Serial.print(revs);
Serial.println(" revs complete");
}
CCWlst = CCW;
}