153 lines
4.0 KiB
C
153 lines
4.0 KiB
C
/**
|
|
* Lab 3
|
|
* To develop a simple stopwatch that measures time intervals between
|
|
* button presses.
|
|
*
|
|
* On pressing the START pseudo-button (GP15),
|
|
* the stopwatch will begin,
|
|
* 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
|
|
* reset the elapsed time to zero.
|
|
*
|
|
* The START pseudo-button must incorporate a debouncing algorithm.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/gpio.h"
|
|
|
|
#define PSEUDO_BTN 15 // GPIO 15 is the pseudo-button
|
|
#define TIMER_US 1000000 // 1-second delay for repeating timer
|
|
#define DEBOUNCE_US 100 // 100us debounce time
|
|
|
|
struct repeating_timer timer; // Repeating timer
|
|
u_int64_t time = 0; // Elapsed time
|
|
|
|
typedef enum btn_state { // Button state
|
|
PRESSED = 0,
|
|
RELEASED = 1
|
|
} btn_state_t;
|
|
|
|
struct btn_status { // Button status
|
|
uint btn_pressed;
|
|
uint btn_released;
|
|
} btn_status = {0, 0};
|
|
|
|
/**
|
|
* Callback function for repeating timer
|
|
* This function will print the elapsed time every second as required by the
|
|
* lab specification.
|
|
* @param t The timer that triggered the callback
|
|
* @return True to keep the timer running, false to stop it
|
|
*/
|
|
bool elapsed_time_callback (struct repeating_timer *t) {
|
|
time++;
|
|
// Print elapsed time every second
|
|
printf("Elapsed Time: %llus\n", time);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the state of the pseudo-button (pull-up)
|
|
* This function will implement a debounce algorithm to
|
|
* get the state of the pseudo-button. (With added complexity)
|
|
* @return The state of the pseudo-button
|
|
*/
|
|
btn_state_t get_btn_state () {
|
|
u_int64_t start_time = time_us_64();
|
|
while (time_us_64() - start_time < DEBOUNCE_US)
|
|
{
|
|
if (gpio_get(PSEUDO_BTN))
|
|
{
|
|
btn_status.btn_released += 1;
|
|
}
|
|
else
|
|
{
|
|
btn_status.btn_pressed += 1;
|
|
}
|
|
}
|
|
|
|
btn_state_t state = (btn_status.btn_pressed > btn_status.btn_released) ?
|
|
PRESSED : RELEASED;
|
|
|
|
btn_status.btn_pressed = 0;
|
|
btn_status.btn_released = 0;
|
|
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* Interrupt callback function for pseudo-button (pull-up)
|
|
* This function will start the timer on button press (falling edge)
|
|
* and stop the timer on button release. (rising edge)
|
|
* @param gpio The GPIO pin that triggered the interrupt
|
|
* @param events The type of interrupt that triggered the callback
|
|
*/
|
|
void gpio_callback (uint gpio, uint32_t events) {
|
|
btn_state_t btn_state = get_btn_state();
|
|
|
|
if (events == GPIO_IRQ_EDGE_FALL && btn_state == PRESSED)
|
|
{
|
|
printf("\n====================================\n");
|
|
printf("Timer Started\n");
|
|
printf("====================================\n");
|
|
|
|
add_repeating_timer_us(
|
|
TIMER_US,
|
|
elapsed_time_callback,
|
|
NULL,
|
|
&timer
|
|
);
|
|
|
|
}
|
|
|
|
if (events == GPIO_IRQ_EDGE_RISE && btn_state == RELEASED)
|
|
{
|
|
cancel_repeating_timer(&timer);
|
|
|
|
// Print elapsed time and reset
|
|
printf("\n====================================\n");
|
|
printf("Timer Stopped\n");
|
|
printf("====================================\n");
|
|
printf("Final Elapsed Time: %llus\n", time);
|
|
printf("====================================\n");
|
|
|
|
time = 0;
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the pseudo-button (pull-up)
|
|
* The pseudo-button is connected to GPIO 15 and is configured as
|
|
* an input with a pull-up resistor.
|
|
* The interrupt is configured to trigger on both rising and
|
|
* falling edges.
|
|
*/
|
|
static void btn_init () {
|
|
gpio_init(PSEUDO_BTN);
|
|
gpio_set_dir(PSEUDO_BTN, GPIO_IN);
|
|
gpio_set_pulls(PSEUDO_BTN, true, false);
|
|
|
|
gpio_set_irq_enabled_with_callback(
|
|
PSEUDO_BTN,
|
|
GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL,
|
|
true,
|
|
&gpio_callback
|
|
);
|
|
}
|
|
|
|
int main () {
|
|
stdio_init_all();
|
|
btn_init();
|
|
|
|
while (true)
|
|
{
|
|
tight_loop_contents();
|
|
}
|
|
|
|
}
|