From c3dcc2925e32d6d949d42a5bcff7e657fa0a5596 Mon Sep 17 00:00:00 2001 From: Jim Parziale Date: Sun, 3 Apr 2022 12:45:47 -0400 Subject: [PATCH] Added buttons4 to show button debouncing. --- examples/Makefile | 2 +- examples/buttons4.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++ wiringPi/wiringPi.h | 2 + 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 examples/buttons4.c diff --git a/examples/Makefile b/examples/Makefile index 679b707..b7847e8 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -40,7 +40,7 @@ LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt SRC = \ blink12.c blink12drcs.c blink6drcs.c blink8.c blink8-drcn.c blink.c blink-thread.c \ - buttons.c buttons2.c buttons3.c \ + buttons.c buttons2.c buttons3.c buttons4.c \ clock.c \ delayTest.c \ ds1302.c \ diff --git a/examples/buttons4.c b/examples/buttons4.c new file mode 100644 index 0000000..cf20c98 --- /dev/null +++ b/examples/buttons4.c @@ -0,0 +1,197 @@ +/* + * buttons4.c: + * Multiple button handling with debounce. + * + *********************************************************************** + * This file is part of wiringPi: + * https://github.com/nuncio-bitis/WiringPi + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + *by the Free Software Foundation, either version 3 of the License, or (at your + *option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +//********************************************************************************************************************** + +// Define the GPIOs (BCM) that buttons are attached to. +// Button1, Button2, ... , ButtonN-1 +static const int buttonGpios[] = { 26, 16, 20, 21 }; + +// Button flags: 1 = button was pressed. +// @NOTE The size of this array must match the number of GPIOs specified in buttonGpios above +static int buttons[4]; + +static const int nButtons = (sizeof (buttonGpios) / sizeof (int)); + +// Debounce time in mS +#define DEBOUNCE_TIME 50 + +static int terminate_process = 0; + +//********************************************************************************************************************** + +static void Signal_handler(int sig); + +//********************************************************************************************************************** + +/* debounce + * Thread to monitor button GPIOs and debounce them. + */ +static void *debounce (UNUSED void *arg) +{ + int masks[nButtons]; + int button_times[nButtons]; + + // Set the GPIOs as inputs + // Also set up the gpio bank masks for each button + for (int i = 0; i < nButtons; ++i) + { + pinMode (buttonGpios[i], INPUT); + pullUpDnControl (buttonGpios[i], PUD_UP); + + // Set up GPIO masks for the GPIO bank + masks[i] = (1 << buttonGpios[i]); + + // Clear button flags and counters + buttons[i] = 0; + button_times[i] = 0; + } + + // -------------------------------- + // GPIO monitor & debounce loop + uint32_t bank0 = 0; + uint32_t prev_button_states[nButtons]; + + while (!terminate_process) + { + usleep(5 * 1000); + + bank0 = digitalReadBank(0); + + for (int i=0; i < nButtons; ++i) + { + int buttonState = (bank0 & masks[i]); + + // If button changed state, reset its timer. + if (buttonState != prev_button_states[i]) + { + button_times[i] = millis(); + } + + if ((millis() - button_times[i]) >= DEBOUNCE_TIME) + { + // Pressed button = LOW = 0 + // Set the state to 1 if pressed, 0 if released. + buttons[i] = !buttonState; + } + + prev_button_states[i] = buttonState; + } + } // end while + + // -------------------------------- + + printf("Debounce done.\n"); + + return (void *)NULL; +} + +//********************************************************************************************************************** + +static void Button_Wait (int pin) +{ + printf(" %-2d %-2d %-2d %-2d\n", buttons[0], buttons[1], buttons[2], buttons[3]); +} + +//********************************************************************************************************************** + +int main (int argc, char *argv[]) +{ + // Set the handler for SIGTERM (15) + signal(SIGTERM, Signal_handler); + signal(SIGHUP, Signal_handler); + signal(SIGINT, Signal_handler); + signal(SIGQUIT, Signal_handler); + signal(SIGTRAP, Signal_handler); + signal(SIGABRT, Signal_handler); + signal(SIGALRM, Signal_handler); + signal(SIGUSR1, Signal_handler); + signal(SIGUSR2, Signal_handler); + + printf ("Raspberry Pi Button Test\n"); + + // ---------------------------------------------------- + + // Set up for BCM pin numbering + wiringPiSetupGpio (); + + // ---------------------------------------------------- + // Set up the button debounce thread + + pthread_t debounceThreadId; + pthread_create (&debounceThreadId, NULL, debounce, NULL) ; + + // ---------------------------------------------------- + + // Set up a callback for when any of these buttons is pressed/released + // The ISR will display the state of all buttons. + if (wiringPiISRmulti ((int *)buttonGpios, nButtons, INT_EDGE_RISING, &Button_Wait) < 0) + { + fprintf (stderr, "%s: Unable to setup ISR: %s\n", argv[0], strerror(errno)); + return EXIT_FAILURE; + } + + // ---------------------------------------------------- + + printf("Buttons:\n"); + printf(" 1 2 3 4\n"); + printf("--- --- --- ---\n"); + while (!terminate_process) + { + delayMs(100); + } + + // ---------------------------------------------------- + + pthread_join(debounceThreadId, NULL); + + printf("%s done.\n", argv[0]); + + return EXIT_SUCCESS; +} + +//********************************************************************************************************************** + +/** + * Intercepts and handles signals from QNX + * This function is called when the SIGTERM signal is raised by QNX + */ +static void Signal_handler(int sig) +{ + printf("Received signal %d\n", sig); + + // Signal process to exit. + terminate_process = 1; +} + +//********************************************************************************************************************** diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index 7eff836..2d4f382 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -278,6 +278,7 @@ extern void digitalWriteByte2 (int value); // Set up for a callback to be called when the specified pin changes according to mode. // mode = INT_EDGE_SETUP, INT_EDGE_FALLING, INT_EDGE_RISING, INT_EDGE_BOTH // Uses SYS mode, and also waitForInterrupt +// @NOTE: This leaves gpios exported in /sys/class/gpio when the program ends. extern int wiringPiISR (int pin, int mode, void (*function)(int)); // Same as wiringPiISR above, but takes a list of pins to wait for. @@ -287,6 +288,7 @@ extern int wiringPiISRmulti (int pins[], int n_pins, int mode, void (*functi // Internal-only (unless you know how to set up /sys/class/gpio) // Wait for "interrupt" on a GPIO pin. // Must be in SYS mode (wiringPiSetupSys was called for setup) +// @NOTE: This leaves gpios exported in /sys/class/gpio when the program ends. extern int waitForInterrupt (int pin, int mS); // ----------------------------------------------------------------------------