Освой Arduino играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
05.Control: ForLoopIteration
05.Control: Arrays
Бегущие огни
07.Display: barGraph (Световая шкала и потенциометр)
Модуль 2-цветного светодиода KY-011
Модуль 2-цветного светодиода KY-029
Семицветный светодиодный модуль KY-034
Мигать одним светодиодом не слишком интересно. В этом уроке мы рассмотрим работу с множеством светодиодов. Если проявить фантазию, то можно создавать интересные эффекты.
Сам принцип работы со светодиодами не меняется, мы также задаём номера выводом и подаём нужные сигналы. Но проблема заключается в том, что придётся писать однотипный код для каждого светодиода. И когда светодиодов наберётся большое количество и вы решите поменять логику, то придётся искать и менять код у каждого светодиода. Это не очень удобно. Поэтому для облегчения рутинной работы используют циклы, массивы, коллекции.
Для знакомства с циклом for в Arduino IDE есть пример File | Examples | 05.Control | ForLoopIteration.
Для эксперимента нам понадобятся шесть светодиодов. Соответственно, к ним нужно добавить шесть резисторов. Соединяем их как на рисунке. Задействуем цифровые выводы 2, 3, 4, 5, 6, 7.
Цель скетча - поочерёдно зажигать и гасить светодиоды в одном направлении, а затем в другом.
int timer = 100; // интервал между миганиями светодиодов
void setup() {
// проходимся в цикле по каждому светодиоду от 2 до 7 и влючаем нужный режим
for (int thisPin = 2; thisPin < 8; thisPin++) {
pinMode(thisPin, OUTPUT);
}
}
void loop() {
// опять проходимся в цикле по каждому светодиоду
for (int thisPin = 2; thisPin < 8; thisPin++) {
// включаем
digitalWrite(thisPin, HIGH);
delay(timer);
// выключаем
digitalWrite(thisPin, LOW);
}
// ещё раз проходимся в цикле, но в обратном порядке от 7 до 2
for (int thisPin = 7; thisPin >= 2; thisPin--) {
// включаем
digitalWrite(thisPin, HIGH);
delay(timer);
// выключаем
digitalWrite(thisPin, LOW);
}
}
Доказательство, что код работает.
Обращаться к каждому светодиоду можно не только по очереди в цикле, но и через массив. Использование массивов даёт больше гибкости. Посмотрим на примере File | Examples | 5.Control | Arrays. Схема остаётся прежней из предыдущего примера.
Массив объявляется с помощью квадратных скобок, а затем к переменной массива обращаются, указывая в квадратных скобках индекс массива, который начинается с 0. Таким образом, чтобы обратиться к первому элементу массива, следует писать ledPins[0] и т.д. Комментарии к скетчу смотрите в предыдущем примере.
int timer = 100;
int ledPins[] = {
2, 7, 4, 6, 5, 3
}; // массив в случайном порядке
int pinCount = 6; // количество светодиодов (размер массива)
void setup() {
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
pinMode(ledPins[thisPin], OUTPUT);
}
}
void loop() {
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
digitalWrite(ledPins[thisPin], HIGH);
delay(timer);
digitalWrite(ledPins[thisPin], LOW);
}
// loop from the highest pin to the lowest:
for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) {
digitalWrite(ledPins[thisPin], HIGH);
delay(timer);
digitalWrite(ledPins[thisPin], LOW);
}
}
Если вы замените строку int ledPins[] = {2, 7, 4, 6, 5, 3}; на int ledPins[] = {2, 3, 4, 5, 6, 7};, то получите точно такое же поведение светодиодов из предыдущего примера с циклом for, когда светодиоды загораются и гаснут по очереди. Но использование массива позволяет поменять начальное положение светодиодов, не меняя остальной код. И вы можете только в одном месте менять начальные позиции для запуска волны. Например, зададим массив через одного: {2, 4, 6, 3, 5, 7}.
Ещё один вариант бегущих по порядку огней. На этот раз уместим код в один цикл for, добавив переменную, следящую за направлением движения.
const int ARRAY_SIZE = 6;
int ledPin[] = {2, 3, 4, 5, 6, 7};
int ledDelay = 500;
int direction = 1;
int currentLed = 0;
unsigned long changeTime;
void setup() {
for (int i = 0; i < ARRAY_SIZE; i++) {
pinMode(ledPin[i], OUTPUT);
}
changeTime = millis();
}
void loop() {
if ((millis() - changeTime) > ledDelay) {
changeLed();
changeTime = millis();
}
}
void changeLed() {
// выключаем все светодиоды
for (int i = 0; i < ARRAY_SIZE; i++) {
digitalWrite(ledPin[i], LOW);
}
// включаем текущий LED
digitalWrite(ledPin[currentLed], HIGH);
// увеличиваем значение
currentLed += direction;
// меняем направление, если достигли конца
if (currentLed == ARRAY_SIZE - 1) {
direction = -1;
}
if (currentLed == 0) {
direction = 1;
}
}
Три примера показывают, что реализовать проект можно разными способами. Не существуют универсальных решений, каждый решает свою задачу индивидуально, опираясь на свой опыт и практику.
Рассмотрим пример с использованием светодиодной шкалы и потенциометра - Examples | 07.Display | barGraph. Если световой шкалы нет, то замените на 10 обычных светодиодов.
Изменяя вручную напряжение при помощи потенциометра, мы будем выводить информацию на световую шкалу.
Добавим на схему потенциометр. Средняя ножка ведёт на аналоговый вывод A0, а остальные две на 5 V и GND.
// константы
const int analogPin = A0; // порт для потенциометра
const int ledCount = 10; // число светодиодов на светодиодной шкале
int ledPins[] = {
2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; // массив портов, к которым привязаны светодиоды
void setup() {
// проходим через все элементы массива и устанавливаем режим для вывода
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT);
}
}
void loop() {
// считываем сигнал с потенциометра
int sensorReading = analogRead(analogPin);
// трансформируем результат в диапазон от 0 до 10 (по числу светодиодов)
int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
// проходим через массив светодиодов
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
// если индекс элемента массива меньше чем ledLevel,
// включаем порт для данного элемента:
if (thisLed < ledLevel) {
digitalWrite(ledPins[thisLed], HIGH);
}
// Выключаем все порты, которые выше чем ledLevel:
else {
digitalWrite(ledPins[thisLed], LOW);
}
}
}
Данный пример интересен функцией map(), предназначенной для пропорционального перевода значений одного диапазона в значения другого диапазона. Мы знаем, что потенциометр может выводить результаты от 0 до 1023, а у нас всего десять светодиодов. Функция нам и поможет в преобразовании.
int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
Все значения будут равномерно распределены от 0 до 10 (приблизительно 102 единицы потенциометра на одну единицу). Представим себе, что у нас потенциометр показывает значение 110 единиц, что соответствует значению 1 после применения функции. Первый светодиод в массиве имеет значение 0, т.е. меньше 1. Первый светодиод загорится, а остальные погаснут (если горели до этого). Поворачивая ручку потенциометра, мы увеличиваем значения и соответственно увеличиваем число включённых светодиодов. Поворачивая ручку потенциометра в обратную сторону, мы уменьшаем число включённых светодиодов. Чтобы следить за результатами, добавьте в код наблюдение за последовательным портом Serial
int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
Serial.println(sensorReading);
delay(1);
...
Демонстрация результата.
Модуль выглядит как один светодиод, но на самом деле состоит из двух светодиодов разных цветов (красный и зелёный). и имеет три вывода. Применяется для индикации режима работы прибора, показа фаз протекания контролируемого процесса и позволяет экономить площадь передней панели прибора. Красно-зелёный светодиод имеет четыре состояния: красное свечение, зелёное, оранжевое и выключен. Оранжевое свечение будет при одновременном включении красного и зелёного полупроводников. Пример реализации: зелёный свет – прибор готов к работе, красный – ожидание, оранжевый - промежуточный.
Контакт S предназначен для соединения с общим проводом схемы, отрицательный полюс питания, средний контакт – красный источник света. При работе с модулем следует использовать резисторы (напр, 330Ω).
На практике при одновременном включении не выводится чистый оранжевый цвет, нужно немного поиграться с разными значениями напряжения.
Скетч, в котором используем все доступные значения.
int redPin = 9; // pin for red led
int greenPin = 10; // pin for green led
int val;
void setup() {
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
}
void loop() {
analogWrite(redPin, 255);
analogWrite(greenPin, 0);
delay(1000);
analogWrite(redPin, 255);
analogWrite(greenPin, 120);
delay(1000);
analogWrite(redPin, 0);
analogWrite(greenPin, 255);
delay(1000);
}
Модуль KY-029 с общим катодом похож на модуль KY-011, только вместо светодиода на 5 мм используется двухцветный светодиод на 3 мм (зелёный и красный).
У модуля три вывода: - (GND) — общий катод светодиодов, средний контакт — анод (+) красного светодиода, «S» — анод (+) зелёного светодиода.
KY-029 | Arduino
----------------
- | GND
N/A | D
S | D
Скетч используйте от модуля KY-011.
Модуль состоит из печатной платы, трёх выводов, сопротивления 10кОм (код SMD-резистора 103) и семицветного светодиода.
Семицветный мигающий светодиод имеет всего два контакта (плюс и минус). Достаточно добавить источник питания и светодиодный модуль будет мигать всеми цветами радуги в разных комбинациях. Происходит эта магия за счёт миниатюрной микросхемы, которая встроена в светодиод.
Программирования не требуется. Просто подключаем вывод - к GND и S к 5V. При желании можете подключить не к питанию, а к цифровому пину Arduino и управлять включением и выключением светодиода (например, скетч Blink).
Входит в состав набора Набор из 37 датчиков