For a aspberry pi project I have buttons connected to GPIO and I want to take different actions depending on how long a button has been pressed. The following python code (extract) is working as expected:
on_button2(channel):
t1 = time.time()
# Wait for button release
while GPIO.input(channel) == 0:
pass
duration = time.time() - t1
print "duration: %f" % (duration)
if duration > 0.75:
mpd_client.previous()
else:
mpd_client.next()
GPIO.add_event_detect(BUTTON2_PIN, GPIO.FALLING, callback=on_button2, bouncetime=700);
I would like to convert this into a C program (don't ask why, I really don't like python and I'm much more familiar with C, so I'd like to do it in C)
Trying to convert this to C with wiringPi, I came up with this, but it is not working as expected:
unsigned long btn2_t0;
static void on_button_2_pressed() {
unsigned long duration, t1;
int level;
level = digitalRead(BUTTON_2_PIN);
// Debounce button
t1 = millis();
if (t1 - btn2_t0 < 700) {
return;
}
btn2_t0 = t1;
// Wait for button being released
while (digitalRead(BUTTON_2_PIN) == LOW) {
delay(100);
}
duration = millis() - t1;
if (duration > 5000) {
printf("Self destruction sequence initiated!\n");
}
else if (duration > 700) {
player_previous();
}
else {
player_next();
}
}
int main() {
// Setup WiringPi Lib
wiringPiSetupGpio();
pinMode(BUTTON_2_PIN, INPUT);
// Register callbacks on button press
wiringPiISR(BUTTON_2_PIN, INT_EDGE_FALLING, on_button_2_pressed);
for (;;) {
delay(500);
}
return 0;
}
It seems that the loop that should wait for button release is not being executed or that the while-condition is always true, and thus, duration always is zero.
Is the digitalRead(BUTTON_2_PIN)
function equivalent to the GPIO.input(channel)
in the python code at all?
If somebody could point me in the right direction on how to detect button press (software-debounced) and measure the duration of the button press in C.
Thanks a lot.
EDIT: Working solution
After playing around a lot and with the help of Francesco Boi I came around with a working solution, although I do not really understand why the compare logic with HIGH / LOW is swapped compared to the python code (I thought that the button press will cause the pin to FALL to LOW and releasing it would RAISE it to HIGH ...)
static void on_button_2_pressed() {
unsigned long duration;
static unsigned long button_pressed_timestamp;
int level = digitalRead(BUTTON_2_PIN);
if (level == HIGH) { // Why HIGH ?!?
button_pressed_timestamp = millis();
}
else {
duration = millis() - button_pressed_timestamp;
button_pressed_timestamp = millis();
if (duration < 100) {
// debounce...
return;
}
else if (duration < 700) {
syslog(LOG_NOTICE, ">> NEXT\n");
}
else if (duration < 3000) {
syslog(LOG_NOTICE, "<< PREV\n");
}
else {
syslog(LOG_NOTICE, "!! REBOOT\n");
}
}
}
int main() {
...
wiringPiISR(BUTTON_2_PIN, INT_EDGE_BOTH, on_button_2_pressed);
...
}