Bug in code that causes engine to start running after 30 seconds of inactivity --> Arduino Step Motor with one push button 90° CW, Same button 90°CCW

Hello,
I'm new here, and I have a little project where I need to turn my stepper (28ByJ-48) 90° CW after pressing a button, than it has to stops, then turn 90°CCW after pushing the same button again.
I use a ULN2003 5V and Arduino Uno R3.
I already find a program to turn the motor CW and CCW with two buttons, but not with one.
Can someone help me please? thanks a lot!

Have a variable that records the direction the stepper should move to. This may be as simple as a boolean.

Partial pseudo-code:

bool direction_CW = true;

void setup () {
  [...]
}

void loop () {
  
  if (button_pressed) {
    if (direction_CW) {
      [Move stepper clockwise]
      direction_CW = false;
    }
    else {
      [Move stepper counter-clockwise]
      direction_CW = true;    
    }
  }
}

thanks for you fast answer !

after the void loop() I have now this:
That is written for 3 buttons (CW/CCW and STOP)
Like I said, i'm not verry used with this code.
with part do I have to replace with you code?

 void loop() 
{ 
    stepVale = (SPR * goToAngle)/360 ;
  //Robojax.com Stepper Push button Any Angle STPB-4
  if(digitalRead(switchCCW) == LOW) 
  {
    dirStatus =CCW;
    count =0;
  }else if(digitalRead(switchCW) == LOW)
  {
   dirStatus  = CW;  
    count =0;   
  }
  if(digitalRead(switchSTOP) == LOW)
  {
    dirStatus  = STOP;
    delay(200);
  }
 if(dirStatus ==CCW){ 
   poleStep++; 
   count++;   
   if(count+correction_CCW <= stepVale)
   {
    driveStepper(poleStep);      
   }else{
      driveStepper(8);  
   }
  //full explannation at Arduino Course on Udemy.com see link above
 }else if(dirStatus ==CW){ 
   poleStep--; 
   count++;   
   if(count+correction_CW <=stepVale)
   {
    driveStepper(poleStep);      
   }else{
      driveStepper(8);  
   }   
 }else{
  driveStepper(8);   
 }
 if(poleStep>7){ 
   poleStep=0;
 } 
 if(poleStep<0){ 
   poleStep=7; 
 } 
 delay(speedFactor); 
  //Robojax.com Stepper Push button Any Angle STPB-4

}// loop


/*
 * @brief moves motor to specific angle 
 * @param "angle" is integer representing the angle
 * @return does not return anything
 * 
 * www.Robojax.com code Ap1il 19 2020 at 01:22 in Ajax, Ontario, Canada
 */
void driveStepper(int c)
{
    //Robojax.com Stepper Push button Any Angle STPB-4
     digitalWrite(Pin1, pole1[c]);  
     digitalWrite(Pin2, pole2[c]); 
     digitalWrite(Pin3, pole3[c]); 
     digitalWrite(Pin4, pole4[c]);
     if(c ==8)
     {
      digitalWrite(switchCW, HIGH); 
      digitalWrite(switchCCW, HIGH);               
     }
}//driveStepper ends here

None; your code already has a variable that keeps track of the direction ("dirStatus").

You'd have to revise this bit here:

if(digitalRead(switchCCW) == LOW) 
  {
    dirStatus =CCW;
    count =0;
  }else if(digitalRead(switchCW) == LOW)
  {
   dirStatus  = CW;  
    count =0;   
  }

You could do something like this instead:

if(digitalRead(switchCW) == LOW) 
  {
    if (dirStatus == CW) {
      dirStatus = CCW;
    }
    else {
      dirStatus = CW;
    }
    count =0;
  }

Neither your version nor my modification above allows for switch debouncing. I'd suggest including some way of debouncing your switch.

I'd also recommend reading up on the concept of a "finite state machine".

1 Like

without debouncing the direction may be random.

1 Like

I have managed to get the motor to work as it should, but I still have a bug that causes the motor to start rotating automatically after about 30 sec. If I then press the stop button, the program works randomly again.

int Pin1 = 8;//IN1 is connected to 8 
int Pin2 = 9;//IN2 is connected to 9  
int Pin3 = 10;//IN3 is connected to 10  
int Pin4 = 11;//IN4 is connected to 11 
int switchSTOP =2;//define input pin for STOP push button
int switchCW   =3;//define input pin for CW push button
int switchCCW  =4;//define input pin for CCW push button

bool direction_CW=true;

int speedFactor =1;//1=fastest, 2=slower or 3 more slower
long goToAngle = 360;

int correction_CW = 150;//watch video for details
int correction_CCW = 150;//watch video for details

const int CW =1;
const int CCW =2;
const int STOP =3;
int poleStep = 0; 
long stepVale =0;
const int SPR=64*64;

int pole1[] ={0,0,0,0, 0,1,1,1, 0};//pole1, 8 step values
int pole2[] ={0,0,0,1, 1,1,0,0, 0};//pole2, 8 step values
int pole3[] ={0,1,1,1, 0,0,0,0, 0};//pole3, 8 step values
int pole4[] ={1,1,0,0, 0,0,0,1, 0};//pole4, 8 step values

int count=0;
int  dirStatus = STOP;// stores direction status 3= stop (do not change)

void setup() 
{ 
  //Robojax.com Stepper Push button Any Angle STPB-4
  Serial.begin(9600);
  Serial.begin("Robojax Video for Stepper Motor STPB-2");  
 pinMode(Pin1, OUTPUT);//define pin for ULN2003 in1 
 pinMode(Pin2, OUTPUT);//define pin for ULN2003 in2   
 pinMode(Pin3, OUTPUT);//define pin for ULN2003 in3   
 pinMode(Pin4, OUTPUT);//define pin for ULN2003 in4   

 pinMode(switchSTOP,INPUT_PULLUP); 
 pinMode(switchCW,INPUT_PULLUP);
 pinMode(switchCCW,INPUT_PULLUP); 
 
} 
 void loop() 
{ 
    stepVale = (SPR * goToAngle)/360 ;
  //Robojax.com Stepper Push button Any Angle STPB-4
  if(digitalRead(switchCW) == LOW) 
  {
    if (dirStatus == CW) {
      dirStatus = CCW;
      direction_CW = false;
    }
    else {
      dirStatus = CW;
      direction_CW=true;
    }
    count =0;
    delay(200);
  }
  if(digitalRead(switchSTOP) == LOW)
  {
    dirStatus  = STOP;
    delay(200);
  }



 if(dirStatus ==CCW){ 
   poleStep++; 
   count++;   
   if(count+correction_CCW <= stepVale)
   {
    driveStepper(poleStep);      
   }else{
      driveStepper(8);  
   }
  //full explannation at Arduino Course on Udemy.com see link above
 }else if(dirStatus ==CW){ 
   poleStep--; 
   count++;   
   if(count+correction_CW <=stepVale)
   {
    driveStepper(poleStep);      
   }else{
      driveStepper(8);  
   }   
 }else{
  driveStepper(8);   
 }
 if(poleStep>7){ 
   poleStep=0;
 } 
 if(poleStep<0){ 
   poleStep=7; 
 } 
 delay(speedFactor); 
  //Robojax.com Stepper Push button Any Angle STPB-4

}// loop


/*
 * @brief moves motor to specific angle 
 * @param "angle" is integer representing the angle
 * @return does not return anything
 * 
 * www.Robojax.com code Ap1il 19 2020 at 01:22 in Ajax, Ontario, Canada
 */
void driveStepper(int c)
{
    //Robojax.com Stepper Push button Any Angle STPB-4
     digitalWrite(Pin1, pole1[c]);  
     digitalWrite(Pin2, pole2[c]); 
     digitalWrite(Pin3, pole3[c]); 
     digitalWrite(Pin4, pole4[c]);
     if(c ==8)
     {
      digitalWrite(switchCW, HIGH); 
      digitalWrite(switchCCW, HIGH);               
     }
}//driveStepper ends here


this code reliably detects a button press

// simple button processing

const byte butPin = A1;
byte       ledPin = 13;

byte butState;

enum { Off = HIGH, On = LOW };

// -----------------------------------------------------------------------------
void loop (void)
{
    byte but = digitalRead (butPin);

    if (butState != but)  {     // check that button state changed
        butState = but;
        delay (10);         // debounce

        if (LOW == but)     // button pressed
            digitalWrite (ledPin, ! digitalRead (ledPin));
    }
}

// -----------------------------------------------------------------------------
void setup (void)
{
    digitalWrite (ledPin, Off);
    pinMode      (ledPin, OUTPUT);

    pinMode     (butPin, INPUT_PULLUP);
    butState  = digitalRead (butPin);
}

comment

  • don't see where direction_CW is used
  • direction could be +/- 1 and used to in/decrement your polestep instead of have separate CW/CCW routines
  • could limit poleStep to 0-7 using the modulo operator, for example poleStep = (poleStep + direction) % 8;
  • could use an array for the pins, similar to your poleN variables, instead of separately writting to each pin

Well I'm almost there, if it weren't for the fact that the engine starts turning on its own after 30 seconds being not used... the CW and CCW works with 1 button...
anyone who can find that bug please?

That's not apparent from the code. It may be useful to have a look at your hardware setup. Could you post a schematic diagram and a clear photograph of how you've connected everything together?

As a button I tap the wires GND and 3 together :slight_smile:



int Pin1 = 8;//IN1 is connected to 8 
int Pin2 = 9;//IN2 is connected to 9  
int Pin3 = 10;//IN3 is connected to 10  
int Pin4 = 11;//IN4 is connected to 11 
int switchCWCCW   =3;//define input pin for CW push button


bool direction_CW=true;

int speedFactor =1;//1=fastest, 2=slower or 3 more slower
long goToAngle = 90;

int correction_CW = 150;//watch video for details
int correction_CCW = 150;//watch video for details

const int CW =1;
const int CCW =2;
const int STOP =3;
int poleStep = 0; 
long stepVale =0;
const int SPR=64*64;

int pole1[] ={0,0,0,0, 0,1,1,1, 0};//pole1, 8 step values
int pole2[] ={0,0,0,1, 1,1,0,0, 0};//pole2, 8 step values
int pole3[] ={0,1,1,1, 0,0,0,0, 0};//pole3, 8 step values
int pole4[] ={1,1,0,0, 0,0,0,1, 0};//pole4, 8 step values

int count=0;
int  dirStatus = STOP;// stores direction status 3= stop (do not change)

void setup() 
{ 
  //Robojax.com Stepper Push button Any Angle STPB-4
  Serial.begin(9600);
  Serial.begin("Robojax Video for Stepper Motor STPB-2");  
 pinMode(Pin1, OUTPUT);//define pin for ULN2003 in1 
 pinMode(Pin2, OUTPUT);//define pin for ULN2003 in2   
 pinMode(Pin3, OUTPUT);//define pin for ULN2003 in3   
 pinMode(Pin4, OUTPUT);//define pin for ULN2003 in4   

 pinMode(switchCWCCW,INPUT_PULLUP);
  
} 
 void loop() 
{ 
    stepVale = (SPR * goToAngle)/360 ;
  //Robojax.com Stepper Push button Any Angle STPB-4
  if(digitalRead(switchCWCCW) == LOW) 
  {
    if (dirStatus == CW) {
      dirStatus = CCW;
      direction_CW = false;
    }
    else {
      dirStatus = CW;
      direction_CW=true;
    }
    count =0;
    delay(200);
  }
  
 if(dirStatus ==CCW){ 
   poleStep++; 
   count++;   
   if(count+correction_CCW <= stepVale)
   {
    driveStepper(poleStep);      
   }else{
      driveStepper(8);  
   }
  
 }else if(dirStatus ==CW){ 
   poleStep--; 
   count++;   
   if(count+correction_CW <=stepVale)
   {
    driveStepper(poleStep);      
   }else{
      driveStepper(8);  
   }   
 }else{
  driveStepper(8);   
 }
 if(poleStep>7){ 
   poleStep=0;
 } 
 if(poleStep<0){ 
   poleStep=7; 
 } 
 delay(speedFactor); 
  
}// loop


void driveStepper(int c)
{
      digitalWrite(Pin1, pole1[c]);  
     digitalWrite(Pin2, pole2[c]); 
     digitalWrite(Pin3, pole3[c]); 
     digitalWrite(Pin4, pole4[c]);
     if(c ==8)
     {
      digitalWrite(switchCWCCW, HIGH);                   
     }
}//driveStepper ends here

Thanks gcjr in advance,
do you have this hardware? Normally I think you should have the same error with this program. I'm afraid it's not the hardware but a writing bug

Why are you writing to your switch pin?
Btw, this doesn't explain the odd behavior after 30 seconds. This may be something simple like a bad connection in your wiring somewhere. Those DuPont style connectors tend to dislodge kind of easily.

Also, please remember what both @gcjr and me said about debouncing. It's relevant. Please give the code @gcjr provided a try.

It's something i copied of robojax (youtube).
As i told, i'm just new in this..
I can't write it myself, just copy and paste..

the self-starting of the engine always starts after 30 seconds. It would be a coincidence that a wire always comes loose just on that moment?

I would like to try gcjr's code, but I don't know where to paste it/replace my part..

// -----------------------------------------------------------------------------
void loop (void)
{
    byte but = digitalRead (butPin);

    if (butState != but)  {     // check that button state changed
        butState = but;
        delay (10);         // debounce

        if (LOW == but)     // button pressed
            digitalWrite (ledPin, ! digitalRead (ledPin));
    }
}

// -----------------------------------------------------------------------------
void setup (void)
{
    digitalWrite (ledPin, Off);
    pinMode      (ledPin, OUTPUT);

    pinMode     (butPin, INPUT_PULLUP);
    butState  = digitalRead (butPin);
}

Then you'll have to learn. The copy-paste method will always get you stuck.

Start by going through the code you have and attempting to understand what each line does. Then start modifying specific bits to change the program's behavior and see if you can accurately predict the effects of each modification.

To start with, I'd use a simpler program; e.g. an example that just blinks an LED. Then move up in complexity as your understanding improves.

I understand this, learning it myself until I can write such programs is not easy. Been working on it for a few days now and cutting and pasting works. I find this interesting, but it is only for 1 project. Unfortunately, spending weeks learning how to do this is not an option and my efforts and purchases so far are wasted.
Still, thanks for your time so far

I understand. Well, Arduino is relatively user-friendly, but not quite as user-friendly as assembling an IKEA Billy cupboard. I hope you find the willpower to persevere, or otherwise the peace of mind to come to grips with your sunk investment. Good luck either way!

hihi, If a professional like you doesn't find the bug in the program, I guess it's not that easy after all :smiling_face:. That's already a reason why I won't delve into it further. I can still spend weeks on it without getting any results.

look this over
simplifies stepping
uses single button to sequence: stop, forward, stop, reverse

makes it easier to read/debug code

const byte PinStepper [] = { 8, 9, 10, 11 };

const byte switchSTOP =2;//define input pin for STOP push button
const byte switchCW   =3;//define input pin for CW push button
const byte switchCCW  =4;//define input pin for CCW push button

int speedFactor = 1;//1=fastest, 2=slower or 3 more slower

byte butState;
const int Npole = sizeof(PinStepper);

const byte pole [][8] = {
     { 0,0,0,0, 0,1,1,1 },
     { 0,0,0,1, 1,1,0,0 },
     { 0,1,1,1, 0,0,0,0 },
     { 1,1,0,0, 0,0,0,1 },
};

int      state; // stop, forward, stop, reverse
int      dir;   // 1/0/-1
unsigned pos;   // stepper sequence

// -----------------------------------------------------------------------------
void step (
    unsigned c)
{
    Serial.println (c);

    for (int n = 0; n < Npole; n++)
        digitalWrite (PinStepper [n], pole [n][c]);
}

// -----------------------------------------------------------------------------
void loop ()
{
    // handle button
    byte but = digitalRead(switchCW);
    if (butState != but) {
        butState = but;
        delay (20);

        if (LOW == but)  {
            switch (state) {
            case 0:
                state++;
                dir = 1;
                break;
    
            case 1:
                state++;
                dir = 0;
                break;
    
            case 2:
                state++;
                dir = -1;
                break;
            case 3:
                state = 0;
                dir = 0;
                break;
            }
    
            char s [90];
            sprintf (s, " state %d, dir %2d", state, dir);
            Serial.println (s);
        }
    }

    // step
    pos = (pos + dir) % 8;
    step (pos);
    delay (speedFactor);
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    for (int n = 0; n < Npole; n++)
        pinMode (PinStepper [n], OUTPUT);

    pinMode (switchSTOP, INPUT_PULLUP);
    pinMode (switchCW,   INPUT_PULLUP);
    pinMode (switchCCW,  INPUT_PULLUP);

    butState = digitalRead (switchCW);
}

Thank you! I'm trying to convert this to adjustable angle rotation and without a stop in between.