Сигнализация перелива в бочке орала зуммером так, что соседи понимали: что-то там пищит — а что именно, не понять. Один тон — это один уровень тревоги, хоть тресни; мне же нужен был голос: файл с записанным сообщением, который лежит на той же карте, куда пишется лог. Загвоздка в железе: у Uno нет цифро-аналогового преобразователя, ни один пин не выдаёт звуковые уровни — только ШИМ с фиксированной частотой.
Библиотека TMRpcm выкручивается из этого через аппаратный таймер: пин D9 дёргается ШИМом с частотой сэмплирования, а скважность каждого импульса берётся из очередного байта WAV-файла на карте. Звучит как трюк, а на слух — нормальная речь и мелодии, если файл в правильном формате. Разберём формат и конвертацию, почему пин именно D9, и главную развилку новичка: почему динамик напрямую к пину — это сожжённый порт, пьезо-пискун — жалкие милливатты, а усилитель LM386 — правильный ответ.
Формат: 8 бит, моно, 16-32 кГц
TMRpcm понимает один формат: WAV с несжатым PCM, 8 бит на сэмпл, один канал, частота 16-32 кГц. Всё, что льётся из сети и редакторов, — 16-битное стерео 44,1 кГц — библиотека либо молчит, либо играет треском. Конвертация в Audacity занимает четыре минуты: Дорожки — Свести стерео в моно, слева внизу частота проекта 16000, затем Файл — Экспорт — WAV с кодированием Unsigned 8-bit PCM. Имя файла короткое и латиницей, лежит в корне карты: alarm.wav, siren.wav — файловая система любит формат восемь-точка-три, о котором подробно в уроке про формат FAT16 и FAT32.
Числа для планирования места: 16 кГц по одному байту — это 16 КБ в секунду, минута звука — 960 КБ, карта на 2 ГБ хранит больше тридцати часов. Частота 32000 удваивает расход и требует вызова quality(1) в скетче: без него сэмплы читаются вразнобой и звук плывёт. На карте Class 4 при 32 кГц я слышал запинки — SPI не успевал качать байты; при 16 кГц та же карта играла ровно. Мой стандарт — 16000 Гц, 8 бит, моно: голосовой сигнализации большего не нужно, а запас по карте остаётся на лог.
Про качество звука честно: 8 бит — это около 48 дБ динамического диапазона, и шипение на тихих местах слышно всегда. Для сигнализации это неважно: сообщение записывается с нормальным уровнем, и фон тонет в шуме комнаты. Трюк, который заметно улучшает восприятие: перед конвертацией нормализуйте громкость в Audacity, Effect — Normalize, — поднимите уровень так, чтобы тихие места стояли выше шума квантования. Паузу в начале файла тоже срежьте: TMRpcm начинает играть сразу после вызова play, и секунду тишины никто в скетче не пропустит.
| Параметр | Значение | Почему так | Если нарушить |
|---|---|---|---|
| Битность | 8 бит, Unsigned PCM | сэмпл = 1 байт, читается одним read | 16-битный WAV играет треском или молчит |
| Каналы | моно | второму каналу на одном пине взяться неоткуда | стерео играет вполголоса и с глюками |
| Частота | 16-32 кГц | лимит таймера и скорости SPI на Uno | ниже 8000 бубнит, выше 32000 — запинки |
| Имя файла | 8.3, латиница, в корне | короткие имена каталога FAT | alarm-2024-январь.wav не найдётся |
#include <SPI.h>#include <SD.h>#include <TMRpcm.h> const int csPin = 10; // CS картыTMRpcm speaker; // объект плеера void setup() { Serial.begin(9600); if (!SD.begin(csPin)) { Serial.println("SD error"); while (true) { } } speaker.speakerPin = 9; // D9 на Uno: выход OC1A таймера 1 speaker.setVolume(5); // шкала 0-6 Serial.println("commands: play alarm / play siren / stop");} void loop() { if (Serial.available()) { String cmd = Serial.readStringUntil('\n'); cmd.trim(); if (cmd == "play alarm") { speaker.play("alarm.wav"); // WAV 8 bit, 16000 Hz, mono, в корне } else if (cmd == "play siren") { speaker.play("siren.wav"); speaker.loop(1); // крутить файл по кругу } else if (cmd == "stop") { speaker.stop(); } }}Пин D9 выбран не из красоты: это выход OC1A аппаратного таймера 1 на Uno, и TMRpcm заводит туда частоту сэмплирования, меняя скважность ШИМ вслед за байтами файла. Отсюда запрет, о который ломается половина проектов: пока играет звук, таймер 1 занят, и analogWrite на пины 9 и 10 — это тот же таймер — работать не будет. Библиотека Servo по умолчанию тоже сидит на таймере 1, и звук с сервой на Uno не дружат без правок самих библиотек. Планируйте пины заранее: одному таймеру — один хозяин.
После пина звук сырой: ШИМ несёт огибающую волны, но и несущую частоту таймера тоже. RC-фильтр — резистор 10 кОм с пина и конденсатор 10 нФ на землю — срезает несущую и оставляет звук; без фильтра в динамике слышен высокочастотный фон поверх речи. Для пищалки-подтверждения фильтр не нужен, для голоса — обязателен. И проверьте файл до play: SD.exists() из урока про режимы File отловит опечатку в имени — иначе вместо звука минута тишины и поиск виноватого в проводах.
Питание модуля и громкость
Вторая серия граблей — питание. SD-карта трёхвольтовая, и модули к ней бывают разные: типовой модуль со стабилизатором и преобразователем уровней ест 5 В от платы — устройство этого модуля разобрано в уроке про модуль изнутри. А есть голые микросборки под 3,3-вольтовые платы вроде ESP: на пятивольтовых пинах Uno они сжигают карту — иногда сразу, иногда после недели работы, что хуже всего для поиска причины. Читайте маркировку на плате модуля до подключения, а не после первого мёртвого лога.
В момент play питание проседает: карта берёт импульсы до 100 мА, усилитель добавляет свои, и без конденсатора 100-470 мкФ на входе модуля звук может начинаться с щелчков и обрывов. Ток пина против громкости — та же песня снизу: даже с фильтром пин отдаёт на нагрузку порядка милливатта, а LM386 с пятёрки питания — до половины ватта на динамик 8 Ом. Разница между слышно у макетки и слышно за стеной стоит 120 рублей и двух конденсаторов — дешевле любой альтернативы.
Схема с LM386 минимальная: вход через конденсатор 10 мкФ на ножку 3, перемычка между ножками 1 и 8 с конденсатором 10 мкФ поднимает усиление до 200, выход с ножки 5 через конденсатор 220-470 мкФ идёт на динамик. Земля общая с Arduino, и это главный источник тресков: динамик возвращает ток импульсами, и если его земля идёт тонким проводом через макетку вместе с сигнальными, в звук лезет фон. Провод земли динамика ведите отдельным и потолще — прямо на GND платы, мимо гребёнки макетки.
В симуляторе мелодия играет тональностями через tone — честная оговорка: настоящий WAV из байтов файла собирает TMRpcm, симулятор показывает только логику плеера. Смотрите на массив частот из файла, нота за нотой, на busy-светодиод и на поведение loop: файл кончился — зуммер молчит, либо крутится заново, если тумблер включён. На реальной плате вместо частот — байты сэмплов, вместо ноты — огибающая речи, а сам порядок play — isPlaying — stop совпадает один в один.
Команды play и stop в скетче ловятся через Serial тем же readStringUntil, каким мы ловили команды в уроке про команды из Serial — плеер без экрана остаётся управляемым. Собрать всё в устройство проще всего поверх логгера: карта уже читает датчики и пишет строки по схеме из урока про логирование, остаётся добавить динамик с LM386 и пару конвертированных файлов — вечер работы и прибор, который разговаривает.
- 1. Какой формат файлов играет TMRpcm?
- 2. Почему на Uno пин вывода звука именно D9?
- 3. Что случится, если подключить динамик 8 Ом напрямую к D9?
- 4. Сколько весит минута WAV при 16 кГц, 8 бит, моно?
- 5. На карте файл 16-битного стерео WAV 44,1 кГц из интернета. Что делать?
- TMRpcm играет только WAV PCM 8 бит моно 16-32 кГц; конвертация в Audacity: моно, 16000 Гц, Unsigned 8-bit PCM
- Пин D9 — выход OC1A таймера 1: пока играет звук, analogWrite на 9 и 10 недоступен, Servo на том же таймере не дружит
- 16 КБ в секунду: минута звука — 960 КБ; 32 кГц требует quality(1) и карты побыстрее, иначе запинки
- Пин Uno отдаёт 20-40 мА: пьезо можно прямо, динамик 8 Ом — только через LM386 или резистор 100-150 Ом
- Модуль SD для Uno — со стабилизатором и преобразователем уровней; 3,3-вольтовая сборка на 5 В пинах сжигает карту
- play — isPlaying — stop, loop(1) для повтора; RC-фильтр 10 кОм и 10 нФ убирает фон ШИМ из звука
Частые вопросы по теме урока
- Какой формат файлов играет TMRpcm?
- Библиотека понимает только несжатый восьмибитный моно PCM. Всё остальное — MP3, 16-битные WAV, стерео — требует конвертации перед заливкой на карту. WAV PCM 8 бит, моно, 16-32 кГц
- Почему на Uno пин вывода звука именно D9?
- TMRpcm вешает частоту сэмплирования на аппаратный таймер 1, а его выход на Uno — пин 9. Пока играет звук, таймер занят, и analogWrite на 9-10 недоступен. Это выход OC1A таймера 1, которым библиотека модулирует ШИМ
- Что случится, если подключить динамик 8 Ом напрямую к D9?
- Пин Uno гарантирует 20 мА, потолок — 40. Динамик 8 Ом просит в пятнадцать раз больше: порт деградирует, а громкого звука всё равно не получится. Нужен LM386 или резистор. Ток 5 В / 8 Ом ≈ 0,6 А сожжёт пин, звука не будет
- Сколько весит минута WAV при 16 кГц, 8 бит, моно?
- 16000 сэмплов по одному байту = 16 КБ в секунду, минута — 960 КБ. На карте 2 ГБ помещается больше тридцати часов звука. Около 960 КБ
- На карте файл 16-битного стерео WAV 44,1 кГц из интернета. Что делать?
- Дело не в имени, а в кодировании. Audacity: моно, 16000 Гц, экспорт WAV с Unsigned 8-bit PCM — после этого файл играет. Свести в моно, понизить до 16000 Гц и экспортировать в 8 бит PCM