CHAPTER 07 / FIELD GUIDE
时间与状态机
让灯闪烁,同时仍能响应按键。
一次循环做一点事
若在处理按键的同一个循环里延迟 2 秒,这 2 秒内就不会再次读按键。解决办法是记住截止时间,每轮检查“时间到了吗”,完成小步工作后马上继续。
int64_t changed = now_ms();
bool on = false;
for (;;) {
if (now_ms() - changed >= 500) {
changed = now_ms();
on = !on;
gpio_set_level(LED, on);
}
if (button_pressed()) {
// 这里处理一次按下事件
}
vTaskDelay(pdMS_TO_TICKS(10));
}这是循环片段,放进已初始化 LED 和按键的 app_main 中,不是单独工程。now_ms 使用单调计时;不要用网络校准后的日历时间计算控制周期。
状态机让行为可描述
| 当前状态 | 事件 | 动作 | 下一状态 |
|---|---|---|---|
| 停止 | 按下 | 记录开始时间,打开输出 | 运行 |
| 运行 | 按下 | 关闭输出 | 停止 |
| 运行 | 超时 | 关闭输出 | 停止 |
| 任意 | 检测到故障 | 关闭输出并记录故障 | 故障 |
先写转移表再写 if,比堆多个相互覆盖的布尔变量容易检查。故障状态是否允许再次启动,应明确规定;真实机器人不应在故障解除后自动重新运动。
实验
- 从 03_button 复制一个新工程,保留公共组件目录。
- 把闪烁计时加入循环;按键只切换是否允许闪烁。
- 关闭闪烁时立即将 LED 置 0。
- 记录最慢按键响应:它至少受到采样周期、30 ms 消抖和循环中最长工作时间影响。
停下来想一想
循环里没有 delay,就一定响应快吗?
查看推导与答案
不一定。屏幕传输、网络等待、长计算一样会阻塞。还可能因为忙循环占满 CPU 而影响其他任务。需要分析每段工作的最长耗时。
本章验收
本章一手资料
卡住时可以直接向我提问:附上章节号、工程名、接线和第一条错误日志。