Светофор из трёх светодиодов

Сложность
Компоненты
Arduino Unoсветодиоды: красный, жёлтый, зелёный3 резистора 220 Оммакетная платапровода
Навыки
GPIOdigitalWritedelayфункциицикл for

Коротко: собрал светофор из трёх светодиодов и написал для него две версии скетча. Первая переключает сигналы по кругу: красный, красный с жёлтым, зелёный, жёлтый. Вторая перед жёлтым мигает зелёным — как настоящий светофор.

Зачем

Классический первый проект — мигнуть одним светодиодом. Я решил сразу взять три: задача та же, но появляется логика. Нужно следить, какой сигнал горит, какой погасить и сколько ждать.

Цель — разобраться с цифровыми выходами: как сказать пину «работай на выход» и как подать на него напряжение из кода.

Что понадобилось

  • плата Arduino;
  • три светодиода: красный, жёлтый и зелёный;
  • три резистора на 220 Ом, по одному на каждый светодиод;
  • макетная плата и провода.

Резистор ограничивает ток. Без него светодиод получит больше тока, чем рассчитан, и быстро выйдет из строя — а заодно нагрузит пин платы.

Каждый светодиод подключается одинаково: пин → резистор → длинная ножка светодиода (анод) → короткая ножка (катод) → GND.

Сигнал Пин Резистор
Красный 11 220 Ом
Жёлтый 10 220 Ом
Зелёный 9 220 Ом

Как собирал

Скетч для Arduino состоит из двух функций. setup() выполняется один раз при включении платы, loop() — бесконечно по кругу. Для бэкендера это похоже на воркер: инициализация, а потом вечный цикл обработки.

Светофор на макетке

Версия 1: переключение сигналов

Сначала объявляю номера пинов константами и в setup() переключаю их в режим выхода:

const int RED = 11;
const int YELLOW = 10;
const int GREEN = 9;

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(YELLOW, OUTPUT);
  pinMode(GREEN, OUTPUT);
}

Дальше в loop() описываю четыре фазы светофора. digitalWrite(pin, HIGH) подаёт на пин напряжение — светодиод загорается, LOW — гаснет. delay() останавливает программу на указанное число миллисекунд:

void loop() {
  // красный
  digitalWrite(RED, HIGH);
  digitalWrite(YELLOW, LOW);
  digitalWrite(GREEN, LOW);
  delay(5000);

  // красный + жёлтый
  digitalWrite(RED, HIGH);
  digitalWrite(YELLOW, HIGH);
  delay(1000);

  // зелёный
  digitalWrite(RED, LOW);
  digitalWrite(YELLOW, LOW);
  digitalWrite(GREEN, HIGH);
  delay(5000);

  // жёлтый
  digitalWrite(GREEN, LOW);
  digitalWrite(YELLOW, HIGH);
  delay(1000);
}

Обратите внимание: пин сохраняет состояние, пока его явно не поменяешь. Поэтому в каждой фазе нужно не только включить нужные светодиоды, но и выключить лишние. В фазе «жёлтый» красный уже погашен предыдущей фазой, а после неё цикл начинается заново и снова зажигает красный.

Версия 2: мигающий зелёный

Первая версия работает, но у неё два недостатка. Настоящий светофор перед жёлтым несколько раз мигает зелёным, а у меня зелёный гаснет внезапно. И код однообразный: каждая фаза — это три почти одинаковых вызова digitalWrite, в которых легко забыть погасить лишний светодиод.

Начну со второй проблемы. Выношу установку сигналов в функцию setLights(): она принимает состояние всех трёх светодиодов сразу, поэтому каждая фаза описывается одной строкой и ни один светодиод не останется гореть по ошибке. Мигание описываю циклом for:

const int RED = 11;
const int YELLOW = 10;
const int GREEN = 9;

const int BLINK_COUNT = 3;    // сколько раз мигает зелёный
const int BLINK_DELAY = 500;  // полпериода мигания, мс

void setLights(bool red, bool yellow, bool green) {
  digitalWrite(RED, red ? HIGH : LOW);
  digitalWrite(YELLOW, yellow ? HIGH : LOW);
  digitalWrite(GREEN, green ? HIGH : LOW);
}

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(YELLOW, OUTPUT);
  pinMode(GREEN, OUTPUT);
}

void loop() {
  // красный
  setLights(true, false, false);
  delay(5000);

  // красный + жёлтый
  setLights(true, true, false);
  delay(1000);

  // зелёный
  setLights(false, false, true);
  delay(5000);

  // мигающий зелёный
  for (int i = 0; i < BLINK_COUNT; i++) {
    setLights(false, false, false);
    delay(BLINK_DELAY);
    setLights(false, false, true);
    delay(BLINK_DELAY);
  }

  // жёлтый
  setLights(false, true, false);
  delay(1000);
}

Разберу, что изменилось:

  • setLights(red, yellow, green) читается как состояние светофора: setLights(true, true, false) — горят красный и жёлтый. Раньше то же самое занимало три строки.
  • Цикл for повторяет пару «погасить — зажечь» BLINK_COUNT раз. Каждый проход занимает 2 × BLINK_DELAY, то есть мигание длится 3 × 1000 мс = 3 секунды.
  • Константы BLINK_COUNT и BLINK_DELAY вынесены наверх. Чтобы зелёный мигал быстрее или дольше, достаточно поменять одно число.

Цикл начинается с выключения, потому что перед ним зелёный уже горит пять секунд. Если начать с включения, первое мигание просто продлит зелёный на полсекунды, и глаз его не заметит.

Светофор на макетке

Попробовать в симуляторе