I would like to take different actions with a long vs. a short button press and I'm facing the problem that my input always reads a short button press on init. I have a function that looks like:
enum input button_get(void) {
#define BTN_LONGPRESS 500
static int presscycles = 0; // count the number of iterations the button has been pushed for
static int released = 0; // has the button been released?
static int pushed = 0; // keep track if the button has ever been pushed
if (digitalRead(BUTTON)) {
pushed = 1;
released = 0;
presscycles++;
} else {
if (pushed == 1)
released = 1; //only set released to 1 if the button was pushed at least once
}
if ( released == 1 &&
presscycles >= BTN_LONGPRESS ) {
//long press
released = 0;
presscycles = 0;
Serial.print("IN_REFILL\n");
delay(3000);
return IN_REFILL;
} else if ( released == 1 &&
presscycles > 0 &&
presscycles < BTN_LONGPRESS ) {
//short press
released = 0;
presscycles = 0;
Serial.print("IN_CLEAN\n");
delay(3000);
return IN_CLEAN;
} else {
return IN_NONE;
}
and for some reason, the pushed
(and hence also the released
flag) are always set to1
after a reset, why is this and how can I prevent that from happening?
I'm using the ESPRESSIF FREENOVE ESP32 WROVER
From your code, I suspect you are calling button_get
from the main loop
:
void setup() {
// setup code
}
void loop() {
// code
enum input = button_get();
// do_something(input);
}
Your timing math in button_get
assumes that button_get
(and thus the main loop) is called at a 1ms period (1000 loops / second).
As written, the main loop function will run as fast as it can. Much much faster than the assumed 1000 loops / second https://forum.arduino.cc/t/cycles-per-second-in-the-loop/61382/3. This causes button_get
and your timing math to not be accurate to the real time (i.e. your press_cycles
variable increments much faster than you are expecting).
You can slow down the main loop so that your timing math is based on a 1ms period (1000 loops / second) by putting a 1ms delay in the main loop (or you could also put it in button_get
, but it may be better to leave it in the main loop for organization reasons).
void setup() {
// setup code
}
void loop() {
delay(1); // added delay for timing math
// code
enum input = button_get();
// do_something(input);
}
This should fix the timing issue you are seeing!
While this solution is convenient, it has the downside of slowing the code for the timing math, and is not necessarily accurate.
If you would like the rest of your program to run as fast as possible, you can remove the 1 ms delay, and do your timing math with the millis()
function.
You can instead calculate elapsed time by using something like:
// button pressed
int startTime = millis();
// button released
int endTime = millis();
int deltaTime = endTime - startTime;
if (deltaTime >= BTN_LONGPRESS) {
// timing code
This is also likely more accurate timing wise, because delaying 1ms in the main is really like a 1ms + buffer delay because of the time it takes to execute your code and run the chip etc.