refactor(Debounce, Error handling):

Modified:
- Debounce Algorithm
- Result Printings
- Formatting
This commit is contained in:
Devoalda 2023-09-13 22:05:48 +08:00
parent 8b03fa6fcc
commit 3567d6deb3
1 changed files with 69 additions and 37 deletions

View File

@ -1,17 +1,31 @@
/** /**
* Lab 3 * Lab 3
* To develop a simple stopwatch that measures time intervals between
* button presses.
* *
* On pressing the START pseudo-button (GP15), * This is my solution to the lab 3 assignment.
* the stopwatch will begin, * There are multiple structs and enums defined in this file.
* and the elapsed time will be displayed every second on
* the Serial Monitor (or equivalent).
* *
* Releasing the START pseudo-button will stop the timer and * time_struct is used to store the start time and current time for
* reset the elapsed time to zero. * time calculations.
* *
* The START pseudo-button must incorporate a debouncing algorithm. * btn_status struct is used to keep track of the number of times the
* button is pressed and released. This is used to implement a debounce
* algorithm.
*
* btn_state enum is used to return the states of the button, used to check
* for errors and to return the state of the button.
*
* This firmware will use GPIO 15 as a pseudo-button (pull-up) and
* will start a timer on button press (falling edge) and stop the timer
* on button release (rising edge).
*
* The Timer will print the elapsed time every second as required by the
* lab specification.
*
* The DEBOUNCE_US macro is used to set the debounce delay to 20ms, the value
* can be refined to get more accurate results.
*
* This is made more complex with the use of interrupts, timers and a debounce
* algorithm.
* *
*/ */
@ -21,21 +35,26 @@
#define PSEUDO_BTN 15 // GPIO 15 is the pseudo-button #define PSEUDO_BTN 15 // GPIO 15 is the pseudo-button
#define TIMER_US 1000000 // 1-second delay for repeating timer #define TIMER_US 1000000 // 1-second delay for repeating timer
#define DEBOUNCE_US 100 // 100us debounce time #define DEBOUNCE_US 20000 // 20ms debounce delay
struct repeating_timer timer; // Repeating timer struct repeating_timer timer; // Repeating timer
u_int64_t time = 0; // Elapsed time
typedef enum btn_state { // Button state struct time_struct {
PRESSED = 0, uint64_t start_time;
RELEASED = 1 uint64_t current_time;
} btn_state_t; } time_struct = {0, 0};
struct btn_status { // Button status struct btn_status { // Button status (Used to implement debounce)
uint btn_pressed; uint btn_pressed;
uint btn_released; uint btn_released;
} btn_status = {0, 0}; } btn_status = {0, 0};
typedef enum btn_state { // Button state (Used as return value)
PRESSED = 0,
RELEASED = 1,
ERROR = -1
} btn_state_t;
/** /**
* Callback function for repeating timer * Callback function for repeating timer
* This function will print the elapsed time every second as required by the * This function will print the elapsed time every second as required by the
@ -44,9 +63,14 @@ struct btn_status { // Button status
* @return True to keep the timer running, false to stop it * @return True to keep the timer running, false to stop it
*/ */
bool elapsed_time_callback (struct repeating_timer *t) { bool elapsed_time_callback (struct repeating_timer *t) {
time++; time_struct.start_time = (time_struct.start_time == 0) ?
// Print elapsed time every second time_us_64() : time_struct.start_time;
printf("Elapsed Time: %llus\n", time);
time_struct.current_time = time_us_64();
printf("%llus\n",
(time_struct.current_time - time_struct.start_time) / 1000000);
return true; return true;
} }
@ -57,7 +81,13 @@ bool elapsed_time_callback (struct repeating_timer *t) {
* @return The state of the pseudo-button * @return The state of the pseudo-button
*/ */
btn_state_t get_btn_state () { btn_state_t get_btn_state () {
if (btn_status.btn_pressed != 0 || btn_status.btn_released != 0)
{
return ERROR;
}
u_int64_t start_time = time_us_64(); u_int64_t start_time = time_us_64();
while (time_us_64() - start_time < DEBOUNCE_US) while (time_us_64() - start_time < DEBOUNCE_US)
{ {
if (gpio_get(PSEUDO_BTN)) if (gpio_get(PSEUDO_BTN))
@ -89,11 +119,15 @@ btn_state_t get_btn_state () {
void gpio_callback (uint gpio, uint32_t events) { void gpio_callback (uint gpio, uint32_t events) {
btn_state_t btn_state = get_btn_state(); btn_state_t btn_state = get_btn_state();
if (btn_state == ERROR)
{
printf("Error: Button is bouncing\n");
return;
}
if (events == GPIO_IRQ_EDGE_FALL && btn_state == PRESSED) if (events == GPIO_IRQ_EDGE_FALL && btn_state == PRESSED)
{ {
printf("\n====================================\n");
printf("Timer Started\n"); printf("Timer Started\n");
printf("====================================\n");
add_repeating_timer_us( add_repeating_timer_us(
TIMER_US, TIMER_US,
@ -101,31 +135,29 @@ void gpio_callback (uint gpio, uint32_t events) {
NULL, NULL,
&timer &timer
); );
} }
if (events == GPIO_IRQ_EDGE_RISE && btn_state == RELEASED) if (events == GPIO_IRQ_EDGE_RISE && btn_state == RELEASED)
{ {
cancel_repeating_timer(&timer); if (cancel_repeating_timer(&timer))
{
// Print elapsed time and reset
printf("\n====================================\n");
printf("Timer Stopped\n"); printf("Timer Stopped\n");
printf("====================================\n"); printf("Final Elapsed Time: %llus\n",
printf("Final Elapsed Time: %llus\n", time); (time_struct.current_time - time_struct.start_time) /
printf("====================================\n"); 1000000);
}
time = 0;
time_struct = (struct time_struct) {0, 0};
} }
} }
/** /**
* Initialize the pseudo-button (pull-up) * Initialize the pseudo-button (pull-up)
* The pseudo-button is connected to GPIO 15 and is configured as * The pseudo-button is connected to GPIO 15 and
* an input with a pull-up resistor. * is configured as an input with a pull-up resistor.
* The interrupt is configured to trigger on both rising and *
* falling edges. * The interrupt is configured to trigger on both
* rising and falling edges.
*/ */
static void btn_init () { static void btn_init () {
gpio_init(PSEUDO_BTN); gpio_init(PSEUDO_BTN);