Слушать интернет-радио через телефон или компьютер не всегда удобно: устройство должно быть рядом, Bluetooth — подключён, а батарея — не разряжена. Если хочется просто включить музыку на кухне, в мастерской или детской — логичнее сделать отдельное устройство, которое работает само по себе.
В этом проекте вы соберёте компактное интернет-радио на базе ESP32-C3. Оно автоматически подключается к Wi-Fi, запускает поток и управляется всего двумя кнопками. Без приложений, без сопряжения и без лишних действий — включил питание и слушаешь.
В конце статьи вы найдёте готовый код и 3D-модель корпуса.
Что получится в итоге
- Рабочее интернет-радио с Wi-Fi подключением
- Воспроизведение MP3-потока через I2S-усилитель
- Управление громкостью кнопками
- Автоматическое переподключение при обрыве потока
- Готовый корпус для 3D-печати
Используемые компоненты
- ESP32-C3 Mini — микроконтроллер
- MAX98357A — I2S-усилитель со встроенным DAC
- Динамик 3W (рекомендуется 4Ω)
- Кнопки tact switch ×2
- Провода DuPont
- 3D-печатный корпус
Как это работает
- ESP32 подключается к Wi-Fi сети (в коде укажите настройки вашего WI-FI)
- Получает поток интернет-радио в формате MP3 (замените url радиостанции на свой).
- Далее аудио декодируется и передаётся по интерфейсу I2S на усилитель.
- MAX98357A усиливает сигнал и выводит звук на динамик.
- Вся логика работает автономно — без внешних устройств.
Схема подключения MAX98357A
Подключение по I2S:
- BCLK → GPIO 5
- LRC → GPIO 3
- DIN → GPIO 7
- VIN → 5V
- GND → GND
Советы по сборке
Проверьте правильность подключения BCLK, LRC и DIN
Используйте динамик 4Ω 3W для нормальной громкости
Обеспечьте стабильное питание 5V
Не подключайте динамик напрямую к ESP32
Что важно знать про MAX98357A
MAX98357A — это цифровой усилитель класса D с интерфейсом I2S и встроенным ЦАП. Он позволяет напрямую выводить звук с ESP32 без сложных аналоговых схем, благодаря чему идеально подходит для DIY аудио-проектов.
Если нет звука
1. Проверьте пины I2S
Чаще всего ошибка в подключении BCLK / LRC / DIN
2. Проверьте динамик
Оптимально — 4Ω 3W
3. Питание
Нестабильные 5V = искажения или пропадание звука
Используемые библиотеки
- WiFi.h
- AudioGeneratorMP3
- AudioFileSourceHTTPStream
- AudioOutputI2S
Итог
Собрав это устройство, вы получите полностью автономное интернет-радио, которое включается одной кнопкой и не требует смартфона или компьютера. Это отличная база для дальнейших проектов на ESP32: можно добавить дисплей, переключение станций или интеграцию с умным домом.
По всем вопросам по проекту вы можете написать в комментариях ниже.
Internet Radio on ESP32 – Arduino Sketch
#include <WiFi.h>
#include "AudioFileSourceHTTPStream.h"
#include "AudioFileSourceBuffer.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"
// ===== SETTINGS =====
const char* ssid = "YOUR-WIFI";
const char* password = "YOUR-PASS";
const char* streamUrl = "http://zt01.cdn.eurozet.pl/zet-net.mp3";
// usable pins (NOT 0 and 1)
#define VOL_UP_PIN 2
#define VOL_DOWN_PIN 4
float currentVolume = 0.21;
const float volumeStep = 0.03;
// buttons
unsigned long volUpPressTime = 0;
unsigned long volDownPressTime = 0;
// audio
AudioGeneratorMP3* mp3 = nullptr;
AudioFileSourceHTTPStream* file = nullptr;
AudioFileSourceBuffer* buff = nullptr;
AudioOutputI2S* out = nullptr;
// ===== START STREAM =====
void startStream() {
Serial.println("Starting stream");
if (mp3) { mp3->stop(); delete mp3; mp3 = nullptr; }
if (buff) { delete buff; buff = nullptr; }
if (file) { delete file; file = nullptr; }
file = new AudioFileSourceHTTPStream(streamUrl);
buff = new AudioFileSourceBuffer(file, 32768); // was 16384 → 32 KB more stable
mp3 = new AudioGeneratorMP3();
if (!mp3->begin(buff, out)) {
Serial.println("Error: mp3->begin() failed");
} else {
Serial.println("MP3 decoder started");
}
}
// ===== BUTTONS =====
void handleButtons() {
unsigned long now = millis();
// VOL UP
if (digitalRead(VOL_UP_PIN) == LOW) {
if (volUpPressTime == 0) {
volUpPressTime = now;
}
} else if (volUpPressTime > 0) {
unsigned long pressDuration = now - volUpPressTime;
if (pressDuration < 800 && pressDuration > 50) { // debounce ~50 ms
currentVolume += volumeStep;
if (currentVolume > 1.0) currentVolume = 1.0;
out->SetGain(currentVolume);
Serial.print("Volume ↑: ");
Serial.println(currentVolume, 2);
}
volUpPressTime = 0;
}
// VOL DOWN
if (digitalRead(VOL_DOWN_PIN) == LOW) {
if (volDownPressTime == 0) {
volDownPressTime = now;
}
} else if (volDownPressTime > 0) {
unsigned long pressDuration = now - volDownPressTime;
if (pressDuration < 800 && pressDuration > 50) {
currentVolume -= volumeStep;
if (currentVolume < 0.0) currentVolume = 0.0;
out->SetGain(currentVolume);
Serial.print("Volume ↓: ");
Serial.println(currentVolume, 2);
}
volDownPressTime = 0;
}
}
// ===== SETUP =====
void setup() {
Serial.begin(115200);
delay(500);
pinMode(VOL_UP_PIN, INPUT_PULLUP);
pinMode(VOL_DOWN_PIN, INPUT_PULLUP);
Serial.print("WiFi...");
WiFi.begin(ssid, password);
unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startTime < 15000) {
delay(300);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi OK");
// WiFi.setTxPower(WIFI_POWER_8_5dBm); // commented out — often interferes with stability
} else {
Serial.println("\nWiFi FAIL");
}
out = new AudioOutputI2S();
out->SetPinout(5, 3, 7); // your pins — left as is
out->begin(); // important: begin AFTER SetPinout
out->SetGain(currentVolume);
startStream();
}
// ===== LOOP =====
void loop() {
if (mp3 && mp3->isRunning()) {
if (!mp3->loop()) {
Serial.println("Stream interrupted → restarting...");
delay(300);
startStream();
}
}
handleButtons();
delay(5); // small pause to avoid 100% CPU usage
}
Комментарии к статье
Дякую.
Добавить комментарий