Menu
CoddyTech

Máy trạng thái đèn giao thông

Thuộc phần Định thời không dùng delay trong hành trình Arduino của Coddy. Bài học 10 trên 18.

Đèn giao thông là một máy trạng thái: nó luôn ở một trạng thái (xanh lá, vàng hoặc đỏ), mỗi trạng thái kéo dài một khoảng thời gian nhất định và mỗi trạng thái biết trạng thái nào sẽ đến tiếp theo:

  • GREEN: đèn xanh lá bật; sau 2 s, chuyển sang YELLOW
  • YELLOW: đèn vàng bật; sau 1 s, chuyển sang RED
  • RED: đèn đỏ bật; sau 2 s, chuyển sang GREEN

Mỗi dòng trở thành một case:

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

Dùng delay(2000) thì đèn cũng hoạt động, nhưng không thể chạy việc nào khác. Với millis(), mỗi lượt chạy qua loop() chỉ mất vài micro giây, nên bo mạch có thời gian xử lý việc khác: ở đây là một đèn LED báo trạng thái nhấp nháy liên tục để cho biết bộ điều khiển vẫn đang hoạt động.

challenge icon

Thử thách

Trung bình

Đèn LED trạng thái ở chân 13 đã nhấp nháy, và enum cùng lightStart đã sẵn sàng. Viết đèn giao thông bằng switch (light), mỗi đèn có một case:

  • đèn xanh 2 s, đèn vàng 1 s, đèn đỏ 2 s, rồi lại đến đèn xanh
  • mỗi lần chỉ bật một đèn, dùng setLights()
  • không dùng delay(), để đèn LED trạng thái tiếp tục nhấp nháy

Nhấn Chạy, rồi nhấn Kiểm tra.

Tự làm thử

const int greenLed = 10;
const int yellowLed = 11;
const int redLed = 12;
const int statusLed = 13;   // đèn LED tích hợp trên bo mạch

enum Light { GREEN, YELLOW, RED };
Light light = GREEN;
unsigned long lightStart = 0;   // thời điểm đèn hiện tại bật sáng

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();

  // đèn LED trạng thái đổi trạng thái sau mỗi 250 ms để báo bộ điều khiển vẫn hoạt động
  if (now - statusPrevious >= 250) {
    statusPrevious = now;
    if (statusState == LOW) {
      statusState = HIGH;
    } else {
      statusState = LOW;
    }
    digitalWrite(statusLed, statusState);
  }

  // đèn giao thông: câu lệnh switch (light) có một case cho mỗi màu đèn
  // đèn xanh 2 s, đèn vàng 1 s, đèn đỏ 2 s, rồi lại đến đèn xanh
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Định thời không dùng delay

Tự luyện tập: Playground Arduino