裸机实现-状态机困局的具象化呈现

// 裸机实现:超级循环状态机
typedef enum {
STATE_IDLE, STATE_AD采集, STATE_UART_SEND, STATE_DELAY
} SystemState;

volatile uint8_t adc_done = 0;
volatile uint8_t uart_tx_done = 0;
SystemState current_state = STATE_IDLE;
uint32_t last_tick = 0;

int main(void) {
HAL_Init();
ADC_Init(); UART_Init(); GPIO_Init();
last_tick = HAL_GetTick();

while(1) {
switch(current_state) {
case STATE_IDLE:
if(HAL_GetTick() – last_tick >= 100) {
ADC_StartConversion();
current_state = STATE_AD采集;
} else if(Key_Scan() == KEY_PRESSED) {
// 立即响应按键,但会阻塞主循环
LED_Toggle();
}
break;

case STATE_AD采集:
if(adc_done) { // ADC中断中设置
sensor_data = ADC_GetValue();
adc_done = 0;
UART_Send(sensor_data); // 阻塞式发送!
current_state = STATE_UART_SEND;
}
break;

case STATE_UART_SEND:
if(uart_tx_done) { // UART中断中设置
uart_tx_done = 0;
current_state = STATE_DELAY;
}
// 此状态CPU被阻塞,无法响应按键
break;

case STATE_DELAY:
if(HAL_GetTick() – last_tick >= 100) {
last_tick = HAL_GetTick();
current_state = STATE_IDLE;
}
break;
}
}
}

// ADC中断服务程序
void ADC_IRQHandler(void) {
adc_done = 1;
}

// UART发送完成中断
void UART_IRQHandler(void) {
uart_tx_done = 1;
}

裸机架构的三大痛点
1. 响应性灾难
当UART_Send()以阻塞方式发送10字节数据(约870μs @115200bps)时,主循环停滞在STATE_UART_SEND状态,此期间按键扫描完全停止。若采用DMA发送,虽能解决CPU阻塞,但状态机复杂度会进一步增加,需处理DMA传输完成中断、错误处理等更多状态,导致状态空间爆炸。

2. 模块化失效
所有功能耦合在main()函数内,新增显示屏功能需要修改状态机枚举、添加新状态、处理显示刷新与采集/通信的状态冲突。任何一个功能的修改都可能破坏其他功能的时序,例如调整采集频率会影响按键检测的实时性。

3. 可维护性崩溃
全局标志位adc_done、uart_tx_done在中断和主循环间共享,缺乏访问保护,易发生竞态条件。调试时需同时跟踪状态变量、全局标志、时间戳,难以复现偶发性时序bug。当功能扩展到5个以上时,状态机将变得不可控,状态转换逻辑复杂度呈指数级增长。

欢迎使用66资源网
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
7. 本站有不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!

66源码网 » 裸机实现-状态机困局的具象化呈现

提供最优质的资源集合

立即查看 了解详情