Интерактивный MP3-плеер на Arduino с ультразвуковым датчиком расстояния
Компоненты и материалы
| Arduino UNO | ×1 |
| Последовательный MP3-плеер Catalex (требуется SD-карта и кардридер) | ×1 |
| Ультразвуковой датчик HC-SR04 | ×2 |
| Динамик с входом 3.5 мм | ×1 |
О проекте
Использование последовательного MP3-плеера Catalex
В предыдущем уроке использовалась только библиотека SoftwareSerial.h и простые функции. Основная функция отправки команд:
void sendCommand(int8_t command, int16_t dat) {
if (command == CMD_PLAY_WITHFOLDER || command == CMD_PLAY_WITHVOLUME) {
Serial.println("PLAYING SONG, SLIGHTLY MOVE YOUR HEAD FOR GREAT EFFECT");
}
delay(20);
Send_buf[0] = 0x7e; // стартовый байт
Send_buf[1] = 0xff; // версия
Send_buf[2] = 0x06; // длина команды без стартового и конечного байтов
Send_buf[3] = command;
Send_buf[4] = 0x00; // 0x00 = без подтверждения, 0x01 = с подтверждением
Send_buf[5] = (int8_t)(dat >> 8); // старший байт данных
Send_buf[6] = (int8_t)(dat); // младший байт данных
Send_buf[7] = 0xef; // конечный байт
for (uint8_t i = 0; i < 8; i++) {
mySerial.write(Send_buf[i]);
}
Serial.println();
}

Использование ультразвукового датчика HC-SR04
Библиотеки не требуется. Функция измерения расстояния:
long measureDistance() {
long duration, distance;
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration / 2) / 29.1;
Serial.println("distance:");
Serial.println(distance);
return distance; // расстояние в см
}

Версия 1: Простой триггер MP3 по расстоянию
Сначала установите библиотеку SoftwareSerial.h, если её нет.
В этой версии: если объект приближается ближе 50 см — срабатывает воспроизведение аудио. Я использовал это, чтобы напугать соседей громким клипом «surprise motherfucker».
Примечание: Полный код .ino находится в вложениях проекта.
void loop() {
if (measureDistance() < 50) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0203); // 3-я песня 2-й папки
delay(1000); // пауза для избежания ошибок
}
delay(300);
}
Версия 2: Триггер по изменению расстояния (Disturbance)
Эта версия не учитывает абсолютное расстояние, а реагирует на резкое изменение показаний. Если ложные срабатывания — увеличьте порог в if(gap > 20). Новые переменные объявляются вне цикла.
int firstTime = 0;
long Distance, auxDistance, gap = 0;
void loop() {
Distance = measureDistance(trigPin, echoPin);
gap = abs(Distance - auxDistance);
if (firstTime == 0) {
auxDistance = Distance; gap = 0;
firstTime++; delay(1000);
}
if (gap > 20) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0201); // 1-я песня 2-й папки
firstTime = 0; delay(2000);
}
Serial.print("New Distace:"); Serial.print(Distance);
Serial.print(" Old Distance: "); Serial.print(auxDistance); Serial.println(gap);
delay(300);
auxDistance = Distance;
}
Версия 3: Два датчика расстояния — определение направления движения
С двумя датчиками можно определить направление движения: программа воспроизводит «hello» или «bye» в зависимости от того, в какую сторону движется человек.
- Определяем пины для второго HC-SR04:
#define trigPin 13 // первый датчик
#define echoPin 12
#define trigPin2 10 // второй датчик
#define echoPin2 9
- Новые переменные:
long Distance, auxDistance, gap = 0;
long Distance2, auxDistance2, gap2 = 0;
- В
setup()добавляем инициализацию новых пинов.
- Функция
measureDistance()теперь принимает пины как аргументы.
long measureDistance(int trigger, int echo) {
long duration, distance;
digitalWrite(trigger, LOW); delayMicroseconds(2);
digitalWrite(trigger, HIGH); delayMicroseconds(10);
digitalWrite(trigger, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration / 2) / 29.1;
return distance;
}
- Основной цикл
loop():
void loop() {
Distance = measureDistance(trigPin, echoPin);
Distance2 = measureDistance(trigPin2, echoPin2);
gap = abs(Distance - auxDistance);
gap2 = abs(Distance2 - auxDistance2);
if (firstTime == 0) {
auxDistance = Distance; auxDistance2 = Distance2;
gap = 0; gap2 = 0; firstTime++; delay(2000);
}
if (gap > 20 && gap2 < 20) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0201);
firstTime = 0; Serial.println("RIGHT MOVEMENT DETECTED"); delay(2000);
}
if (gap2 > 20 && gap < 20) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0202);
firstTime = 0; Serial.println("LEFT MOVEMENT DETECTED"); delay(2000);
}
// ... отладочный вывод
delay(300);
auxDistance = Distance; auxDistance2 = Distance2;
}
Удачного творчества!
Программный код
- Версия 1 — Простой триггер по расстоянию
- Версия 2 — Триггер по изменению расстояния
- Версия 3 — Два датчика, определение направления
Версия 1 — Простой триггер по расстоянию Arduino
// Javier Muñoz 10/11/2016, javimusama@hotmail.com
#include <SoftwareSerial.h>
#define ARDUINO_RX 5 // к TX MP3-модуля
#define ARDUINO_TX 6 // к RX MP3-модуля
#define trigPin 13
#define echoPin 12
SoftwareSerial mySerial(ARDUINO_RX, ARDUINO_TX);
static int8_t Send_buf[8] = {0};
#define NEXT_SONG 0X01
#define PREV_SONG 0X02
#define CMD_PLAY_W_INDEX 0X03
#define VOLUME_UP_ONE 0X04
#define VOLUME_DOWN_ONE 0X05
#define CMD_SET_VOLUME 0X06
#define SET_DAC 0X17
#define CMD_PLAY_WITHVOLUME 0X22
#define CMD_SEL_DEV 0X09
#define DEV_TF 0X02
#define SLEEP_MODE_START 0X0A
#define SLEEP_MODE_WAKEUP 0X0B
#define CMD_RESET 0X0C
#define CMD_PLAY 0X0D
#define CMD_PAUSE 0X0E
#define CMD_PLAY_WITHFOLDER 0X0F
#define STOP_PLAY 0X16
#define PLAY_FOLDER 0X17
#define SET_CYCLEPLAY 0X19
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
delay(500);
sendCommand(CMD_SEL_DEV, DEV_TF);
delay(200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
if (measureDistance(trigPin, echoPin) < 50) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0203);
delay(1000);
}
delay(300);
}
void sendCommand(int8_t command, int16_t dat) {
delay(20);
Send_buf[0] = 0x7e; Send_buf[1] = 0xff; Send_buf[2] = 0x06;
Send_buf[3] = command; Send_buf[4] = 0x00;
Send_buf[5] = (int8_t)(dat >> 8); Send_buf[6] = (int8_t)(dat);
Send_buf[7] = 0xef;
for (uint8_t i = 0; i < 8; i++) {
mySerial.write(Send_buf[i]);
Serial.print(Send_buf[i], HEX);
}
Serial.println();
}
long measureDistance(int trigger, int echo) {
long duration, distance;
digitalWrite(trigger, LOW); delayMicroseconds(2);
digitalWrite(trigger, HIGH); delayMicroseconds(10);
digitalWrite(trigger, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration / 2) / 29.1;
Serial.println("distance:"); Serial.println(distance);
return distance;
}
Версия 2 — Триггер по изменению расстояния Arduino
// Javier Muñoz 10/11/2016
#include <SoftwareSerial.h>
#define ARDUINO_RX 5
#define ARDUINO_TX 6
#define trigPin 13
#define echoPin 12
SoftwareSerial mySerial(ARDUINO_RX, ARDUINO_TX);
static int8_t Send_buf[8] = {0};
// ... (те же define, что в версии 1)
int firstTime = 0;
long Distance, auxDistance, gap = 0;
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
delay(500);
sendCommand(CMD_SEL_DEV, DEV_TF);
delay(200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
Distance = measureDistance(trigPin, echoPin);
gap = abs(Distance - auxDistance);
if (firstTime == 0) {
auxDistance = Distance; gap = 0; firstTime++; delay(1000);
}
if (gap > 20) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0201);
firstTime = 0; delay(2000);
}
Serial.print("New Distace:"); Serial.print(Distance);
Serial.print(" Old Distance: "); Serial.print(auxDistance); Serial.println(gap);
delay(300);
auxDistance = Distance;
}
void sendCommand(int8_t command, int16_t dat) {
if (command == CMD_PLAY_WITHFOLDER || command == CMD_PLAY_WITHVOLUME) {
Serial.print("PLAYING SONG, SLIGHTLY MOVE YOUR HEAD FOR GREAT EFFECT");
}
delay(20);
Send_buf[0] = 0x7e; Send_buf[1] = 0xff; Send_buf[2] = 0x06;
Send_buf[3] = command; Send_buf[4] = 0x00;
Send_buf[5] = (int8_t)(dat >> 8); Send_buf[6] = (int8_t)(dat);
Send_buf[7] = 0xef;
for (uint8_t i = 0; i < 8; i++) mySerial.write(Send_buf[i]);
Serial.println();
}
long measureDistance(int trigger, int echo) {
long duration, distance;
digitalWrite(trigger, LOW); delayMicroseconds(2);
digitalWrite(trigger, HIGH); delayMicroseconds(10);
digitalWrite(trigger, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration / 2) / 29.1;
return distance;
}
Версия 3 — Два датчика, определение направления Arduino
// Javier Muñoz 10/11/2016
#include <SoftwareSerial.h>
#define ARDUINO_RX 5
#define ARDUINO_TX 6
#define trigPin 13
#define echoPin 12
#define trigPin2 10
#define echoPin2 9
SoftwareSerial mySerial(ARDUINO_RX, ARDUINO_TX);
static int8_t Send_buf[8] = {0};
// ... (те же define)
int firstTime = 0;
long Distance, auxDistance, gap = 0;
long Distance2, auxDistance2, gap2 = 0;
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
delay(500);
sendCommand(CMD_SEL_DEV, DEV_TF);
delay(200);
pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT);
pinMode(trigPin2, OUTPUT); pinMode(echoPin2, INPUT);
}
void loop() {
Distance = measureDistance(trigPin, echoPin);
Distance2 = measureDistance(trigPin2, echoPin2);
gap = abs(Distance - auxDistance);
gap2 = abs(Distance2 - auxDistance2);
if (firstTime == 0) {
auxDistance = Distance; auxDistance2 = Distance2;
gap = 0; gap2 = 0; firstTime++; delay(2000);
}
if (gap > 20 && gap2 < 20) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0201);
firstTime = 0; Serial.println("RIGHT MOVEMENT DETECTED"); delay(2000);
}
if (gap2 > 20 && gap < 20) {
sendCommand(CMD_PLAY_WITHFOLDER, 0X0202);
firstTime = 0; Serial.println("LEFT MOVEMENT DETECTED"); delay(2000);
}
Serial.println("\\\\\\\\\\\\\\\\\\\\\\\\");
Serial.print(" New Distace:"); Serial.print(Distance);
Serial.print(" Old Distance: "); Serial.print(auxDistance);
Serial.print(" GAP "); Serial.println(gap);
Serial.print("New Distace2:"); Serial.print(Distance2);
Serial.print(" Old Distance2: "); Serial.print(auxDistance2);
Serial.print(" GAP2 "); Serial.println(gap2);
Serial.println("\\\\\\\\\\\\\\\\\\\\\\\\");
delay(300);
auxDistance = Distance; auxDistance2 = Distance2;
}
void sendCommand(int8_t command, int16_t dat) {
if (command == CMD_PLAY_WITHFOLDER || command == CMD_PLAY_WITHVOLUME) {
Serial.print("PLAYING SONG, SLIGHTLY MOVE YOUR HEAD FOR GREAT EFFECT");
}
delay(20);
Send_buf[0] = 0x7e; Send_buf[1] = 0xff; Send_buf[2] = 0x06;
Send_buf[3] = command; Send_buf[4] = 0x00;
Send_buf[5] = (int8_t)(dat >> 8); Send_buf[6] = (int8_t)(dat);
Send_buf[7] = 0xef;
for (uint8_t i = 0; i < 8; i++) mySerial.write(Send_buf[i]);
Serial.println();
}
long measureDistance(int trigger, int echo) {
long duration, distance;
digitalWrite(trigger, LOW); delayMicroseconds(2);
digitalWrite(trigger, HIGH); delayMicroseconds(10);
digitalWrite(trigger, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration / 2) / 29.1;
return distance;
}
Схемы подключения
- Один датчик расстояния
- Два датчика расстояния — просто добавьте второй на пины 10, 9
Производственный процесс
- Построение доступной беспроводной сети датчиков для дома
- Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
- Цифровой стадиометр на Arduino: отслеживание роста лазерным датчиком VL53L0X
- Интеграция ёмкостного сканера отпечатков DFRobot с Arduino или ESP8266
- Как воспроизводить аудио с Arduino UNO и DFPlayer Mini – Пошаговое руководство
- Веб-управляемый MP3-плеер на Arduino: Воспроизведение аудио через браузер
- Сенсорная башня на Arduino Cloud: Мониторинг температуры, движения и газа
- Умный водяной пистолет с датчиком движения на Arduino Nano
- Arduino UNO + WiFi Shield: реальный график температуры в вебе через Serial
- Компактный радар на Arduino Nano с HC-SR04 и дисплеем 1.8"