Find the error - Code issue to drive CC motor with timer

Good afternoon Developers,
A little help from you as I'm having some trouble to drive a simple CC motor for a set time (3 second) with Arduino Nano and L298N driver.
I have a button with a pull-up resistor as input. I want:

  • When the button is pressed the motor rotate clockwise for 3 second and then stop.
  • When the button is released the motor rotate counterclockwise for 3 second and then stop.

I'm driving the Enable signal available on the L298N board to stop the motor.
My code is working correctly only if I remove the IF related to Button not pressed but of course like that I'm having only half of the functionality When I'm adding also the other part of the code (Button not pressed) the motor keeps rotating without exting from that IF.

What am I doing wrong?

My code is the following:

int motor1pin1 = 2;
int motor1pin2 = 3;
int isAtHomePin = 4; //detect the button
int Enablepin = 5; //pin to turn on and off the motor
unsigned long ritardo;
int isAtHome;
int Enable=0;

void setup() {
    pinMode(motor1pin1, OUTPUT);
    pinMode(motor1pin2, OUTPUT);
    pinMode(isAtHomePin, INPUT);
    pinMode (Enablepin, OUTPUT);
  digitalWrite(Enablepin, LOW);
    ritardo=millis();
  Serial.begin(9600);

}

void loop() {
  isAtHome = digitalRead(isAtHomePin);
  
    if (isAtHome==HIGH) //case button is pressed
       {
         delay (100); //antibouncing for the button
          Serial.println("Maggiordomo è uscito");
        digitalWrite(motor1pin1,LOW);
        digitalWrite(motor1pin2,HIGH);
        Enable =1;
        ritardo = millis();
        digitalWrite(Enablepin, HIGH);
        }

    if (isAtHome==LOW) //case button is not pressed 
       {
         delay(100); //antibouncing for the button
          Serial.println("button not pressed");
        digitalWrite(motor1pin1,HIGH);
        digitalWrite(motor1pin2,LOW);
         Enable =1;
        ritardo = millis();
        digitalWrite(Enablepin, HIGH);
        
        }
  
    if (Enable && (millis()-ritardo)>3000) 
         {
          digitalWrite(Enablepin,LOW);
          Serial.println("3 second passed");
           Enable =0;
         }
  
    }

Thank you for your help

Welcome to the forum

    pinMode(isAtHomePin, INPUT);

How is this pin wired ?

Is it always at a known state (HIGH or LOW) or is it floating at an unknown voltage, maybe HIGH or maybe LOW ?

Hello,

The problem is that you are looking at the actual state of the button, whereas you should be looking at a changing of state

Let me explain
Here you check if isAtHome==LOW. So as long as you don't press the button, this is true. This means that as long as you don't press the button, you set ritardo = millis() so the motor has no reason to stop since if (Enable && (millis()-ritardo)>3000) will keep being false.

What you need to do is detect when your button is going from HIGH to LOW, and LOW to HIGH.
You can do it easily with interrupt, or by remembering the previous state of the button

1 Like

Acting on levels, rather than acting in transitions.

Your logic will run a motor all the time, either one way or the other.

Add logic so it won't go CCW twice in a row. It would be like your enable, only like enabling CCW only after you've done CW, and enabling CW only after you've done CCW.

Or you could code classic "State Change Detection", also know as edge detection, and when you see the button go down, launch your timed CCW response, and when you see the button come up, launch the time CW response.

There's a state change detection example in the IDE and. A link to a competent article

https://docs.arduino.cc/built-in-examples/digital/StateChangeDetection/

HTH

a7

Hi, thank you for your reply,
"isAtHomePin" is connected to the temporary switch and it is wired to a 10Kohm Pull-up so that when temp switch not pressed the pin is logical 5V.
When (manually) pressed pin goes to GND

In that case, your logical inside the code itself isn't good

You wrote the opposit here:

That is good news, but take note of the advice in other replies regarding detecting the change of state

As an aside, you might like to consider using INPUT_PULLUP in the pinMode() for this pin to activate the built in pullup resistor. The project wiring will then be slightly simpler

yep, the PIN when temp. switch isn't pressed is Logical HIGH, but the comment is referring to the moment I press it, but you're right. I should change the comment.
Anyway I think all of your comments are valid anyway: "I should write the code focusing on the transition from HIGH to LOW and form LOW to HIGH to activate the motor rather then just detecting if the pin is LOW or HIGH.
So let me read the article @alto777 posted and I'll be right back with a fresh code.

You could also be interested in a library that would deal with the buttons for you:
https://docs.arduino.cc/libraries/button2/

Whether you use that idea or not, state change detection will reappear in many disguises, so is worth learning.

Meanwhile, my first idea is effective. I'll just post the one line I finally had to use. I added one variable direction which is used to see which direction got done last (-1 or 1 coding the clockwise and anticlockwise direction, and to keep that direction from being done again

  if (isAtHome == HIGH && direction != -1 && !Enable) //case button is pressed

So each if statement can only invoke motion if: the button is right, the direction is the way we didn't go last time and only if we haven't already properly invoked the timed motion for this button state.

a7

got it. Are you then setting "direction" inside each if statement?
Like

if (isAtHome == HIGH && direction != -1 && !Enable) //case button is pressed
       {
         delay (100); //antibouncing for the button
          Serial.println("Maggiordomo è uscito");
        digitalWrite(motor1pin1,LOW);
        digitalWrite(motor1pin2,HIGH);
        Enable =1;
direction = -1
        ritardo = millis();
        digitalWrite(Enablepin, HIGH);
        }

and then direction = 1 inside the other IF statement?

But adding direction I can't see how it can pop out from below statement (as is doing right now)

if (isAtHome==LOW) //case button is not pressed

You surely need to do it for both of your IF statement; ofc

However, looking at this, I'm not sure it will work the best way

Let's say you enter the IF, you set then direction = -1 and Enable = 1, as well as ritardo = millis().

Once the 3s passed, you'll set Enable = 0. Doing this will stop the motor.
But let's say you change the state of the button BEFORE the end of the 3sec, nothing will happen.

So the best is still to learn to deal with the state changing. You will have a lot of this in your future as a programmer

Word. Same with switch debouncing. Both problems are challenges with many explanations and quite a few ways to code up. Worth having struggled through, even if you punt for the erst of your life and use a library.

But...

Yes. Then it will "pop out" from the second. You got half of it, just do the same thing in the other if.

Is that what your test of the idea showed?

In my sketch, if you get off the button during the button down action, the button up action ensues immediately after the button down action ends. And vice-versa. As soon as the conditions are correct the corresponding if statement body executes: button state, motion direction and already doing not.

If you stay on the button, and the button down action finiches, it will be when you finally get off the button that the button up action is invoked.

a7

Sorry I wasn't clear enough. I didn't run the code, I made just a "simulation" in my head.
What I wanted to say is, as you now did, you'll have to wait the end of the actual action before being able to do the other

But if he wants to change directly, with your method he can't.

I should have been clearer thanks for the attention you gave to it

It's a nice nonblocking sketch and there is no doubt just getting the edges of the signal will allow better flexibility for the responses.

I went with

  • When the button is pressed the motor rotate clockwise for 3 second and then stop.
  • When the button is released the motor rotate counterclockwise for 3 second and then stop.

and the actual behaviour that emerges may make the OP rethink or enhance the description of the desired functionality.

It's a nice nonblocking sketch and there is no doubt just getting the edges of the signal will allow maximum flexibility for the responses.

a7

Ok, I tried the code adding variable "direction" as suggested.
When I push the button the motor turn CW for 3 seconds and then CCW for other 3 seconds before stopping so looks like is entering into the first IF statement:
if (isAtHome==HIGH && direction != -1 && !Enable)
and then into the second one:
if (isAtHome==LOW && direction != 1 && !Enable)

int motor1pin1 = 2;
int motor1pin2 = 3;
int isAtHomePin = 4;
int Enablepin = 5; //pin to turn on and off the motor
unsigned long ritardo;
int isAtHome;
int Enable=0;
int direction =0;

void setup() {
    pinMode(motor1pin1, OUTPUT);
    pinMode(motor1pin2, OUTPUT);
    pinMode(isAtHomePin, INPUT);
    pinMode (Enablepin, OUTPUT);
  digitalWrite(Enablepin, LOW);
    ritardo=millis();
  Serial.begin(9600);

}

void loop() {
  isAtHome = digitalRead(isAtHomePin);
  
    if (isAtHome==HIGH && direction != -1 && !Enable) //case button not pressed)
       {
         delay (100); //antibouncing per il pulsante
          Serial.println("Maggiordomo è uscito");
        digitalWrite(motor1pin1,LOW);
        digitalWrite(motor1pin2,HIGH);
        Enable =1;
         direction =-1;
        ritardo = millis();
        digitalWrite(Enablepin, HIGH);
        }

    if (isAtHome==LOW && direction != 1 && !Enable) //caso button pressed
       {
         delay(100); //antibouncing for the button
          Serial.println("Maggiordomo è a casa");
        digitalWrite(motor1pin1,HIGH);
        digitalWrite(motor1pin2,LOW);
         Enable =1;
         direction =1;
        ritardo = millis();
        digitalWrite(Enablepin, HIGH);
        
        }
  
    if (Enable && (millis()-ritardo)>3000) 
         {
          digitalWrite(Enablepin,LOW);
          Serial.println("Sono passati 3 secondi");
           Enable =0;
         }
  
    }

​​

​​

First of all, the real suggestion was to detect the edges my friend, not doing this
This is a work around. So I'll help you with this but you really should then try to do it with the detection of the edges

Here you want the motor to turn in a specific direction, let's say CCW. So you set direction = -1 in the IF statement right?

Here you want to turn in the other way, here it would be CW. So you need to set AND test for direction = 1 (or something else than -1)

You get it? :slight_smile:

I used the code in #17 and it functions correclty. I am in transit, so I can't look into

When I push the button the motor turn CW for 3 seconds and then CCW for other 3 seconds before stopping so looks like is entering into the first IF statement:

BUt that's what is sipposed to happen. Hold the button down for the entire three seconds; no motion will ensue until you get off the button.

If you get off the button during the button down motion, the button up motion will happen immediatley the other motion is done.

I had this essnetial additions:


  if (isAtHome == HIGH && direction != -1 && !Enable) //case button is pressed
  {

// ...

    direction = -1;

  }

  if (isAtHome == LOW && direction != 1 && !Enable) //case button is not pressed
  {

//...

    direction = 1;

  }

So the question is, what should happen if you press and right away release the button? Only the button down? And then what? No motion until the button goes down and up (again)?

The problem is underspecified. Solving it before you decide what all the possible inputs can look like is not a good use of time.

a7

Naturally I think you could do worse than understand the code in this post from the near past:

The thread is worth time and will place that post in context.

However you do the buttons the way we all want you to, you will have to decide what to do with the edges.

It seems like you are solving a specific problem, perhaps describing it in some detail would let us help better, fun as it is to speculate.

a7

ok, thank you for your time.
Let me try to clear out any doubt with the signal chart.

  • When the button is pressed the motor rotate clockwise for 3 second and then stop.
  • When the button is released the motor rotate counterclockwise for 3 second and then stop.