
Общие сведения:
В этом уроке мы создадим тематическое устройство, которое можно использовать как украшение стола, а именно Arduino-тыкву, реагирующую на движение в зоне видимости датчика расстояния.
У датчика существует 2 зоны чувствительности (в зависимости от расстояния от датчика), попав в каждую из которых будет выполняться светозвуковая анимация.
Видео:
Нам понадобится:
- 1х Arduino / Piranha UNO;
- 1х Battery Shield;
- 1х Trema Shield;
- 4х Trema-модуль Адресный светодиод NeoPixel;
- 1х датчика расстояния HC-SR04;
- 1х MP3-плеер;
- 1х Карта памяти MicroSD;
- 1х Динамик;
- 1х ПВХ-конструктор;
- 1х Тыква;
Для реализации проекта нам необходимо установить библиотеки:
- DFPlayer Mini mp3 Arduino Library V1.3 — для работы с плеером;
- iarduino_HC_SR04_int — для работы с ультразвуковыми датчиками расстояния;
- iarduino_NeoPixel — для работы с адресными светодиодами NeoPixel;
О том, как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Описание работы устройства:
После подачи питания Arduino-тыква готова к работе.
Для того, чтобы включить анимацию, достаточно поднести руку к датчику на одно из двух указанных расстояний.
Схема сборки:
Arduino / Piranha UNO:

Batery Shield:
Установите Battery Shield на Arduino / Piranha UNO:
Во время установки Battery Shield должен быть в выключенном состоянии.

Trema Shield:
На Battery Shield установите Trema Shield:

MP3-плеер:
Подключите MP3-плеер к Trema Shield и динамик к MP3-плееру:

Так как выводы 0 и 1 зарезервированы под RX и TX, перед загрузкой скетча необходимо отключить плеер от платы, а после загрузки и перед использованием подключить обратно.
Датчик расстояния
Подключите датчик расстояния HC-SR04 к Trema Shield:

Адресные светодиоды:
Подключите адресные светодиоды NeoPixel к Trema Shield:

Все используемые в уроке Trema-модули NeoPixel соединены друг c другом, а первый модуль можно подключить к любому выводу Arduino. Номер вывода указывается в скетче (в примере используется вывод D5). Чем больше модулей в цепи, тем больше тока она потребляет, поэтому в схеме используется стабилизированный источник питания Battery Shield на 5В постоянного тока.
Код программы (скетч):
#include <DFRobotDFPlayerMini.h> // подключаем библиотеку для работы с MP3-плеером
#include <iarduino_NeoPixel.h> // подключаем библиотеку для работы со светодиодами NEoPixel
#include <iarduino_HC_SR04_int.h> // подключаем библиотеку для работы с датчиком расстояния HC-SR04
DFRobotDFPlayerMini myDFPlayer; // объявляем объект myDFPlayer для работы с плеером
uint8_t neo_pin = 5; // указываем вывод, к которому подключены светодиоды NeoPixel
uint16_t modul_number = 4; // указываем количество модулей в цепи
iarduino_NeoPixel led(neo_pin, modul_number * 4 ); // объявляем объект led для работы со светодиодами NeoPixel
iarduino_HC_SR04_int sensor(3, 2); // объявляем объект sensor для работы с датчиком расстояния HC-SR04
uint8_t j; // Объявляем переменную для хранения значения сдвига спектра цветов для всех светодиодов (от 0 до 255)
uint8_t r, g, b; // Объявляем переменную для хранения цветов RGB для каждого светодиода
uint32_t timer1, timer2; // счётчики времени при срабатывании анимации
uint32_t timer3; // счётчик времени при включении светодиодной подсветки тыквы
uint32_t hcsr_waiting_time_far = 600000; // время ожидания повтора анимации ДВИЖЕНИЕ ВДАЛЕКЕ
uint32_t hcsr_waiting_time_near = 60000; // время ожидания повтора анимации ДВИЖЕНИЕ ВБЛИЗИ
uint32_t action_time = 10000; // время работы анимации
uint8_t flg_near, flg_far; // флаги для включения анимации
uint8_t rev_flg; // флаг включения реверса при счёте
uint8_t p; // переменная для хранения номера светодиода при сдвиге
uint8_t l; // переменная для хранения значения яркости светодиодов
void setup() {
Serial.begin(9600); // инициируем работу Монитора последовательного порта на скорости 9600бод
myDFPlayer.begin(Serial); // указываем последовательный порт для общения с MP3-плеером
led.begin(); // инициализируем адресные светодиоды
led.setColor(NeoPixelAll, 0, 0, 0); // указываем всем светодиодам погаснуть
led.write(); // выключаем светодиоды
randomSeed(analogRead(0)); // инициируем генератор псевдослучайных чисел
sensor.distance(); // запрашиваем значение расстояния
delay(500); // задержка 0.5сек
}
void loop() {
//====================================================================//
//====================================================================//
if (sensor.distance() >= 1 && sensor.distance() <= 15) { // Проверяем, если расстояние до препятствия от 1 до 15см, то
if(millis() > timer1 + hcsr_waiting_time_near || flg_near ==0){ // проверяем, прошло ли заданное время после последней сработки, или сброшен ли флаг при первом запуске, и если да, то
flg_near = true; // ставим флаг,
timer1 = millis(); // обновляем значение таймера,
myDFPlayer.volume(20); // выставляем уровень громкости плеера
myDFPlayer.play(4); // указываем плееру включить 4 трек
}
}
if (sensor.distance() >= 30 && sensor.distance() <= 70) { // Проверяем, если расстояние до препятствия от 30 до 70 см, то
if(millis() > timer2 + hcsr_waiting_time_far || flg_far ==0){ // проверяем, прошло ли заданное время после последней сработки, или сброшен ли флаг при первом запуске, и если да, то
flg_far = true; // ставим флаг,
timer2 = millis(); // обновляем значение таймера,
myDFPlayer.volume(15); // выставляем уровень громкости плеера
myDFPlayer.play(5); // указываем плееру включить 5 трек
l = 0; // обнуляем переменную для изменения значения яркости светодиодов
}
}
//====================================================================//
//====================================================================//
if (flg_near) { // Если был установлен флаг ПРЕПЯТСТВИЕ БЛИЗКО, то
if(millis() < timer1 + action_time){ // проверяем, прошло ли заданное время на выполнение анимации, и если нет, то
//============================================================// // БЛОК РАБОТЫ ВНУТРЕННЕЙ ПОДСВЕТКИ
if (millis() > timer3 + 500) { // Проверяем, прошло ли время с момента последнего выполнения блока, и если нет, то
timer3 = millis(); // обновляем значение таймера,
uint16_t f; // определяем переменную как коэффициент яркости
if (f == 0 ) {f = 42; } else // f=60° (0 ... 42 ... 255 = 0° ... 60° ... 360°)
if (f == 42 ) {f = 85; } else // f=120° (0 ... 85 ... 255 = 0° ... 120° ... 360°)
if (f == 85 ) {f = 127;} else // f=180° (0 ... 127 ... 255 = 0° ... 180° ... 360°)
if (f == 127) {f = 170;} else // f=240° (0 ... 170 ... 255 = 0° ... 240° ... 360°)
if (f == 170) {f = 212;} else // f=300° (0 ... 212 ... 255 = 0° ... 300° ... 360°)
if (f == 212) {f = 0; } // f=360° (0 ... 255 ... 255 = 0° ... 360° ... 360°)
if (f < 85) { b = 0; r = f * 3; g = 255 - r;} else // перелив от зелёного к красному, через жёлтый
if (f < 170) {f -= 85; g = 0; b = f * 3; r = 255 - b;} else // перелив от красного к синему , через фиолетовый
{f -= 170; r = 0; g = f * 3; b = 255 - g;} // перелив от синего к зелёному, через голубой
for (uint8_t t = 0; t < 8; t++) {led.setColor(t, r, g, b);} // устанавливаем выбранный цвет для очередного светодиода
}
//============================================================// // БЛОК РАБОТЫ "ГЛАЗ" - эффект "бегающих" по кругу глаз
p++; // увеличиваем значение переменной на 1 при каждом выполнении цикла
if (p == 4) p = 0; // при превышении значения сбрасываем его
led.setColor(8 + p, 255, 0, 0); // указываем указанному светодиоду на левом модуле гореть красным
led.setColor(12 + p, 255, 0, 0); // указываем указанному светодиоду на правом модуле гореть красным
led.setColor(7 + (p ? p : 4), 127, 127, 127); // указываем всем остальным светодиодам на левом модуле гореть белым
led.setColor(11 + (p ? p : 4), 127, 127, 127); // указываем всем остальным светодиодам на правом модуле гореть белым
//============================================================//
led.write(); // записываем указанные цвета в модули
delay(100); // задержка 100мс
} else { // Если время выполнения анимации закончилось, то
flg_near = false; // Сбрасываем флаг
led.setColor(NeoPixelAll, 0, 0, 0); // устанавливаем цвет всех светодиодов в чёрный(гасим)
led.write(); // записываем указанный цвет в модули
}
}
//====================================================================//
//====================================================================//
else if (flg_far) { // Если был установлен флаг ПРЕПЯТСТВИЕ ДАЛЕКО, то
if(millis() < timer2 + action_time){ // проверяем, прошло ли заданное время на выполнение анимации, и если нет, то
if (!rev_flg) { // проверяем, установлен флаг реверса, и если нет, то
l++; // увеличиваем значение яркости на 1 при кажом выполнении цикла
r = l; g = 0; b = 0; // устанавливаем светодиодам внутри красный цвет, и задаём яркость
for (uint8_t e = 0; e < 8; e++) { // проходим по указанным светодиодам (установленным внутри)
led.setColor(e, r, g, b); // задаём указанным светодиодам яркость и цвет
}
led.write(); // записываем указанный цвет и яркость в модули
delay(19); // задержка 19мс
if (l == 255) rev_flg = 1; // при достижении максимального значения яркости устанавливаем флаг реверса
} else { // Если установлен флаг реверса, то
l--; // уменьшаем значение яркости на 1 при каждом выполнении цикла
r = l; g = 0; b = 0; // устанавливаем светодиодам внутри красный цвет, и задаём яркость
for (uint8_t e = 0; e < 8; e++) { // проходим по указанным светодиодам (установленным внутри)
led.setColor(e, r, g, b); // задаём указанным светодиодам яркость и цвет
}
led.write(); // записываем указанный цвет и яркость в модули
delay(19); // задержка 19мс
if (l == 0) rev_flg = 0; // при достижении минимального значения яркости сбрасываем флаг реверса
}
} else { // Если время выполнения анимации закончилось, то
flg_far = false; // Сбрасываем флаг
led.setColor(NeoPixelAll, 0, 0, 0); // устанавливаем цвет всех светодиодов в чёрный(гасим)
led.write(); // записываем указанный цвет в модули
}
}
}
Алгоритм работы скетча:
До кода void setup() определяются переменные, подключаются необходимые библиотеки.
В коде void setup() инициализируется MP3-плеер, адресные светодиоды NeoPixel, датчик расстояния, выключаются светодиоды, если до этого они горели.
Код void loop() делится 2 части:
- Проверяется, обнаружил ли датчик расстояния препятствие в одной из 2 указанных зон:
- Если препятствие находится вблизи, то запускается трек 4, ставится флаг наличия препятствия
flg_nearв данной зоне, обнуляется счётчик времениtimer1, фиксирующий наступление события, чтобы в следующий раз оно сработало через времяhcsr_waiting_time_near; - Если препятствие находится вдалеке, то запускается трек 5, ставится флаг наличия препятствия
flg_farв данной зоне, обнуляется счётчик времениtimer2, фиксирующий наступление события, чтобы в следующий раз оно сработало через времяhcsr_waiting_time_far;
- Проверяется, был ли установлен флаг наличия препятствия:
- Если препятствие было обнаружено вблизи (установлен флаг
flg_near):- Проверяем, истекло время выполнения анимации
timer1 + action_timeили нет;- Если не истекло, то задаём режим работы светодиодных модулей;
- Если истекло, то гасим все светодиоды и сбрасываем флаг;
- Проверяем, истекло время выполнения анимации
- Если препятствие было обнаружено вдалеке (установлен флаг
flg_far):- Проверяем, истекло время выполнения анимации
timer2 + action_timeили нет;- Если не истекло, то задаём режим работы светодиодных модулей;
- Если истекло, то гасим все светодиоды и сбрасываем флаг;
- Проверяем, истекло время выполнения анимации
- Если препятствие было обнаружено вблизи (установлен флаг
Ссылки:
- Библиотека iarduino_NeoPixel;
- Библиотека DFPlayer Mini mp3 Arduino Library V1.3;
- Библиотека iarduino_HC_SR04_int;
- Wiki - Установка библиотек в Arduino IDE;
- Wiki - Piranha UNO;
- Wiki - Battery Shield;
- Wiki - Trema Shield;
- Wiki - Trema-модуль Адресные светодиоды NeoPixel;
- Wiki - Ультразвуковой датчик измерения расстояния HC-SR04;

Обсуждение