Событийный автомат
Желая облегчить себе жизнь, придется создать еще одно перечисление и переменную для событий. Все два события нам известны — поступим так же, как и в прошлый раз:
// state_machine.h
typedef enum {
EVENT_NONE,
EVENT_BUTTON_PRESSED,
EVENT_TIME_OUT,
} EVENT_t;
// state_machine.c
volatile EVENT_t event = EVENT_NONE;
Происходит событие — меняется значение event
. Следовательно, обработчики прерываний необходимо переписать.
// stm32f10x.h
void EXTI_IRQHandler(void) {
event = EVENT_BUTTON_PRESSED;
// reset pending bit
}
// …
void TIM1_Handler(void) {
event = EVENT_TIME_OUT;
// reset pending bit
}
Перепишем главный цикл так, чтобы он реагировал на события в зависимости от состояния.
int main(void) {
mcu_init();
while(1) {
switch (state) {
default:
case STATE_SHOW_TIME:
switch(event) {
case EVENT_BUTTON_PRESSED:
state = STATE_SHOW_TEMPERATURE;
event = EVENT_NONE;
countdown_start(RETURN_DELAY);
state = STATE_SHOW_TEMPERATURE;
event = EVENT_NONE;
countdown_start(RETURN_DELAY);
break;
default:
display_time();
break;
}
break;
case STATE_SHOW_TEMPERATURE:
switch(event) {
case EVENT_BUTTON_PRESSED:
state = (display_get_intensivity()) ?
STATE_SHOW_TIME : STATE_ADJUST_HOURS;
event = EVENT_NONE;
countdown_stop();
break;
default:
display_temperature();
break;
}
break;
case SHOW_ADJUST_HOURS:
switch(event) {
case EVENT_BUTTON_PRESSED:
state = STATE_ADJUST_MINUTES;
event = EVENT_NONE;
countdown_start(RETURN_DELAY);
break;
default:
display_hours();
break;
}
break;
case SHOW_ADJUST_MINUTES:
switch(event) {
case EVENT_BUTTON_PRESSED:
state = STATE_SHOW_TIME;
event = EVENT_NONE;
countdown_start(RETURN_DELAY);
break;
default:
display_minutes();
break;
}
break;
} // end of the main loop
}
Мы сильно потеряли в читаемости кода — блоки получились очень большими. Дабы исправить ситуацию, всю логику инкапсулируем в функции.
void time_routine() {
//
}
// …
int main(void) {
mcu_init();
while(1) {
switch (state) {
default:
case STATE_SHOW_TIME:
time_routine();
// ...
Такой подход, с одной стороны, лучше, так как все переходы явно видны, это облегчает отладку. С другой стороны, хуже: сложнее добавлять новые состояния, код плохо читается и имеет меньшую производительность.