Урок 7. Бегущий огонек


В этом эксперименте мы заставляем огонёк бежать по светодиодной шкале.

Список деталей для эксперимента

Принципиальная схема

Урок 7. Бегущий огонек. Принципиальная схема

Схема на макетке

Урок 7. Бегущий огонек. Схема на макетке

Обратите внимание

  • Обратите внимание, что в данном эксперименте резисторы установлены между катодами и землей в отличие от эксперимента пульсар.
  • Мы подключаем светодиоды к цифровым портам, начиная с порта 2. Мы можем использовать порты 0 и 1, но они являются каналами передачи данных последовательного порта и для каждой перепрошивки платы придется отключать устройства, подключенные к ним.

Скетч

  1.     // светодиодная шкала подключена к группе пинов расположенных
  2.     // подряд. Даём понятные имена первому и последнему пинам
  3.     #define FIRST_LED_PIN  2
  4.     #define LAST_LED_PIN   11
  5.  
  6.     void setup()
  7.     {
  8.       // в шкале 10 светодиодов. Мы бы могли написать pinMode 10
  9.       // раз: для каждого из пинов, но это бы раздуло код и
  10.       // сделало его изменение более проблематичным.
  11.       // Поэтому лучше воспользоваться циклом. Мы выполняем
  12.       // pinMode для (англ. for) каждого пина (переменная pin)
  13.       // от первого (= FIRST_LED_PIN) до последнего включительно
  14.       // (<= LAST_LED_PIN), всякий раз продвигаясь к следующему
  15.       // (++pin увеличивает значение pin на единицу)
  16.       // Так все пины от 2-го по 11-й друг за другом станут выходами
  17.       for (int pin = FIRST_LED_PIN; pin <= LAST_LED_PIN; ++pin)
  18.         pinMode(pin, OUTPUT);
  19.     }
  20.  
  21.     void loop()
  22.     {
  23.       // получаем время в миллисекундах, прошедшее с момента
  24.       // включения микроконтроллера
  25.       unsigned int ms = millis();
  26.       // нехитрой арифметикой вычисляем, какой светодиод
  27.       // должен гореть именно сейчас. Смена будет происходить
  28.       // каждые 120 миллисекунд. Y % X — это остаток от
  29.       // деления Y на X; плюс, минус, скобки — как в алгебре.
  30.       int pin = FIRST_LED_PIN + (ms / 120) % 10;
  31.       // включаем нужный светодиод на 10 миллисекунд, затем —
  32.       // выключаем. На следующем проходе цикла он снова включится,
  33.       // если гореть его черёд, и мы вообще не заметим отключения
  34.       digitalWrite(pin, HIGH);
  35.       delay(10);
  36.       digitalWrite(pin, LOW);
  37.     }

Пояснения к коду

  • С помощью выражения for мы организуем цикл со счетчиком. В данном случае для настройки портов на выход. Чтобы сделать такой цикл, нужно:
  • Инициализировать переменную-счетчик, присвоив ей первоначальное значение. В нашем случае: int pin = FIRST_LED_PIN
  • Указать условие, до достижения которого будет повторяться цикл. В нашем случае: pin <= LAST_LED_PIN
  • Определить правило, по которому будет изменяться счетчик. В нашем случае ++pin (см. ниже об операторе ++).
  • Например, можно сделать цикл for (int i = 10; i > 0; i = i - 1). В этом случае:
  1. Переменной i присваивается значение 10
  2. Это значение удовлетворяет условию i > 0
  3. Поэтому блок кода, помещенный в цикл, выполняется первый раз
  4. Значение i уменьшается на единицу, согласно заданному правилу, и принимает значение 9
  5. Блок кода выполняется второй раз.
  6. Всё повторяется снова и снова вплоть до значения i равного 0
  7. Когда i станет равна 0, условие i > 0 не выполнится, и выполнение цикла закончится
  8. Контроллер перейдет к коду, следующему за циклом for
  • Помещайте код, который нужно зациклить, между парой фигурных скобок {}, если в нем больше одной инструкции.
  • Переменная-счетчик, объявляемая в операторе for, может использоваться внутри цикла. Например, в данном эксперименте pin последовательно принимает значения от 2 до 11 и, будучи переданной в pinMode, позволяет настроить 10 портов одной строкой, помещенной в цикл.
  • Переменные-счетчики видны только внутри цикла. Т.е. если обратиться к pin до или после цикла, компилятор выдаст ошибку о необъявленной переменной.
  • Конструкция i = i - 1 в пояснении выше не является уравнением! Мы используем оператор присваивания = для того, чтобы в переменную i поместить значение, равное текущему значению i, уменьшенному на 1.
  • Выражение ++pin — это т.н. оператор инкремента, примененный к переменной pin. Эта инструкция даст тот же результат, что pin = pin + 1
  • Аналогично инкременту работает оператор декремента --, уменьшающий значение на единицу. Подробнее об этом в статье про арифметические операции.
  • Тип данных unsigned int используют для хранения целых чисел без знака, т.е. только неотрицательных. За счет лишнего бита, который теперь не используется для хранения знака, мы можем хранить в переменной такого типа значения до 65 535.
  • Функция millis возвращает количество миллисекунд, прошедших с момента включения или перезагрузки микроконтроллера. Здесь мы используем ее для отсчета времени между переключениями светодиодов.
  • С помощью выражения (ms / 120) % 10 мы определяем, который из 10 светодиодов должен гореть сейчас. Перефразируя, мы определяем какой отрезок длиной в 120 мс идет сейчас и каков его номер внутри текущего десятка. Мы добавляем порядковый номер отрезка к номеру того порта, который в текущем наборе выступает первым.
  • То, что мы гасим светодиод с помощью digitalWrite(pin, LOW) всего через 10 мс после включения не заметно глазу, т.к. очень скоро будет вновь вычислено, какой из светодиодов включать, и он будет включен — только что погашенный или следующий.

Вопросы для проверки себя

  • Почему в данном эксперименте мы подключаем светодиодную шкалу, не используя транзистор?
  • Если бы мы включали светодиоды только на портах 5, 6, 7, 8, 9, что нужно было бы изменить в программе?
  • С помощью какой другой инструкции можно выполнить действие, эквивалентное ++pin?
  • В чем разница между переменными типов int и unsigned int?
  • Что возвращает функция millis()?
  • Как в данном эксперименте мы вычисляем номер порта, на котором нужно включить светодиод?

Задания для самостоятельного решения

  • Измените код так, чтобы светодиоды переключались раз в секунду.
  • Не выключая порты, сделайте так, чтобы огонёк бежал только по средним четырем делениям шкалы.
  • Переделайте программу так, чтобы вместо int pin = FIRST_LED_PIN + (ms / 120) % 10 перемещением огонька управлял цикл for
  • Не меняя местами провода, измените программу так, чтобы огонёк бегал в обратном направлении.
Источник: 

wiki.amperka.ru