Освой Arduino играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
01.Basics: Fade
03.Analog: Fading
Мигалка
PWM на любом выводе
Продолжим изучение цифровых выводов. Напомню, что есть два типа выводов: цифровые и аналоговые. Цифровые выводы в свою очередь могут быть двух видов: c PWM и без них. PWM-выводы помечены символом тильды (~): ~3, ~5, ~6, ~9, ~10, ~11 и используют широтно-импульсную модуляцию (ШИМ) или по английски PWM. Сигнал ШИМ используется для управления устройствами (электродвигатели), которым требуется аналоговый сигнал.
Для плавного изменения сигнала используют вызов функции analogWrite(), указав в параметре значение от 0 до 255.
Рассмотрим пример Fade, который поставляется с Arduino IDE (File | Examples| 01.Basics | Fade). Скетч позволяет делать плавное затухание светодиода с использованием цифрового PWM-вывода.
Сама конструкция на плате совпадает с примером мигания внешнего светодиода через резистор и провода.
Когда я только начинал изучать Arduino, то допустил ошибку - запустив скетч на плате, я не увидел плавного затухания. В моём случае светодиод продолжал мигать странным образом. Расстроившись, я стал читать ответы на форумах и случайно перечитал ответ на свой вопрос. Там я заметил ремарку, на которую не обратил внимание в первый раз. Оказывается, нужно было соединяться с выводом, который помечен символом тильды (~). На Arduino UNO вывод 12 тильдой не был отмечен. Я быстро перекинул перемычку на вывод с меткой 10 и все заработало. Кстати, в комментариях к примеру уже даны необходимые пояснения, но раньше их не было или я не обратил на них внимания.
Теперь рассмотрим код для затухания. Он совсем несложный. Комментарии даны с переводом.
/*
Fade (Затухание)
Пример показывает, как управлять затуханием светодиода на выводе 9,
используя функцию analogWrite()
Функция analogWrite() использует PWM (ШИМ), таким образом, если вы хотите изменить вывод,
то используйте подходящие пины, помеченные символом "~" (тильда): ~3, ~5, ~6, ~9, ~10, ~11.
*/
int led = 9; // PWM-вывод для светодиода
int brightness = 0; // начальная яркость светодиода
int fadeAmount = 5; // величина изменения шага яркости светодиода
void setup() {
// используем вывод 9 для операции вывода
pinMode(led, OUTPUT);
}
void loop() {
// устанавливаем яркость у светодиода на выводе 9
analogWrite(led, brightness);
// изменяем яркость в цикле, прибавляя заданную величину
brightness = brightness + fadeAmount;
// меняем порядок затухания на обратный при достижении минимальной или максимальной яркости
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount;
}
// делаем паузу 30 миллисекунд для лучшего эффекта затухания
delay(30);
}
Есть ещё один похожий пример в File | 03.Analog | Fading. Только на этот раз вместо автоматического увеличения значения яркости в главной цикле-функции loop() используются два цикла for. Результат такой же.
int ledPin = 9; // светодиод на выводе 9
void setup() {
// ничего не устанавливаем при запуске
}
void loop() {
// увеличиваем яркость от 0 до максимального значения по 5 единиц
for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
analogWrite(ledPin, fadeValue);
// делаем паузу 30 миллисекунд для лучшего эффекта затухания
delay(30);
}
// уменьшаем яркость от 255 до 0 по 5 единиц
for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
analogWrite(ledPin, fadeValue);
delay(30);
}
}
Усложним макет. Возьмём ещё один светодиод другого цвета (у меня получилось красный и синий), резистор и соберём аналогичную схему на этой же макетной плате, подключив новый светодиод к выводу номер 3 и другому входу GND (ищите у другого края платы).
Отредактируем программу таким образом, чтобы оба светодиода мигали в противофазу: первый выключен, второй горит максимально ярко и наоборот.
У меня получился следующий код.
/*
Мигалка
Если этот код работает, его написал Александр Климов,
а если нет, то не знаю, кто его писал.
*/
int led_9 = 9; // контакт 9
int led_3 = 3; // контакт 3
int brightness = 0; // минимальная яркость
int fadeAmount = 5; // величина изменения яркости за шаг
void setup() {
// два контакта в режиме вывода
pinMode(led_9, OUTPUT);
pinMode(led_3, OUTPUT);
}
void loop() {
// у первого контакта минимальное значение, у второго - максимальное
analogWrite(led_9, brightness);
analogWrite(led_3, 255 - brightness);
// остальной код без изменений
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
Запустив проект, мы получим два светодиода, мигающих поочерёдно. Напомнило мне мигалку. Осталось подключить сирену. Надо запомнить этот урок и реализовать недостающую функциональность.
При желании можно реализовать широтно-импульсную модуляцию на любом выводе, написав чуть больше кода. Создадим глобальную переменную pwm, в которой будем сохранять текущее значение уровня заполнения в процентах. Дальше мы включаем "высокое" и "низкое" состояние вывода, в соответствии с этим значением - когда одно значение велико, второе, наоборот, мало. В цикле for повторим участок кода 1000 раз - без него светодиод менял бы яркость слишком быстро.
Если загрузить скетч, мы увидим плавно увеличивающий яркость светодиод. Но не стоит использовать код в реальных примерах. Процессор занят только переключением светодиода, любая другая задача нарушит согласованность временных интервалов.
int led = 13;
int pwm = 0;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
for (int i = 0; i < 1000; i++) {
digitalWrite(led, HIGH);
delayMicroseconds(pwm);
digitalWrite(led, LOW);
delayMicroseconds(100 - pwm);
}
pwm += 1;
if (pwm > 100) pwm = 0;
}
Управляем яркостью светодиода с помощью двух кнопок