В этом эксперименте мы заставляем огонёк бежать по светодиодной шкале.
СПИСОК ДЕТАЛЕЙ ДЛЯ ЭКСПЕРИМЕНТА
- 1 плата Arduino Uno;
- 1 беспаечная макетная плата;
- 1 светодиодная шкала;
- 10 резисторов номиналом 220 Ом;
- 11 проводов «папа-папа».
ПРИНЦИПИАЛЬНАЯ СХЕМА
СХЕМА НА МАКЕТНОЙ ПЛАТЕ
ОБРАТИТЕ ВНИМАНИЕ
- Обратите внимание, что в данном эксперименте резисторы установлены между катодами и землей в отличие от эксперимента пульсар;
- Мы подключаем светодиоды к цифровым портам, начиная с порта 2. Мы можем использовать порты 0 и 1, но они являются каналами передачи данных последовательного порта и для каждой перепрошивки платы придется отключать устройства, подключенные к ним.
СКЕТЧ
скачать скетч для Arduino IDE
// светодиодная шкала подключена к группе пинов расположенных
// подряд. Даём понятные имена первому и последнему пинам
#define FIRST_LED_PIN 2
#define LAST_LED_PIN 11
void setup()
{
// в шкале 10 светодиодов. Мы бы могли написать pinMode 10
// раз: для каждого из пинов, но это бы раздуло код и
// сделало его изменение более проблематичным.
// Поэтому лучше воспользоваться циклом. Мы выполняем
// pinMode для (англ. for) каждого пина (переменная pin)
// от первого (= FIRST_LED_PIN) до последнего включительно
// (<= LAST_LED_PIN), всякий раз продвигаясь к следующему
// (++pin увеличивает значение pin на единицу)
// Так все пины от 2-го по 11-й друг за другом станут выходами
for (int pin = FIRST_LED_PIN; pin <= LAST_LED_PIN; ++pin)
pinMode(pin, OUTPUT);
}
void loop()
{
// получаем время в миллисекундах, прошедшее с момента
// включения микроконтроллера
unsigned int ms = millis();
// нехитрой арифметикой вычисляем, какой светодиод
// должен гореть именно сейчас. Смена будет происходить
// каждые 120 миллисекунд. Y % X — это остаток от
// деления Y на X; плюс, минус, скобки — как в алгебре.
int pin = FIRST_LED_PIN + (ms / 120) % 10;
// включаем нужный светодиод на 10 миллисекунд, затем —
// выключаем. На следующем проходе цикла он снова включится,
// если гореть его черёд, и мы вообще не заметим отключения
digitalWrite(pin, HIGH);
delay(10);
digitalWrite(pin, LOW);
}
ПОЯСНЕНИЯ К КОДУ
- С помощью выражения
for мы организуем цикл со счетчиком. В данном случае для настройки портов на выход. Чтобы сделать такой цикл, нужно:
- Инициализировать переменную-счетчик, присвоив ей первоначальное значение. В нашем случае:
int pin = FIRST_LED_ PIN;
- Указать условие, до достижения которого будет повторяться цикл. В нашем случае:
pin <= LAST_LED_ PIN;
- Определить правило, по которому будет изменяться счетчик. В нашем случае
++pin (см. ниже об операторе ++ ).
- Например, можно сделать цикл
for (int i = 10; i > 0; i = i - 1) . В этом случае:
- Переменной
i присваивается значение 10;
- Это значение удовлетворяет условию
i > 0 ;
- Поэтому блок кода, помещенный в цикл, выполняется первый раз;
- Значение
i уменьшается на единицу, согласно заданному правилу, и принимает значение 9;
- Блок кода выполняется второй раз;
- Всё повторяется снова и снова вплоть до значения
i равного 0;
- Когда
i станет равна 0, условие i > 0 не выполнится, и выполнение цикла закончится;
- Контроллер перейдет к коду, следующему за циклом
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 .
- Не меняя местами провода, измените программу так, чтобы огонёк бегал в обратном направлении.
С оригиналом статьи вы можете ознакомиться на сайте Amperka.ru
ЭКСПЕРИМЕНТ 6 | ОГЛАВЛЕНИЕ | ЭКСПЕРИМЕНТ 8 |