Edge detection of momentary buttons

Hi Everyone,

First post here! Working on a little DIY project involving a motor that is controlled by a pot and a switch. I'm using a momentary switch to reverse the direction of the motor. At first, reversing the direction only worked when I was keeping the button pressed. I read tutorials and instructions from the site and so I learned about edge detection. I've been trying to implement it for my situation but I've run into a little trouble - can't get it to work.

I'm just starting up with electronics so your input would be much appreciated!

My code is the following:

int enablePin = 11;
int in1Pin = 10;
int in2Pin = 9;
const int switchPin = 7;
int potPin = 0;

int buttonState = 0;
int lastButtonState = 0;

void setup()
{
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
}

void loop()
{
  int speed = analogRead(potPin) / 4;
  boolean reverse = digitalRead(switchPin);
  setMotor(speed, reverse);


  //Edge detection for mommentary switch
  
   buttonState = digitalRead(switchPin);
   lastButtonState = buttonState;
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      digitalWrite(in1Pin, ! reverse);
        } else {
    digitalWrite(in2Pin, reverse);
  }
      
    }

}

void setMotor(int speed, boolean reverse)
{
  analogWrite(enablePin, speed);
  digitalWrite(in1Pin, ! reverse);
  digitalWrite(in2Pin, reverse);
  

  }

Looking forward to reading your replies and hope I will learn something new! :) Thanks!

   buttonState = digitalRead(switchPin);
   lastButtonState = buttonState;
  if (buttonState != lastButtonState) {

That is NOT the way the state change detection example did it.

Of course the if statement will always evaluate to false if you expect two variables, that you have just set to be equal, to be different.

PaulS:   buttonState = digitalRead(switchPin);   lastButtonState = buttonState;   if (buttonState != lastButtonState) {

That is NOT the way the state change detection example did it.

Of course the if statement will always evaluate to false if you expect two variables, that you have just set to be equal, to be different.

Hi PaulS,

Thank you for your prompt reply. I'm quite a beginner so I'm just figuring my way around. Could you please be a bit more specific?

You need to read the current state. Then, you need to compare the current state to the previous state. THEN, you need to set the previous state to the current state.

Look at the state change detection example again. Notice the order of the steps. They are correct. Yours are not.

You set the two states equal before comparing them, so you know they are always equal at that point in the code.

previous state should be previous state. You only update it after you've finished processing, as the last action.

MarkT: You set the two states equal before comparing them, so you know they are always equal at that point in the code.

previous state should be previous state. You only update it after you've finished processing, as the last action.

PaulS: You need to read the current state. Then, you need to compare the current state to the previous state. THEN, you need to set the previous state to the current state.

Look at the state change detection example again. Notice the order of the steps. They are correct. Yours are not.

Thanks for the replies PaulS and MarkT, appreciated.

I think I got the order right but it's still not working. Could the code be in the wrong part of the sketch?

int enablePin = 11;
int in1Pin = 10;
int in2Pin = 9;
const int switchPin = 7;
int potPin = 0;

int buttonState = 0;
int lastButtonState = 0;

void setup()
{
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
}

void loop()
{
  int speed = analogRead(potPin) / 4;
  boolean reverse = digitalRead(switchPin);
  setMotor(speed, reverse);


  //Edge detection for mommentary switch
  
   buttonState = digitalRead(switchPin);
   
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      digitalWrite(in1Pin, ! reverse);
        } else {
    digitalWrite(in2Pin, reverse);
  }
      
    }

    lastButtonState = buttonState;

}

void setMotor(int speed, boolean reverse)
{
  analogWrite(enablePin, speed);
  digitalWrite(in1Pin, ! reverse);
  digitalWrite(in2Pin, reverse);
  

  }
    if (buttonState == HIGH) {
      digitalWrite(in1Pin, ! reverse);
        } else {
    digitalWrite(in2Pin, reverse);
  }

This section of code seriously needs some comments.

With the internal pullup resistors, LOW means pressed.

On every pass through loop(), you set the state of both (poorly named) output pins. Why on earth are you calling output pins inPin anything? Why are you doing that?

PaulS:     if (buttonState == HIGH) {       digitalWrite(in1Pin, ! reverse);         } else {     digitalWrite(in2Pin, reverse);   }

This section of code seriously needs some comments.

With the internal pullup resistors, LOW means pressed.

On every pass through loop(), you set the state of both (poorly named) output pins. Why on earth are you calling output pins inPin anything? Why are you doing that?

They are called that because some of the code is part of an online example of how to connect motors in this situation. The outputs from the Arduino are going to the 2 in pins of an L293D ic.

Also, I'm sorry, I don't understand how this is helpful to figuring out a solution for my problem. I'm just trying to learn..

castravete: I'm using a momentary switch to reverse the direction of the motor. At first, reversing the direction only worked when I was keeping the button pressed.

It sounds like you want to reverse the direction each time the button is pressed, not go one way while the button is pressed and the other way while the button is not pressed. To do that you need to use File->Examples->01.Digital->StateChangeDetection which counts up each time the button is pressed. Since you only have two states (forward and backward) you can toggle a value rather than count.

// this constant won't change:
const int  BUTTON_PIN = 2;    // the pin that the pushbutton is attached to
// Variables will change:
boolean MotorForward = true;
boolean LastButtonState = false;     // previous state of the button
void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  // initialize the button pin as a input:
  pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
  // read the pushbutton input pin:
  boolean buttonState = digitalRead(BUTTON_PIN);
  // compare the buttonState to its previous state
  if (buttonState != LastButtonState) {
    // save the current state as the last state,
    //for next time through the loop
    LastButtonState = buttonState;
    // If the state has changed to 'Pressed', toggle the direction
    if (buttonState == LOW) { // Pushing button grounds pin
      MotorForward = !MotorForward;
      // Debug output:
      Serial.print("Pressed, direction=");
      Serial.println(MotorForward ? "Forward" : "Reverse");
      /*
           HERE IS WHERE YOU WOULD SET THE MOTOR SPEED AND DIRECTION
      */
    } else {
      // If the state has change to 'Released' do nothing
      // Debug output:
      Serial.println("Released");
    }
  }
}

Here's a simple edge detect + 50 mS debounce: :)

const byte btn = 4; // button connected between pin 4 and GND
uint32_t timeStart;
byte dbTime = 50;
bool btnState = false;

void setup(){
  pinMode(btn,INPUT_PULLUP),
         (13,OUTPUT);
}
void loop(){
  if(digitalRead(btn) != btnState)
    timeStart = millis();
  if(millis() - timeStart > dbTime)
    btnState = !btnState;
  digitalWrite(13,btnState);  
}

My favorite way of debouncing: Ignore state changes that happen within 5 milliseconds of a legit state change. This will make each state last at least 5 ms.

// this constant won't change:
const int  BUTTON_PIN = 2;    // the pin that the pushbutton is attached to
const unsigned long BUTTON_DEBOUNCE_TIME = 5;

// Variables will change:
boolean MotorForward = true;
boolean LastButtonState = false;     // previous state of the button
unsigned long ButtonChangeTime;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);

  // initialize the button pin as a input:
  pinMode(BUTTON_PIN, INPUT_PULLUP);
}


void loop() {
  // read the pushbutton input pin:
  boolean buttonState = digitalRead(BUTTON_PIN);
  unsigned long currentTime = millis();

  // compare the buttonState to its previous state
  if (buttonState != LastButtonState &&
      currentTime - ButtonChangeTime > BUTTON_DEBOUNCE_TIME) {
    // save the current state as the last state,
    //for next time through the loop
    LastButtonState = buttonState;
    ButtonChangeTime = currentTime;

    // If the state has changed to 'Pressed', toggle the direction
    if (buttonState == LOW) { // Pushing button grounds pin
      MotorForward = !MotorForward;
      // Debug output:
      Serial.print("Pressed, direction=");
      Serial.println(MotorForward ? "Forward" : "Reverse");

      /*
           HERE IS WHERE YOU WOULD SET THE MOTOR SPEED AND DIRECTION
      */

    } else {
      // If the state has change to 'Released' do nothing
      // Debug output:
      Serial.println("Released");
    }
  }
}

Also, I'm sorry, I don't understand how this is helpful to figuring out a solution for my problem. I'm just trying to learn..

Part of that is learning how to ask questions. Part of that is being able to explain what the code actually does. Part of that is being able to explain what you were trying to do when you wrote the code.

Learning to program is NOT a matter of finding code that someone else wrote.