CHAPTER 07 / FIELD GUIDE

时间与状态机

让灯闪烁,同时仍能响应按键。

建议用时 40 分钟先预测,再实验,再解释

一次循环做一点事

若在处理按键的同一个循环里延迟 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,比堆多个相互覆盖的布尔变量容易检查。故障状态是否允许再次启动,应明确规定;真实机器人不应在故障解除后自动重新运动。

实验

  1. 从 03_button 复制一个新工程,保留公共组件目录。
  2. 把闪烁计时加入循环;按键只切换是否允许闪烁。
  3. 关闭闪烁时立即将 LED 置 0。
  4. 记录最慢按键响应:它至少受到采样周期、30 ms 消抖和循环中最长工作时间影响。
停下来想一想

循环里没有 delay,就一定响应快吗?

查看推导与答案

不一定。屏幕传输、网络等待、长计算一样会阻塞。还可能因为忙循环占满 CPU 而影响其他任务。需要分析每段工作的最长耗时。

本章验收

本章一手资料

卡住时可以直接向我提问:附上章节号、工程名、接线和第一条错误日志。