| 编辑推荐: |
本文主要介绍了基于状态机与事件驱动的嵌入式软件框架设计相关内容,希望对您的学习有所帮助。
本文来自于微信公众号嵌入式软件客栈,由火龙果软件Alice编辑、推荐。 |
|
在嵌入式系统开发中,传统的程序结构往往依赖大量的if-else分支和delay()延时函数,导致代码可读性差、响应不及时、难以维护。
传统方案问题
常见的问题代码模式
按键处理问题示例
// ❌ 问题代码:传统按键处理方式 voidkey_scan(void) { staticuint32_t last_time = 0; uint32_t now = HAL_GetTick(); if (now - last_time < 50) { // 50ms扫描一次 return; } last_time = now; if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { delay_ms(20); // 阻塞延时20ms if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { // 短按检测 uint32_t press_time = HAL_GetTick(); while (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { delay_ms(10); // 继续阻塞等待 } uint32_t release_time = HAL_GetTick(); uint32_t duration = release_time - press_time; if (duration < 500) { // 短按处理 printf("Short press\r\n"); } elseif (duration < 3000) { // 长按处理 printf("Long press\r\n"); } else { // 超长按处理 printf("Extra long press\r\n"); } } } }
// 问题分析: // 1. delay_ms()阻塞CPU,无法响应其他事件 // 2. while循环占用CPU,功耗高 // 3. 无法处理多个按键同时按下 // 4. 代码逻辑混乱,难以扩展
|
状态机与事件驱动
有限状态机基础
状态机的优势:
• 清晰的状态表示:系统在任何时刻都处于明确的状态
• 可预测的行为:相同状态和事件总是产生相同的转换
• 易于测试:可以系统性地测试所有状态转换
• 易于扩展:添加新状态和转换相对简单
事件驱动基础
事件驱动的优势:
• 非阻塞:事件处理函数快速返回,不阻塞系统
• 实时响应:事件可以立即得到处理
• 解耦:事件源和事件处理解耦
• 可扩展:易于添加新的事件类型和处理者
状态机与事件驱动的结合
轻量级事件-状态机框架设计
框架整体架构
核心数据结构设计
// event_state_machine.c #include "event_state_machine.h" #include <string.h>
// 事件队列初始化 voidevent_queue_init(event_queue_t *queue) { if (queue == NULL) return; memset(queue, 0, sizeof(event_queue_t)); queue->head = 0; queue->tail = 0; queue->count = 0; }
// 事件入队 boolevent_queue_push(event_queue_t *queue, event_t *event) { if (queue == NULL || event == NULL) returnfalse; // 队列满检查 if (queue->count >= EVENT_QUEUE_SIZE) { returnfalse; // 队列满,丢弃最旧的事件或返回错误 } // 添加时间戳 event->timestamp = GET_TICK(); // 入队 queue->events[queue->tail] = *event; queue->tail = (queue->tail + 1) % EVENT_QUEUE_SIZE; queue->count++; returntrue; }
// 事件出队 boolevent_queue_pop(event_queue_t *queue, event_t *event) { if (queue == NULL || event == NULL) returnfalse; // 队列空检查 if (queue->count == 0) { returnfalse; } // 出队 *event = queue->events[queue->head]; queue->head = (queue->head + 1) % EVENT_QUEUE_SIZE; queue->count--; returntrue; }
// 检查队列是否为空 boolevent_queue_is_empty(event_queue_t *queue) { if (queue == NULL) returntrue; return (queue->count == 0); }
// 检查队列是否满 boolevent_queue_is_full(event_queue_t *queue) { if (queue == NULL) returntrue; return (queue->count >= EVENT_QUEUE_SIZE); }
|
事件队列实现(环形缓冲区)
// event_state_machine.c #include "event_state_machine.h" #include <string.h>
// 事件队列初始化 voidevent_queue_init(event_queue_t *queue) { if (queue == NULL) return; memset(queue, 0, sizeof(event_queue_t)); queue->head = 0; queue->tail = 0; queue->count = 0; }
// 事件入队 boolevent_queue_push(event_queue_t *queue, event_t *event) { if (queue == NULL || event == NULL) returnfalse; // 队列满检查 if (queue->count >= EVENT_QUEUE_SIZE) { returnfalse; // 队列满,丢弃最旧的事件或返回错误 } // 添加时间戳 event->timestamp = GET_TICK(); // 入队 queue->events[queue->tail] = *event; queue->tail = (queue->tail + 1) % EVENT_QUEUE_SIZE; queue->count++; returntrue; }
// 事件出队 boolevent_queue_pop(event_queue_t *queue, event_t *event) { if (queue == NULL || event == NULL) returnfalse; // 队列空检查 if (queue->count == 0) { returnfalse; } // 出队 *event = queue->events[queue->head]; queue->head = (queue->head + 1) % EVENT_QUEUE_SIZE; queue->count--; returntrue; }
// 检查队列是否为空 boolevent_queue_is_empty(event_queue_t *queue) { if (queue == NULL) returntrue; return (queue->count == 0); }
// 检查队列是否满 boolevent_queue_is_full(event_queue_t *queue) { if (queue == NULL) returntrue; return (queue->count >= EVENT_QUEUE_SIZE); }
|
状态机核心实现
// 状态机初始化 voidstate_machine_init(state_machine_t *sm, state_t initial_state, state_handler_t *state_table, uint8_t max_states, state_transition_cb_t on_transition) { if (sm == NULL || state_table == NULL) return; sm->current_state = initial_state; sm->initial_state = initial_state; sm->state_table = state_table; sm->on_transition = on_transition; sm->max_states = max_states; }
// 状态机处理单个事件 voidstate_machine_process(state_machine_t *sm, event_t *event) { if (sm == NULL || event == NULL) return; if (sm->state_table == NULL) return; // 获取当前状态的处理函数 state_t current = sm->current_state; if (current >= sm->max_states) return; state_handler_t handler = sm->state_table[current]; if (handler == NULL) return; // 调用状态处理函数 state_t new_state = handler(event); // 检查状态是否发生变化 if (new_state != current && new_state < sm->max_states) { // 状态转换 state_t old_state = sm->current_state; sm->current_state = new_state; // 调用转换回调 if (sm->on_transition != NULL) { sm->on_transition(old_state, new_state); } } }
// 状态机主循环(从事件队列处理事件) voidstate_machine_run(state_machine_t *sm, event_queue_t *queue) { if (sm == NULL || queue == NULL) return; event_t event; while (!event_queue_is_empty(queue)) { if (event_queue_pop(queue, &event)) { state_machine_process(sm, &event); } } }
|
智能按键处理应用
按键状态机设计
按键状态定义
// key_state_machine.c #include "key_state_machine.h" #include "stm32l4xx_hal.h"
// 用户回调函数(外部定义) key_short_press_cb_t key_short_press_callback = NULL; key_long_press_cb_t key_long_press_callback = NULL;
// 外部按键GPIO定义(根据实际硬件修改) extern GPIO_TypeDef* KEY_GPIO_Port; externuint16_t KEY_Pin;
// 状态处理函数:IDLE状态 staticstate_tkey_state_idle_handler(event_t *event) { if (event->type == KEY_EVENT_PRESS) { return KEY_STATE_PRESSED; // 转换到按下状态 } return KEY_STATE_IDLE; // 保持当前状态 }
// 状态处理函数:PRESSED状态(消抖) staticstate_tkey_state_pressed_handler(event_t *event) { switch (event->type) { case KEY_EVENT_TIMEOUT: // 消抖时间到,检查按键是否仍按下 if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { return KEY_STATE_DEBOUNCED; // 确认按下 } else { return KEY_STATE_IDLE; // 抖动,返回空闲 } case KEY_EVENT_RELEASE: // 在消抖期间释放,认为是抖动 return KEY_STATE_IDLE; default: return KEY_STATE_PRESSED; } }
// 状态处理函数:DEBOUNCED状态 staticstate_tkey_state_debounced_handler(event_t *event) { switch (event->type) { case KEY_EVENT_RELEASE: // 释放,判定为短按 return KEY_STATE_SHORT_PRESS; case KEY_EVENT_TIMEOUT: // 长按超时 return KEY_STATE_LONG_PRESS; default: return KEY_STATE_DEBOUNCED; } }
// 状态处理函数:SHORT_PRESS状态 staticstate_tkey_state_short_press_handler(event_t *event) { // 触发短按回调 if (key_short_press_callback != NULL) { key_short_press_callback(); } return KEY_STATE_IDLE; // 返回空闲状态 }
// 状态处理函数:LONG_PRESS状态 staticstate_tkey_state_long_press_handler(event_t *event) { // 触发长按回调 if (key_long_press_callback != NULL) { key_long_press_callback(); } if (event->type == KEY_EVENT_RELEASE) { return KEY_STATE_RELEASED; } return KEY_STATE_HELD; // 继续按住 }
// 状态处理函数:HELD状态 staticstate_tkey_state_held_handler(event_t *event) { if (event->type == KEY_EVENT_RELEASE) { return KEY_STATE_RELEASED; } return KEY_STATE_HELD; }
// 状态处理函数:RELEASED状态 staticstate_tkey_state_released_handler(event_t *event) { // 释放处理完成,返回空闲 return KEY_STATE_IDLE; }
// 状态转换回调 staticvoidkey_state_transition_cb(state_t old_state, state_t new_state) { // 记录状态转换,可用于调试 // printf("Key state: %d -> %d\r\n", old_state, new_state); }
// 按键处理初始化 voidkey_handler_init(key_handler_t *key) { if (key == NULL) return; // 初始化状态处理函数表 key->handlers[KEY_STATE_IDLE] = key_state_idle_handler; key->handlers[KEY_STATE_PRESSED] = key_state_pressed_handler; key->handlers[KEY_STATE_DEBOUNCED] = key_state_debounced_handler; key->handlers[KEY_STATE_SHORT_Press] = key_state_short_press_handler; key->handlers[KEY_STATE_LONG_PRESS] = key_state_long_press_handler; key->handlers[KEY_STATE_HELD] = key_state_held_handler; key->handlers[KEY_STATE_RELEASED] = key_state_released_handler; // 初始化事件队列 event_queue_init(&key->queue); // 初始化状态机 state_machine_init(&key->sm, KEY_STATE_IDLE, key->handlers, KEY_STATE_MAX, key_state_transition_cb); }
// 按键处理主循环(在主循环中定期调用) voidkey_handler_process(key_handler_t *key) { if (key == NULL) return; // 处理事件队列中的所有事件 state_machine_run(&key->sm, &key->queue); }
// 按键按下事件(在GPIO中断中调用) voidkey_on_press(key_handler_t *key) { if (key == NULL) return; event_t event = { .type = KEY_EVENT_PRESS, .data = 0, .timestamp = GET_TICK() }; event_queue_push(&key->queue, &event); // 启动消抖定时器(使用软件定时器或硬件定时器) // 这里需要在20ms后发送KEY_EVENT_TIMEOUT事件 }
// 按键释放事件(在GPIO中断中调用) voidkey_on_release(key_handler_t *key) { if (key == NULL) return; event_t event = { .type = KEY_EVENT_RELEASE, .data = 0, .timestamp = GET_TICK() }; event_queue_push(&key->queue, &event); }
|
按键状态处理函数实现
// key_state_machine.c #include "key_state_machine.h" #include "stm32l4xx_hal.h"
// 用户回调函数(外部定义) key_short_press_cb_t key_short_press_callback = NULL; key_long_press_cb_t key_long_press_callback = NULL;
// 外部按键GPIO定义(根据实际硬件修改) extern GPIO_TypeDef* KEY_GPIO_Port; externuint16_t KEY_Pin;
// 状态处理函数:IDLE状态 staticstate_tkey_state_idle_handler(event_t *event) { if (event->type == KEY_EVENT_PRESS) { return KEY_STATE_PRESSED; // 转换到按下状态 } return KEY_STATE_IDLE; // 保持当前状态 }
// 状态处理函数:PRESSED状态(消抖) staticstate_tkey_state_pressed_handler(event_t *event) { switch (event->type) { case KEY_EVENT_TIMEOUT: // 消抖时间到,检查按键是否仍按下 if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { return KEY_STATE_DEBOUNCED; // 确认按下 } else { return KEY_STATE_IDLE; // 抖动,返回空闲 } case KEY_EVENT_RELEASE: // 在消抖期间释放,认为是抖动 return KEY_STATE_IDLE; default: return KEY_STATE_PRESSED; } }
// 状态处理函数:DEBOUNCED状态 staticstate_tkey_state_debounced_handler(event_t *event) { switch (event->type) { case KEY_EVENT_RELEASE: // 释放,判定为短按 return KEY_STATE_SHORT_PRESS; case KEY_EVENT_TIMEOUT: // 长按超时 return KEY_STATE_LONG_PRESS; default: return KEY_STATE_DEBOUNCED; } }
// 状态处理函数:SHORT_PRESS状态 staticstate_tkey_state_short_press_handler(event_t *event) { // 触发短按回调 if (key_short_press_callback != NULL) { key_short_press_callback(); } return KEY_STATE_IDLE; // 返回空闲状态 }
// 状态处理函数:LONG_PRESS状态 staticstate_tkey_state_long_press_handler(event_t *event) { // 触发长按回调 if (key_long_press_callback != NULL) { key_long_press_callback(); } if (event->type == KEY_EVENT_RELEASE) { return KEY_STATE_RELEASED; } return KEY_STATE_HELD; // 继续按住 }
// 状态处理函数:HELD状态 staticstate_tkey_state_held_handler(event_t *event) { if (event->type == KEY_EVENT_RELEASE) { return KEY_STATE_RELEASED; } return KEY_STATE_HELD; }
// 状态处理函数:RELEASED状态 staticstate_tkey_state_released_handler(event_t *event) { // 释放处理完成,返回空闲 return KEY_STATE_IDLE; }
// 状态转换回调 staticvoidkey_state_transition_cb(state_t old_state, state_t new_state) { // 记录状态转换,可用于调试 // printf("Key state: %d -> %d\r\n", old_state, new_state); }
// 按键处理初始化 voidkey_handler_init(key_handler_t *key) { if (key == NULL) return; // 初始化状态处理函数表 key->handlers[KEY_STATE_IDLE] = key_state_idle_handler; key->handlers[KEY_STATE_PRESSED] = key_state_pressed_handler; key->handlers[KEY_STATE_DEBOUNCED] = key_state_debounced_handler; key->handlers[KEY_STATE_SHORT_Press] = key_state_short_press_handler; key->handlers[KEY_STATE_LONG_PRESS] = key_state_long_press_handler; key->handlers[KEY_STATE_HELD] = key_state_held_handler; key->handlers[KEY_STATE_RELEASED] = key_state_released_handler; // 初始化事件队列 event_queue_init(&key->queue); // 初始化状态机 state_machine_init(&key->sm, KEY_STATE_IDLE, key->handlers, KEY_STATE_MAX, key_state_transition_cb); }
// 按键处理主循环(在主循环中定期调用) voidkey_handler_process(key_handler_t *key) { if (key == NULL) return; // 处理事件队列中的所有事件 state_machine_run(&key->sm, &key->queue); }
// 按键按下事件(在GPIO中断中调用) voidkey_on_press(key_handler_t *key) { if (key == NULL) return; event_t event = { .type = KEY_EVENT_PRESS, .data = 0, .timestamp = GET_TICK() }; event_queue_push(&key->queue, &event); // 启动消抖定时器(使用软件定时器或硬件定时器) // 这里需要在20ms后发送KEY_EVENT_TIMEOUT事件 }
// 按键释放事件(在GPIO中断中调用) voidkey_on_release(key_handler_t *key) { if (key == NULL) return; event_t event = { .type = KEY_EVENT_RELEASE, .data = 0, .timestamp = GET_TICK() }; event_queue_push(&key->queue, &event); }
|
按键使用示例
// main.c #include "key_state_machine.h" #include "stm32l4xx_hal.h"
key_handler_t g_key_handler;
// 短按回调函数 voidon_key_short_press(void) { printf("Short press detected\r\n"); // 执行短按业务逻辑,例如:切换LED状态 HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); }
// 长按回调函数 voidon_key_long_press(void) { printf("Long press detected\r\n"); // 执行长按业务逻辑,例如:进入配置模式 enter_config_mode(); }
// GPIO中断回调 voidHAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == KEY_Pin) { if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { key_on_press(&g_key_handler); } else { key_on_release(&g_key_handler); } } }
// 软件定时器回调(1ms调用一次) voidsystick_callback(void) { staticuint32_t debounce_timer = 0; staticuint32_t long_press_timer = 0; // 消抖定时器 if (debounce_timer > 0) { debounce_timer--; if (debounce_timer == 0) { event_t event = { .type = KEY_EVENT_TIMEOUT, .data = KEY_DEBOUNCE_TIME, .timestamp = GET_TICK() }; event_queue_push(&g_key_handler.queue, &event); } } // 长按定时器(在DEBOUNCED状态时启动) // ... 类似处理 }
intmain(void) { // 硬件初始化 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); // 设置回调函数 key_short_press_callback = on_key_short_press; key_long_press_callback = on_key_long_press; // 初始化按键处理 key_handler_init(&g_key_handler); // 主循环 while (1) { // 处理按键事件(非阻塞) key_handler_process(&g_key_handler); // 其他任务 // ... // 进入低功耗模式(可选) HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); } }
|
|