detecting falling and rising edges

Hello everybody,

For checking a falling edge on pin 12 and rising edge on pin 11 I wrote this small program. The program " buttonstate.ino" is also included as attachment.

int buttonStateRising=1;
int buttonRisingEdge = 1;
int lastButtonStateRising = 1;
int buttonStateFalling=0;
int buttonFallingEdge = 1;
int lastButtonStateFalling = 0;

void setup(){
Serial.begin(9600);
digitalWrite(11,HIGH);//activation of the pull-up resistor of pin 11
digitalWrite(12,HIGH);//activation of the pull-up resistor of pin 12
}

void loop(){

//Here starts the code for detecting a rising edge on pin 11
buttonStateRising = digitalRead(11);
if (buttonStateRising != lastButtonStateRising) {
if (buttonStateRising == LOW) {
buttonRisingEdge = 0;
Serial.println(‚ÄúThere was a rising edge on pin 11‚ÄĚ);
}
}
else{
buttonRisingEdge = 1;
Serial.println(‚ÄúThere was no rising edge on pin 11‚ÄĚ);
}
lastButtonStateRising = buttonStateRising;

//Here starts the code for detecting a fallng edge on pin 12
buttonStateFalling = digitalRead(12);
if (buttonStateFalling != lastButtonStateFalling) {
if (buttonStateFalling == HIGH) {
buttonFallingEdge = 1;
Serial.println(‚ÄúThere was a falling edge on pin 12‚ÄĚ);
}
}
else{
buttonFallingEdge = 0;
Serial.println(‚ÄúThere was no falling edge on pin 12‚ÄĚ);
}
lastButtonStateFalling = buttonStateFalling;

}

It seems to work but when I integrate it in a bigger program (used as a library) the detection doesn’t detect all the edges.

Anyone an idea what is wrong?

Thanks in advance,
Bart

buttonstate.ino (1.28 KB)

use inteerupt code to detect the rising & falling edge

http://arduino.cc/en/Reference/AttachInterrupt example code avilable here.

pinMode(11, INPUT_PULLUP); //Enable pullup
pinMode(12, INPUT_PULLUP); //Enable pullup

Also, you’re sharing the lastButtonStateRising/lastButtonStateFalling across both pins?
It looks as though if one did update, it’ll reset the other.

Separate the pin check. Also you can simplify the code with a little refactoring and pointers:

int buttonRisingEdgeA = 0;        
int lastButtonStateA = 0;   
int buttonRisingEdgeB = 0;        
int lastButtonStateB = 0;

bool PinStateChanged(int pin, int *lastButtonState, int *buttonRisingEdge)
{
 //Get pin state
 int buttonState = digitalRead(pin);
 
 //Here starts the code for detecting an edge
 if (buttonState != *lastButtonState) {
 if (buttonState == LOW) {
 *buttonRisingEdge = 0;
 } else {
 *buttonRisingEdge = 1;
 }
 *lastButtonState = buttonState;
 return true;
 }
 
 return false;
}

void setup() {

  //Configure pins
  pinMode(11, INPUT_PULLUP); //Enable pullup
  pinMode(12, INPUT_PULLUP); //Enable pullup

  //Set initial states
  lastButtonStateA = digitalRead(11);
  buttonRisingEdgeA = lastButtonStateA;

  lastButtonStateB = digitalRead(12);
  buttonRisingEdgeB = lastButtonStateB;

}

void loop() {

  if (PinStateChanged(11, &lastButtonStateA, &buttonRisingEdgeA)) {
    //Pin 11 state changed.
    //buttonRisingEdgeA says how: 0 == falling, 1 == Rising
    if (buttonRisingEdgeA == 0) {
      Serial.println("There was a falling edge on pin 11");
    } else {
      Serial.println("There was a rising edge on pin 11");
    }
  }

  if (PinStateChanged(12, &lastButtonStateB, &buttonRisingEdgeB)) {
    //Pin 12 state changed.
    //buttonRisingEdgeB says how: 0 == falling, 1 == Rising
    if (buttonRisingEdgeB == 0) {
      Serial.println("There was a falling edge on pin 12");
    } else {
      Serial.println("There was a rising edge on pin 12");
    }
  }

}

If you’re using interrupts, it’s a bit easier, for example:

attachInterrupt(BtnPinInterrupt, someMethod, FALLING);

These two macros are very handy for edge detection:

//macro for detection af rasing edge
#define RE(signal, state) (state=(state<<1)|(signal&1)&3)==1

//macro for detection af falling edge
#define FE(signal, state) (state=(state<<1)|(signal&1)&3)==2

You need to use them together with a variable dedicated to that signal:

const int btn = 11; //btn pin
int btnState;
...
if(RE(digitalRead(btn), btnState)){
  //code here gets executed on raising edge of btn
}
1 Like

You may also need debounce…

int buttonStateRising = 1;
int lastButtonStateRising = 1;
int buttonStateFalling = 1;
int lastButtonStateFalling = 1;
unsigned long millisPrevious;
byte debounceInterval = 50; // milliseconds

void setup() {
  Serial.begin(9600);
  pinMode(11, INPUT_PULLUP); //activation of the pull-up resistor of pin 11
  pinMode(12, INPUT_PULLUP); //activation of the pull-up resistor of pin 12
}

void loop() {

  //Here starts the code for detecting a rising edge on pin 11
  buttonStateRising = digitalRead(11);
  if ((buttonStateRising == HIGH) && (lastButtonStateRising == LOW)) {
    if (millis() - millisPrevious >= debounceInterval) {  // if debounce interval expired
      Serial.println("There was a rising edge on pin 11");
    }
    millisPrevious = millis();
  }
  lastButtonStateRising = buttonStateRising;

  //Here starts the code for detecting a fallng edge on pin 12
  buttonStateFalling = digitalRead(12);
  if ((buttonStateFalling == LOW) && (lastButtonStateFalling == HIGH)) {
    if (millis() - millisPrevious >= debounceInterval) {  // if debounce interval expired
      Serial.println("There was a falling edge on pin 12");
    }
    millisPrevious = millis();
  }
  lastButtonStateFalling = buttonStateFalling;
}

dlloyd: You may also need debounce...

  //Here starts the code for detecting a rising edge on pin 11
  buttonStateRising = digitalRead(11);
  if ((buttonStateRising == HIGH) && (lastButtonStateRising == LOW)) {
    if (millis() - millisPrevious >= debounceInterval) {  // if debounce interval expired
      Serial.println("There was a rising edge on pin 11");
    }
    millisPrevious = millis();
  }
  lastButtonStateRising = buttonStateRising;

}

That will not debounce and will fire twice: millisPrevious is already outdated, on first iteration.

Try this, it will fire and set millisPrevious on the first 'valid' state, then reset on timeout. This will also code with a perfect state change (where a bounce is never discerned)

  //Here starts the code for detecting a rising edge on pin 11
  buttonStateRising = digitalRead(11);
  if ((buttonStateRising == HIGH) && (lastButtonStateRising == LOW)) {
    if (millisPrevious == 0) {
      Serial.println("There was a rising edge on pin 11");
      millisPrevious = millis();
    }
  }

  if (millis() - debounceInterval >= millisPrevious) {  // if debounce interval expired
    millisPrevious = 0;
  }

  lastButtonStateRising = buttonStateRising;

}

Whoops - a bug!

Change:

if (millis() - debounceInterval >= millisPrevious) {  // if debounce interval expired
    millisPrevious = 0;
}

To:

if (millisPrevious > 0 && millis() - debounceInterval >= millisPrevious) {  // if debounce interval expired
    millisPrevious = 0;
}

None of the previous solution worked properly for me with debouncing >:( , so I ended up with something like this:

#include "Wire.h"

#define NB_METER 2
int pins[]={11,10};

#define DEBOUNCE_DELAY 120
char meterTopic[]="meter/0";
int buttonStateFalling[NB_METER];
int lastButtonStateFalling[NB_METER];
unsigned long millisPrevious[NB_METER];

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

  for (int i=0; i < NB_METER; i++) {
    pinMode(pins[i], INPUT_PULLUP);
    buttonStateFalling[i]=1;
    lastButtonStateFalling[i]=1;
  }
  
  Serial.println("Started");
}

void loop() {
  unsigned long now=millis();
  for(int i=0 ; i < NB_METER ; i++) {
    buttonStateFalling[i] = digitalRead(pins[i]);
    if ((buttonStateFalling[i] == HIGH) && (lastButtonStateFalling[i] == LOW)) {
      millisPrevious[i] = now;
    } else if ((buttonStateFalling[i] == LOW) && (lastButtonStateFalling[i] == HIGH) && (now - millisPrevious[i] > DEBOUNCE_DELAY)) {
        meterTopic[6]='1'+i;
        Serial.println(meterTopic);
    }
    lastButtonStateFalling[i] = buttonStateFalling[i];
  }
}

Bonus: the code is more generic, you can have 1 or several sensors just by changing NB_METER and pins.