Search code examples
buttonarduinodebouncinglong-pressteensy

Button2 Library isPressed() method return inverted?


I am using two buttons on a teensy 4.1 MCU to control a robot. I want to add debouncing (and further stuff like longpress etc.) and decided on the library Button2 link to Repo, which is apparently quite popular for this type of tasks.

The buttons are wired as shown in the figure below. They use input pulldown resistors. Adding the option INPUT_PULLDOWN to the begin() method does not make a difference in the problem I encountered. Crude Wiring Diagram of MCU

I compiled a small program to test the library and ran it on the MCU. However, results are unexpected. The output of the method isPressed() seems to be inverted meaning the default value of an idle button is 1 instead of 0. Everything seems to be wired properly as using the digitalRead() returns the expected states of 1 when pressed and 0 when not pressed.

Adding to the problem is, that longpress and doubleclick work "wrong". In the Serial log you can see what I want to say: The button is pressed the first time and the library interprets this as a long press as it just sees the button was pressed from the start and then released.

Source code:

#include <Arduino.h>
#include <Button2.h>
#include <math.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN 26 ///< Pin for status led
#define LED_COUNT 7 ///< Numbers of pins on the status led
#define BRIGHTNESS 10 ///< Brightness of pixels (prevents the LED from being a laserbeam)
#define COLOR_RED ((255 << 16) + (0 << 8) + (0))
#define COLOR_ORANGE ((255 << 16) + (155 << 8) + (0))
#define COLOR_YELLOW ((255 << 16) + (255 << 8) + (0))
#define COLOR_GREEN ((0 << 16) + (255 << 8) + (0))
#define COLOR_CYAN ((0 << 16) + (255 << 8) + (255))
#define COLOR_BLUE ((0 << 16) + (0 << 8) + (255))
#define COLOR_PURPLE ((155 << 16) + (0 << 8) + (255))
#define COLOR_MAGENTA ((255 << 16) + (0 << 8) + (255))
#define COLOR_WHITE ((255 << 16) + (255 << 8) + (255))
#define COLOR_TUM_DARKBLUE ((0 << 16) + (82 << 8) + (147))
#define COLOR_TUM_BLUE ((0 << 16) + (101 << 8) + (189))
#define COLOR_TUM_ORANGE ((227 << 16) + (114 << 8) + (34))
#define COLOR_TUM_GREEN ((162 << 16) + (173 << 8) + (0))
#define COLOR_OFF 0

#define RECORD_BUTTON 5 ///< Pin for record button
#define PLAY_BUTTON 6 ///< Pin for play button
#define DEBOUNCE_TIME_MS 50 ///< Debounce time in ms

Button2 playButton;
Button2 recordButton;

Adafruit_NeoPixel statusLED(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void statusLEDShineFullColorCode(int color) {
    statusLED.fill(color);
    statusLED.setBrightness(BRIGHTNESS);
    statusLED.show();
}

void pressedHandler(Button2 &button){
  Serial.println("Button was pressed");
  statusLEDShineFullColorCode(COLOR_BLUE);
}

void longPressedHandler(Button2 &button){
  Serial.println("Button was pressed long");
  statusLEDShineFullColorCode(COLOR_GREEN);
}

void doubleClickedHandler(Button2 &button){
  Serial.println("Button clicked twice!");
  statusLEDShineFullColorCode(COLOR_RED);
}

void setupButtons(){
  playButton.begin(PLAY_BUTTON);
  recordButton.begin(RECORD_BUTTON);

  playButton.setDebounceTime(50);
  recordButton.setDebounceTime(50);

  playButton.setDoubleClickTime(500);
  recordButton.setDoubleClickTime(500);

  playButton.setLongClickTime(1000);
  recordButton.setLongClickTime(1000);

  playButton.setClickHandler(pressedHandler);
  recordButton.setClickHandler(pressedHandler);

  playButton.setDoubleClickHandler(doubleClickedHandler);
  recordButton.setDoubleClickHandler(doubleClickedHandler);

  playButton.setLongClickHandler(longPressedHandler);
  recordButton.setLongClickHandler(longPressedHandler);
}

void setup() {
  statusLED.begin();

  setupButtons();

  Serial.begin(115200);
}

void loop() {
  playButton.loop();
  recordButton.loop();
  statusLED.show();
  if(millis()%1000 == 0){
    Serial.println("Record button isPressed(): " + String(recordButton.isPressed()) + ", Play button isPressed(): " + String(playButton.isPressed()));
    Serial.println("Record button digitalRead(): " + String(digitalRead(RECORD_BUTTON)) + ", Play button digitalRead(): " + String(digitalRead(PLAY_BUTTON)));
  }
  
}

Serial Log (comments from me added after the fact indexed with #):

Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0 
Button was pressed long                                          # here the record button is pressed the first time, but Button2 thinks this was pressed until now
Record button isPressed(): 0, Play button isPressed(): 1         # record button still pressed isPressed() = 0, digitalRead() = 1 (WTF?)
Record button digitalRead(): 1, Play button digitalRead(): 0
Record button isPressed(): 0, Play button isPressed(): 1         # record button still pressed
Record button digitalRead(): 1, Play button digitalRead(): 0
Record button isPressed(): 0, Play button isPressed(): 1         # record button still pressed
Record button digitalRead(): 1, Play button digitalRead(): 0
Record button isPressed(): 0, Play button isPressed(): 1
Record button digitalRead(): 1, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Button was pressed long                                      # here I am pressing the other button
Record button isPressed(): 1, Play button isPressed(): 0
Record button digitalRead(): 0, Play button digitalRead(): 1
Record button isPressed(): 1, Play button isPressed(): 0
Record button digitalRead(): 0, Play button digitalRead(): 1
Record button isPressed(): 1, Play button isPressed(): 0
Record button digitalRead(): 0, Play button digitalRead(): 1
Record button isPressed(): 1, Play button isPressed(): 0
Record button digitalRead(): 0, Play button digitalRead(): 1
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0
Record button isPressed(): 1, Play button isPressed(): 1
Record button digitalRead(): 0, Play button digitalRead(): 0

The output I would expect is:

Record button isPressed(): 0, Play button isPressed(): 0
Record button digitalRead(): 0, Play button digitalRead(): 0

for idle and:

Record button isPressed(): 1, Play button isPressed(): 0
Record button digitalRead(): 1, Play button digitalRead(): 0

if the record button is pressed.


Solution

  • Thanks to Juraj, I found the "error" it was to set activeLow to false. I do not really get why it is defined that way but whatever it works now.

    The updated working code is:

    #include <Arduino.h>
    #include <Button2.h>
    #include <math.h>
    #include <Adafruit_NeoPixel.h>
    
    #define LED_PIN 26 ///< Pin for status led
    #define LED_COUNT 7 ///< Numbers of pins on the status led
    #define BRIGHTNESS 10 ///< Brightness of pixels (prevents the LED from being a laserbeam)
    #define COLOR_RED ((255 << 16) + (0 << 8) + (0))
    #define COLOR_ORANGE ((255 << 16) + (155 << 8) + (0))
    #define COLOR_YELLOW ((255 << 16) + (255 << 8) + (0))
    #define COLOR_GREEN ((0 << 16) + (255 << 8) + (0))
    #define COLOR_CYAN ((0 << 16) + (255 << 8) + (255))
    #define COLOR_BLUE ((0 << 16) + (0 << 8) + (255))
    #define COLOR_PURPLE ((155 << 16) + (0 << 8) + (255))
    #define COLOR_MAGENTA ((255 << 16) + (0 << 8) + (255))
    #define COLOR_WHITE ((255 << 16) + (255 << 8) + (255))
    #define COLOR_TUM_DARKBLUE ((0 << 16) + (82 << 8) + (147))
    #define COLOR_TUM_BLUE ((0 << 16) + (101 << 8) + (189))
    #define COLOR_TUM_ORANGE ((227 << 16) + (114 << 8) + (34))
    #define COLOR_TUM_GREEN ((162 << 16) + (173 << 8) + (0))
    #define COLOR_OFF 0
    
    #define RECORD_BUTTON 5 ///< Pin for record button
    #define PLAY_BUTTON 6 ///< Pin for play button
    #define DEBOUNCE_TIME_MS 50 ///< Debounce time in ms
    
    Button2 playButton;
    Button2 recordButton;
    
    Adafruit_NeoPixel statusLED(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
    
    void statusLEDShineFullColorCode(int color) {
        statusLED.fill(color);
        statusLED.setBrightness(BRIGHTNESS);
        statusLED.show();
    }
    
    void pressedHandler(Button2 &button){
      Serial.println("Button was pressed");
      statusLEDShineFullColorCode(COLOR_BLUE);
    }
    
    void longPressedHandler(Button2 &button){
      Serial.println("Button was pressed long");
      statusLEDShineFullColorCode(COLOR_GREEN);
    }
    
    void doubleClickedHandler(Button2 &button){
      Serial.println("Button clicked twice!");
      statusLEDShineFullColorCode(COLOR_RED);
    }
    
    void setupButtons(){
      playButton.begin(PLAY_BUTTON, INPUT_PULLDOWN, false); // changed this
      recordButton.begin(RECORD_BUTTON, INPUT_PULLDOWN, false); // changed this
    
      playButton.setDebounceTime(50);
      recordButton.setDebounceTime(50);
    
      playButton.setDoubleClickTime(500);
      recordButton.setDoubleClickTime(500);
    
      playButton.setLongClickTime(1000);
      recordButton.setLongClickTime(1000);
    
      playButton.setClickHandler(pressedHandler);
      recordButton.setClickHandler(pressedHandler);
    
      playButton.setDoubleClickHandler(doubleClickedHandler);
      recordButton.setDoubleClickHandler(doubleClickedHandler);
    
      playButton.setLongClickHandler(longPressedHandler);
      recordButton.setLongClickHandler(longPressedHandler);
    }
    
    void setup() {
      statusLED.begin();
    
      setupButtons();
    
      Serial.begin(115200);
    }
    
    void loop() {
      playButton.loop();
      recordButton.loop();
      statusLED.show();
      if(millis()%1000 == 0){
        Serial.println("Record button isPressed(): " + String(recordButton.isPressed()) + ", Play button isPressed(): " + String(playButton.isPressed()));
        Serial.println("Record button digitalRead(): " + String(digitalRead(RECORD_BUTTON)) + ", Play button digitalRead(): " + String(digitalRead(PLAY_BUTTON)));
      }
      
    }