Menu
CoddyTech

交通灯状态机

本课属于 Coddy Arduino 学习旅程的“无需 delay 的计时”单元。第 10 课,共 18 课。

交通信号灯是一种状态机:它始终处于一种状态(绿色、黄色或红色),每种状态持续一段固定时间,并且每种状态都知道接下来会进入哪种状态:

  • GREEN:绿灯亮;2 s 后,切换到 YELLOW
  • YELLOW:黄灯亮;1 s 后,切换到 RED
  • RED:红灯亮;2 s 后,切换到 GREEN

每一行对应一个 case:

case GREEN:
  setLights(HIGH, LOW, LOW);
  if (now - lightStart >= 2000) {
    light = YELLOW;
    lightStart = now;
  }
  break;

使用 delay(2000),信号灯也能正常工作,但其他任务都无法运行。使用 millis() 时,每次执行 loop() 只需几微秒,因此电路板有时间处理其他任务:这里的其他任务是让状态 LED 一直闪烁,以显示控制器正在运行。

challenge icon

挑战

中等

引脚 13 上的状态 LED 已经在闪烁,enum 和 lightStart 也已准备好。使用 switch (light) 编写交通灯逻辑,每种灯对应一个 case:

  • 绿灯 2 s,黄灯 1 s,红灯 2 s,然后再次亮起绿灯
  • 每次只亮一盏 LED,使用 setLights()
  • 不要使用 delay(),这样状态 LED 就能继续闪烁

点击 运行,然后点击 检查。

亲手试试

const int greenLed = 10;
const int yellowLed = 11;
const int redLed = 12;
const int statusLed = 13;   // 开发板自带的 LED

enum Light { GREEN, YELLOW, RED };
Light light = GREEN;
unsigned long lightStart = 0;   // 当前灯亮起的时间

unsigned long statusPrevious = 0;
int statusState = LOW;

void setup() {
  pinMode(greenLed, OUTPUT);
  pinMode(yellowLed, OUTPUT);
  pinMode(redLed, OUTPUT);
  pinMode(statusLed, OUTPUT);
}

void setLights(int green, int yellow, int red) {
  digitalWrite(greenLed, green);
  digitalWrite(yellowLed, yellow);
  digitalWrite(redLed, red);
}

void loop() {
  unsigned long now = millis();

  // 状态 LED 每隔 250 ms 切换一次,表示控制器正在运行
  if (now - statusPrevious >= 250) {
    statusPrevious = now;
    if (statusState == LOW) {
      statusState = HIGH;
    } else {
      statusState = LOW;
    }
    digitalWrite(statusLed, statusState);
  }

  // 交通信号灯:用 switch(light)为每种灯设置一个 case
  // 绿灯亮 2 s,黄灯亮 1 s,红灯亮 2 s,然后再次亮绿灯
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

无需 delay 的计时中的所有课

自己练习: Arduino 在线编辑器