Машина состояний на указателях на функции
Для ускорения работы программы можно использовать указатели на функции (англ. function pointers): переход по указателю с вычислительной точки зрения почти ничего не стоит (сохранение переменных в стеке, запись адреса возврата), чего нельзя сказать про условные операторы (если их много и предугадать их не получается). Кроме того, это хороший способ продемонстрировать возможность обратного вызова функции (англ. callback). Модифицируем предыдущий пример, убрав switch
/ case
конструкцию из главного цикла.
Для начала создадим тип указателя на функцию:
// state_machine.h
typedef void (STATE_FUNC_PTR_t)();
Затем нужно создать прототипы функций, в которых будет зашита логика поведения устройства. Сколько состояний — столько и функций. Также добавим глобальную переменную, отвечающую за состояние и хранящую адрес вызываемой функции.
// state_machine.h
void *state_time();
void *state_temperature();
void *state_adjust_hours();
void *state_adjust_minutes();
STATE_FUNC_PTR_t state = state_time;
Далее в исходном файле машины состояний пропишем логику программы. Как и в предыдущий раз, будем реагировать на изменение глобальной переменной event
.
// state_machine.c
void *state_time() {
// do some logic here
display_time();
return (event == EVENT_BUTTON_PRESSED) ? state_temperature : state_time; // next state
}
// … others
Код получается довольно компактным, но не очень читаемым, так как нужно отслеживать все переходы в каждой функции. Как уйти от такой необходимости, мы рассмотрим сразу же, как допишем главный цикл.
int main() {
init_mcu();
while(1) {
state = (STATE_FUNC_PTR_t)(*state)();
}
}