WIP: started implementing the countdown state machine

This commit is contained in:
Thomas Kolb 2024-05-15 22:07:53 +02:00
parent 0c95a27a3f
commit 7d36e71923

View file

@ -1,16 +1,24 @@
#include "hardware/gpio.h" #include "hardware/gpio.h"
#include "hardware/irq.h" #include "hardware/irq.h"
#include "hardware/pwm.h"
#include "hardware/irq.h"
#include "sseg.h" #include "sseg.h"
#include "buttons.h"
#include "buzzer.h"
#include "pinout.h" #include "pinout.h"
#include <pico/stdlib.h> #include <pico/stdlib.h>
const uint8_t all_gpios[] = { typedef enum {
OUTPUT_ENABLE_PIN, COUNTDOWN_UNINITIALIZED,
}; COUNTDOWN_STOPPED,
COUNTDOWN_STARTING,
COUNTDOWN_RUNNING
} countdown_state_t;
static countdown_state_t m_countdown_state;
static uint32_t m_last_state_change_time;
static uint32_t m_countdown_off_time;
static volatile bool m_ms_triggered; static volatile bool m_ms_triggered;
static uint32_t m_next_ms_trigger; static uint32_t m_next_ms_trigger;
@ -45,62 +53,139 @@ static void configure_ms_trig_alarm(void)
m_next_ms_trigger = timer_hw->timelr + 10000; m_next_ms_trigger = timer_hw->timelr + 10000;
} }
static void update_countdown_fsm(uint32_t time_ms)
{
countdown_state_t last_state = m_countdown_state;
// note: this calculation works even if time_ms overflows
uint32_t time_in_state = time_ms - m_last_state_change_time;
bool state_entered = (time_in_state == 1);
uint32_t countdown_time_remaining; // only used in COUNTDOWN_RUNNING state
switch(m_countdown_state) {
case COUNTDOWN_UNINITIALIZED:
m_countdown_state = COUNTDOWN_STOPPED;
break;
case COUNTDOWN_STOPPED:
if(state_entered) {
sseg_set_char(0, 'o', false);
sseg_set_char(1, 'f', false);
sseg_set_char(2, 'f', false);
}
if(buttons_get_events(BTN_ON) & BTN_EVENT_PRESSED) {
m_countdown_state = COUNTDOWN_STARTING;
}
break;
case COUNTDOWN_STARTING:
// TODO: show a fancy animation + beep code
if(buttons_get_events(BTN_ON) & BTN_EVENT_RELEASED) {
// button released too early -> back to stopped state
m_countdown_state = COUNTDOWN_STOPPED;
}
if(time_in_state == 3000) {
m_countdown_off_time = time_ms + 30 * 60 * 1000;
m_countdown_state = COUNTDOWN_RUNNING;
}
break;
case COUNTDOWN_RUNNING:
if(state_entered) {
// countdown has been started -> switch on the load
gpio_put(OUTPUT_ENABLE_PIN, true);
}
countdown_time_remaining = m_countdown_off_time - time_ms;
// TODO: show time on display
// TODO: off button handling
// TODO: on button handling (extend time)
// beep codes
switch(countdown_time_remaining) {
case 300000: // short beep at 5 minutes remaining
case 60000: // double beep at 1 minute remaining
case 59600:
case 10000: // triple beep at 10 seconds remaining
case 9600:
case 9200:
case 5000: // count down the last 5 seconds
case 4000:
case 3000:
case 2000:
case 1000: // last second beep is longer
buzzer_on(1000);
break;
case 299800:
case 59800:
case 59400:
case 9800:
case 9400:
case 9000:
case 4800:
case 3800:
case 2800:
case 1800:
case 500:
buzzer_off();
break;
}
if(countdown_time_remaining == 0) {
// switch off the load
gpio_put(OUTPUT_ENABLE_PIN, false);
m_countdown_state = COUNTDOWN_STOPPED;
}
}
if(m_countdown_state != last_state) {
m_last_state_change_time = time_ms;
}
}
int main() int main()
{ {
//stdio_init_all(); //stdio_init_all();
//printf("Hello, world!\n"); //printf("Hello, world!\n");
bool power_switch_state = false; gpio_init(OUTPUT_ENABLE_PIN);
gpio_put(OUTPUT_ENABLE_PIN, false);
gpio_set_dir(OUTPUT_ENABLE_PIN, true);
for(size_t i = 0; i < sizeof(all_gpios); i++) { buzzer_init();
gpio_init(all_gpios[i]); buttons_init();
gpio_put(all_gpios[i], false);
gpio_set_dir(all_gpios[i], true);
}
gpio_put(OUTPUT_ENABLE_PIN, true); buzzer_on(1000);
// set up PWM for 50 kHz @ 512 steps resolution
uint slice_num = pwm_gpio_to_slice_num(BUZZER_PIN);
pwm_set_clkdiv_int_frac(slice_num, 244, (14 << 4) / 100); // 125 MHz / 244.14 / 512 = 1 kHz
gpio_set_function(BUZZER_PIN, GPIO_FUNC_PWM);
pwm_set_wrap(slice_num, 512);
pwm_set_chan_level(slice_num, PWM_CHAN_B, 1 * 512 / 100);
pwm_set_enabled(slice_num, true);
sleep_ms(200); sleep_ms(200);
pwm_set_enabled(slice_num, false); buzzer_off();
pwm_set_clkdiv_int_frac(slice_num, 122, (7 << 4) / 100); // 125 MHz / 122.07 / 512 = 2 kHz buzzer_on(2000);
pwm_set_enabled(slice_num, true);
sleep_ms(200); sleep_ms(200);
pwm_set_enabled(slice_num, false); buzzer_off();
pwm_set_clkdiv_int_frac(slice_num, 61, (3 << 4) / 100); // 125 MHz / 61.03 / 512 = 4 kHz buzzer_on(4000);
pwm_set_enabled(slice_num, true);
sleep_ms(200); sleep_ms(200);
pwm_set_enabled(slice_num, false); buzzer_off();
gpio_init(BUZZER_PIN);
gpio_put(BUZZER_PIN, false);
gpio_set_dir(BUZZER_PIN, true);
sleep_ms(2400); sleep_ms(2400);
pwm_set_enabled(slice_num, false);
gpio_init(BUZZER_PIN);
gpio_put(OUTPUT_ENABLE_PIN, false);
sseg_init(); sseg_init();
configure_ms_trig_alarm(); configure_ms_trig_alarm();
arm_ms_trig_alarm(); arm_ms_trig_alarm();
m_countdown_state = COUNTDOWN_UNINITIALIZED;
uint32_t ms_counter = 0; uint32_t ms_counter = 0;
while (true) { while (true) {
sseg_loop(); sseg_loop();
@ -109,6 +194,11 @@ int main()
m_ms_triggered = false; m_ms_triggered = false;
ms_counter++; ms_counter++;
buttons_update_state(ms_counter);
update_countdown_fsm(ms_counter);
sseg_set_char(2, '0' + (ms_counter / 100) % 10, false); sseg_set_char(2, '0' + (ms_counter / 100) % 10, false);
sseg_set_char(1, '0' + (ms_counter / 1000) % 10, true); sseg_set_char(1, '0' + (ms_counter / 1000) % 10, true);
sseg_set_char(0, '0' + (ms_counter / 10000) % 10, false); sseg_set_char(0, '0' + (ms_counter / 10000) % 10, false);