Делаем светофор с Arduino

В продолжение курса по обучению работы с микроконтроллером Arduino собирём трёх-цветный светофор с несколькими режимами работы. Научимся управлять сразу несколькими светодиодами, а также реализуем задержку в неблокирующем режиме (без использования функции delay).

В продолжение нашего знакомства с Arduino сегодня мы рассмотрим следующий простейший пример – светофор, какой мы видим каждый день на дорогах, который будет включаться, и выключаться по нажатию кнопки.

Необходимые компоненты

  • 3 светодиода (зелёный, жёлтый и красный)
  • Push-кнопка
  • 3 резистора на 220 [Ом]
  • Резистор на 10 [кОм]

Сбор схемы

Соединяем 13 пин Arduino с длинной ногой зелёного светодиода, а короткую ногу через резистор в 220 [Ом] соединяем с “землёй”. Аналогично соединяем жёлтый светодиод через 12 пин и красный через 11 пин. 7 пин через резистор 10 кОм подключим к “земле” и к кнопке.

Схема, необходимая для работы светофора собрана, теперь необходимо подключить кнопку, для управления им.

При установке кнопки есть некоторая хитрость – кнопку надо устанавливать на разделительную полосу между двумя половинками брэдборда.

Теперь подключаем кнопку. Тут всё очень просто – кнопка проводит в обоих направлениях, в отличие от различных диодов, поэтому нет никакой разницы, какой из контактов будет соединён с землёй. Соедините один контакт кнопки с портом №7 Arduino  и этот же контакт соедините через резистор в 10 [кОм] с Землёй, а другой с питанием в 5 [В] – рельса со значком +.

ВАЖНО!! Во всех схемах Земля должна быть всегда одна – для всех подключаемых элементов.

Сборка на этом закончена! Приступаем к программированию Arduino!

Программируем Arduino

// Задаём номера портов для светодиодов
int GPin = 13; // Зелёный
int YPin = 12; // Жёлтый
int RPin = 11; // Красный
int switchPin = 7; // Порт кнопки
boolean lastButton = LOW; // Устанавливаем последнее значение кнопки - выключено
boolean currentButton = LOW; // Устанавливаем текущее значение кнопки - включено
boolean ledOn = false; // Состояние светофора: false - выключен (мигает жёлтый), true - включен
boolean yellowOn = LOW; // Мигающий жёлтый.
unsigned long loopTime; // Вспомогающая переменная для цикла
unsigned long currentTime; // Переменная хранящая текущее значение времени

void setup() {
    // Устанавливаем 3 порта как выход для светодиодов и один как вход для отслеживания кнопки
    pinMode(GPin, OUTPUT);
    pinMode(YPin, OUTPUT);
    pinMode(RPin, OUTPUT);
    pinMode(switchPin, INPUT);
    currentTime = millis();
    loopTime = currentTime;
}

// Функция для лучшего отрабатывания нажатия на кнопку - ждёт установившегося значения, а затем передаёт его в программу.
boolean debounce(boolean last)
{
    boolean current = digitalRead(switchPin);
    if(last != current)
    {
        delay(5);
        current = digitalRead(switchPin);
    }
    return current;
}

void loop() {
    currentButton = debounce(lastButton);
    if(lastButton == LOW && currentButton == HIGH) // При нажатии на кнопку включаем\выключаем светофор
    {
        ledOn = !ledOn;
    }
    lastButton = currentButton;
    currentTime = millis();

    // Цикл действий при выключенном светофоре
    if(currentTime >= (loopTime + 500) && ledOn == false)
    {
        yellowOn = !yellowOn; // Инвертируем значение переменной.
        digitalWrite(GPin, LOW);
        digitalWrite(YPin, yellowOn);
        digitalWrite(RPin, LOW);
        loopTime = currentTime;
    }

    // Цикл действий при включенном светофоре
    if(ledOn == true) {
        // Горит зелёный
        if(currentTime >= loopTime && currentTime < (loopTime + 10000)) {                     
            digitalWrite(GPin, HIGH);
            digitalWrite(YPin, LOW);
            digitalWrite(RPin, LOW);
        }
// Зелёный начинает мигать     

        if(currentTime >= (loopTime + 10000) && currentTime < (loopTime + 10500)) {
            digitalWrite(GPin, LOW);
        }
        if(currentTime >= (loopTime + 10500) && currentTime < (loopTime + 11000)) {
            digitalWrite(GPin, HIGH);
        }
        if(currentTime >= (loopTime + 11000) && currentTime < (loopTime + 11500)) {
            digitalWrite(GPin, LOW);
        }
        if(currentTime >= (loopTime + 11500) && currentTime < (loopTime + 12000)) {
            digitalWrite(GPin, HIGH);
        }
        if(currentTime >= (loopTime + 12000) && currentTime < (loopTime + 12500)) {
            digitalWrite(GPin, LOW);
        }
        if(currentTime >= (loopTime + 12500) && currentTime < (loopTime + 13000)) {
            digitalWrite(GPin, HIGH);
        }
        if(currentTime >= (loopTime + 13000) && currentTime < (loopTime + 13500)) {
            digitalWrite(GPin, LOW);
        }
        if(currentTime >= (loopTime + 13500) && currentTime < (loopTime + 1400)) {
            digitalWrite(GPin, HIGH);
        }
        if(currentTime >= (loopTime + 14000) && currentTime < (loopTime + 14300)) {
            digitalWrite(GPin, LOW);
        }
// Загорается жёлтый 
        if(currentTime >= (loopTime + 14300) && currentTime < (loopTime + 17500)) {
            digitalWrite(YPin, HIGH);
        }
// Загорается красный 
        if(currentTime >= (loopTime + 17500) && currentTime < (loopTime + 27500)) {
            digitalWrite(YPin, LOW);
            digitalWrite(RPin, HIGH);
        }
// Загорается красный с жёлтым     
        if(currentTime >= (loopTime + 27500) && currentTime < (loopTime + 30500)) {
            digitalWrite(YPin, HIGH);
        }
// Загорается зелёный 
        if(currentTime >= (loopTime + 30500)) {
            digitalWrite(GPin, HIGH);
            digitalWrite(YPin, LOW);
            digitalWrite(RPin, LOW);
            loopTime = currentTime;
        }
    }

}

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

Конечно, вместо столько сложного метода мы могли бы использовать простую задержку методом delay(), однако в использовании функции delay() есть один очень большой минус, который не должна обладать наша программа. Во время паузы – процессор не реагирует на другие операции, таким образом, во время задержки, например, на горение красного светодиода, сколько кнопку не нажимай – светофор не выключиться. Чтобы выключить светофор – вам придётся попадать по кнопке в тот момент, когда изменяется состояние светодиода, что, согласитесь, очень неудобно. Поэтому мы используем метод millis(), которые возвращает количество миллисекунд, прошедшее с момента запуска приложения, и отсчитываем нужные нам интервалы времени.

Ну что, сохраняем нашу программу (скетч) и загружаем её в Arduino. Смотрим что у нас получилось.

Задавайте любые, интересующие Вас, вопросы, а я отвечу на них в комментариях к этому посту. До скорых встреч!

6 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Владимир
10 лет назад

Подскажите, почему у меня все время горит зеленый?
где ошибка? 🙂

Владимир
Ответить на  Владимир
10 лет назад

Кстати, во время компиляции выдает ошибку на последнюю фигурную скобку
error: expected declaration before ‘}’ token

Владимир
Ответить на  Владимир
10 лет назад

у вас просто последние строки закоментированы

Вася Пупкин
8 лет назад

Как вариант кнопку можно повесить на внешнее прерывание, тогда нажатие во время паузы Delay() будет отрабатываться правильно.