I am trying to use (someone elses) code on a Raspberry Pico that is supposed to deal with multiple buttons, and checks wether the buttons were short pressed or long pressed.
The sketch is simple:
#include "ButtonEvents.h"
// define event names for the key events
typedef enum {EVT_NOCHANGE, EVT_PA0_BTNUP, EVT_PA0_LONGPRESS, EVT_PA1_BTNUP, EVT_PA1_LONGPRESS, EVT_PC14_BTNUP, EVT_PC14_LONGPRESS, EVT_PC15_BTNUP, EVT_PC15_LONGPRESS,
EVT_PB11_BTNUP, EVT_PB11_LONGPRESS, EVT_PA15_BTNUP, EVT_PA15_LONGPRESS, EVT_PA4_BTNUP, EVT_PA4_LONGPRESS, EVT_PB4_BTNUP, EVT_PB4_LONGPRESS , EVT_PB5_BTNUP, EVT_PB5_LONGPRESS } keyEvents;
ButtonEvents b = ButtonEvents(EVT_NOCHANGE);
#define BTN 13
void setup() {
while (!Serial) {
}
Serial.begin(115200);
Serial.println("Starting");
b.add(BTN, EVT_PA1_BTNUP, EVT_PA1_LONGPRESS);
}
void loop() {
int event = b.getButtonEvent();
Serial.printf("Event = %i\n", event);
}
Notice that I have added only one button here for test purposes.
The include file (ButtonEvents.h) is a bit more complex:
class ButtonEvents {
private:
typedef enum {STATE_UP, STATE_DOWN, STATE_LONGPRESSED} transitionStates;
struct Button {
Button* next;
byte pin;
byte event_button_up;
byte event_long_press;
// debounce
byte stateHistory;
bool debouncedButtonState;
// transition handling - button_up, long_press
transitionStates transitionState;
int_fast32_t buttonPressedDuration;
};
Button* next = NULL;
int noChangeEvent = 0;
int_fast32_t nextButtonPoll = 0;
int debounce(Button* b) {
int buttonPosition = digitalRead(b->pin);
b->stateHistory = ((b->stateHistory<<1) | buttonPosition) & 0x0f;
if (b->stateHistory == 0x0) {b->debouncedButtonState = true;};
if (b->stateHistory == 0xf) {b->debouncedButtonState = false;};
return b->debouncedButtonState;
}
int getButtonEvent(Button* b) {
bool btn = debounce(b);
int result = noChangeEvent;
switch (b->transitionState) {
case STATE_UP:
if (btn) {
b->transitionState = STATE_DOWN;
b->buttonPressedDuration = millis() + 1000;
}
break;
case STATE_DOWN:
if (!btn) {
b->transitionState = STATE_UP;
result = b->event_button_up;
}
if (millis() > b->buttonPressedDuration) {
b->transitionState = STATE_LONGPRESSED;
result = b->event_long_press;
}
break;
case STATE_LONGPRESSED:
if (!btn) {
b->transitionState = STATE_UP;
}
break;
default:
b->transitionState = STATE_UP;
}
return result;
}
public:
ButtonEvents(int noChange) {
noChangeEvent = noChange;
};
void add(uint8_t pinNo, int evt_button_up, int evt_long_press) {
pinMode( pinNo, INPUT_PULLUP);
// initialise the button structure
Button* b = (Button*) malloc(sizeof(struct Button));
//b = {next, pinNo, evt_button_up, evt_long_press, 0, false, STATE_UP, 0};
b->next = next;
b->pin = pinNo;
b->event_button_up = evt_button_up;
b->event_long_press = evt_long_press;
b->stateHistory = 0;
b->debouncedButtonState = false;
b->transitionState = STATE_UP;
b->buttonPressedDuration = 0;
// add it to the head of the chain
next = b;
};
// call this often in the main loop.
int getButtonEvent()
{
// poll the button inputs no closer than every 10 ms
int_fast32_t currentTime = millis();
if (currentTime >= nextButtonPoll) {
nextButtonPoll = currentTime + 10;
Button* b = next;
while(b) { //scan down the linked list
int event = getButtonEvent(b);
if (event != noChangeEvent) {
Serial.println("New event");
return event;
}
b = b->next;
}
}
return noChangeEvent;
}
};
The code loads on the Pico without problems, but however short or long I press the button attached to GPIO 13, nothing is returned from the GetButtonEvent function.
However, when I use the simple Button example, the button works, and makes my onboard LED light up when I press the button.
It has to be said that this code was originally written for a Blue Pill (STMF103C8T6), but I see no reason why it should not work on a Pico as well.
Or am I having problems with timing issues here ?
Anyhow, any help would be greatly appreciated.