Курс Arduino с нуля · Звук
Урок 19. Зуммер: сигналы и мелодии
У платы появляется голос. Разбираемся, что такое частота звука, играем гамму и мелодию и делаем свои сигналы «принято» и «ошибка».
Что понадобится
- Плата Uno из набора
- Кабель USB
- Макетная плата
- Зуммер
- Потенциометр 10 кОм
- Тактовая кнопка
- 6 проводов «папа-папа»
Все детали есть в обучающем наборе, по которому идёт курс.
До сих пор плата разговаривала с нами только светом. Сегодня у неё появится голос. Деталь для этого крошечная — чёрная таблетка размером с монетку, — а возможностей она даёт неожиданно много: сигналы, сирены, мелодии и даже музыкальные инструменты.
Заодно мы разберём, что такое звук с точки зрения платы. Оказывается, ничего таинственного: всё сводится к одному числу.
Что такое зуммер
Внутри зуммера — кольцевой магнит, катушка и тонкая металлическая мембрана. Когда через катушку идёт ток, она притягивает мембрану; ток пропал — мембрана отскочила назад. Если включать и выключать ток много раз в секунду, мембрана начинает дрожать и толкать воздух. Эти толчки и есть звук.
Главное число здесь — частота: сколько раз в секунду мембрана качнулась туда-обратно. Считают её в герцах (Гц). Чем больше герц, тем выше звук.
У зуммера есть полярность
Зуммер, в отличие от резистора, нельзя ставить как попало. На корпусе напечатан знак «+», а у самой детали одна ножка длиннее — это и есть плюс. Он идёт к выводу платы, вторая ножка — на землю. Перевёрнутый зуммер в лучшем случае будет звучать тише и глуше.
Собираем схему
Сегодня на макетке будет сразу три детали: зуммер, крутилка из четырнадцатого урока и кнопка. Так мы сможем не только пищать, но и управлять звуком.
Отключите USB перед сборкой. И собирайте по частям: сначала зуммер и проверьте его первой же программой, потом крутилку, потом кнопку.
Проверьте перед включением: ножка со знаком «+» идёт в столбик 3, откуда провод уходит на вывод 12; вторая ножка зуммера — в шину «−»; средняя ножка крутилки на A0, крайние — на разные шины; кнопка сидит верхом на канавке, причём её провод на вывод 2 уходит сверху от канавки, а провод на землю — снизу (два вывода с одной стороны кнопки соединены всегда, и оба провода сверху дадут вечно нажатую кнопку).
Шаг 1. Первый сигнал
Программа получилась короче некуда — и в ней сразу две новые команды.
const int BUZZER = 12; // зуммер подключён к выводу 12
void setup() {
// Зуммеру, как и светодиоду, нужен режим «выход».
pinMode(BUZZER, OUTPUT);
}
void loop() {
tone(BUZZER, 1000); // подаём сигнал частотой 1000 Гц
delay(300); // держим треть секунды
noTone(BUZZER); // выключаем звук
delay(1000); // и целую секунду молчим
}
tone(вывод, частота) — «подай на этот вывод сигнал такой частоты». Плата начинает щёлкать выводом сама, в фоне, а программа спокойно идёт дальше. Именно поэтому сразу за tone идёт delay: он просто отмеряет, сколько времени звуку звучать.
noTone(вывод) — «замолчи». Без неё зуммер будет пищать бесконечно: командаtone запускает звук и не выключает его сама.
Слишком громко? Это нормально — зуммер рассчитан на то, чтобы его услышали. Если он режет слух, поставьте последовательно с ним резистор на 470 Ом или 1 кОм: звук станет заметно тише. На работу схемы это никак не влияет.
Шаг 2. Два тона подряд
Одна частота — один звук. Поставим два подряд и получим знакомый дверной сигнал.
const int BUZZER = 12;
void setup() {
pinMode(BUZZER, OUTPUT);
}
void loop() {
tone(BUZZER, 988); // «динь» — это нота си
delay(250);
tone(BUZZER, 784); // «дон» — нота соль, она ниже
delay(400);
noTone(BUZZER);
delay(2000);
}
Обратите внимание: между двумя tone нет noTone. Новая команда просто заменяет частоту у уже звучащего сигнала — получается переход от одной ноты к другой без паузы.
Шаг 3. Ноты и гамма
Нота — это тоже просто частота, за которой закрепили название. Ноте «ля» первой октавы соответствуют 440 герц — по ней настраивают все инструменты в мире. Соберём восемь нот в массив и сыграем гамму.
const int BUZZER = 12;
// Частоты нот первой октавы в герцах:
// до ре ми фа соль ля си до
const int NOTES[8] = {262, 294, 330, 349, 392, 440, 494, 523};
void setup() {
pinMode(BUZZER, OUTPUT);
}
void loop() {
for (int i = 0; i < 8; i++) {
tone(BUZZER, NOTES[i]);
delay(300);
}
noTone(BUZZER);
delay(1000);
}
Массив мы уже собирали в шестом уроке для светодиодов — здесь он ровно такой же, только вместо номеров выводов лежат частоты. Цикл for проходит по нему от начала до конца.
Шаг 4. Сирена
А если менять частоту не восемью ступеньками, а сотней маленьких шажков? Получится сирена.
const int BUZZER = 12;
void setup() {
pinMode(BUZZER, OUTPUT);
}
void loop() {
// Вверх: частота растёт от 400 до 1200 герц маленькими шагами.
for (int f = 400; f <= 1200; f = f + 10) {
tone(BUZZER, f);
delay(5);
}
// И тем же путём вниз.
for (int f = 1200; f >= 400; f = f - 10) {
tone(BUZZER, f);
delay(5);
}
}
Здесь for считает не элементы массива, а саму частоту: от 400 до 1200 с шагом 10. Восемьдесят шажков по 5 миллисекунд — и звук плавно уезжает вверх за полсекунды. Попробуйте поменять шаг с 10 на 40: сирена станет «ступенчатой», и вы услышите, из чего она собрана.
Шаг 5. Крутилка задаёт высоту
Соединим звук с тем, что уже умеем: пусть частотой управляет ручка потенциометра.
const int BUZZER = 12;
const int POT = A0;
void setup() {
pinMode(BUZZER, OUTPUT);
Serial.begin(9600);
}
void loop() {
int raw = analogRead(POT); // 0…1023 с крутилки
int freq = map(raw, 0, 1023, 100, 2000); // переводим в герцы
tone(BUZZER, freq);
Serial.print("крутилка: ");
Serial.print(raw);
Serial.print(" частота: ");
Serial.print(freq);
Serial.println(" Гц");
delay(50);
}
Всё уже знакомо: analogRead даёт число от 0 до 1023, map растягивает его в диапазон частот, tone отправляет результат зуммеру. Откройте монитор порта — и вы увидите, как одно число превращается в другое.
Это уже инструмент. Крутилка + зуммер — простейший терменвокс. Если вместо крутилки поставить фоторезистор из пятнадцатого урока, высотой звука можно будет управлять ладонью. Именно этим мы и займёмся в следующем уроке.
Шаг 6. Мелодия
У настоящей мелодии есть не только ноты, но и длительности: одна нота короткая, другая тянется. Значит, нужны два массива — и они работают в паре.
const int BUZZER = 12;
// Частоты нот…
const int MELODY[9] = {392, 392, 392, 311, 466, 392, 311, 466, 392};
// …и сколько миллисекунд звучит каждая.
const int DURATION[9] = {350, 350, 350, 250, 100, 350, 250, 100, 700};
void setup() {
pinMode(BUZZER, OUTPUT);
}
void loop() {
for (int i = 0; i < 9; i++) {
tone(BUZZER, MELODY[i]);
delay(DURATION[i]);
noTone(BUZZER); // крошечная тишина между нотами,
delay(DURATION[i] / 5); // иначе они сливаются в одну
}
delay(2000); // пауза перед повтором
}
Секрет в двух последних строках цикла. Если играть ноты вплотную, три одинаковые ноты подряд сольются в одну длинную — ухо не услышит границы. Поэтому после каждой ноты мы делаем крошечную тишину: noTone и пауза примерно в пятую часть длительности. Это и есть разница между «пищит» и «играет».
Хотите свою мелодию? Найдите в интернете таблицу «частоты нот» и выпишите нужные числа в первый массив, а во второй — длительности. Только не забудьте поправить оба числа 9 в программе: и в объявлении массивов, и в условии цикла. Массивы должны быть одинаковой длины.
Шаг 7. Свои сигналы
В настоящих приборах зуммер чаще всего не играет музыку, а подтверждает действия: пикнул — принято, пикнул дважды — ошибка. Сделаем такую же вещь и у нас.
const int BUZZER = 12;
const int BUTTON = 2;
// Наш собственный сигнал: сколько раз пискнуть и на какой высоте.
void beep(int times, int freq) {
for (int i = 0; i < times; i++) {
tone(BUZZER, freq, 80); // третье число — сколько миллисекунд звучать
delay(160); // 80 мс звук + 80 мс тишина
}
}
void setup() {
pinMode(BUZZER, OUTPUT);
pinMode(BUTTON, INPUT_PULLUP);
beep(2, 1200); // «я включилась и готова»
}
void loop() {
if (digitalRead(BUTTON) == LOW) {
beep(1, 880); // «принято»
delay(300);
}
}
Здесь появился третий вид команды: tone(вывод, частота, длительность). Третье число говорит, сколько миллисекунд звучать, и noTone уже не нужен — плата выключит звук сама.
А наша функция beep из седьмого урока превращает всё это в один понятный приказ: beep(2, 1200) — «пикни дважды высоким». Дальше по курсу мы будем вставлять такие сигналы в устройства, не задумываясь об их устройстве.
Важно: звук занимает таймер
Пока зуммер звучит, на выводах 3 и 11 перестаёт работать плавная яркость (analogWrite) — плата отдаёт звуку тот же внутренний «счётчик». Обычные digitalWrite и все остальные выводы работают как ни в чём не бывало. Просто не вешайте на 3 и 11 светодиоды, которым нужна плавность, если в устройстве есть звук.
И ещё одно ограничение: одновременно звучит только одна нота. Аккорд плата сыграть не сможет — tone работает с одним выводом за раз.
Не работает? Разбираемся
- Полная тишина. Проверьте вывод: в программе 12 — и провод должен идти именно в него. Затем полярность: «плюс» зуммера к плате, вторая ножка на землю.
- Зуммер пищит один раз и замолкает навсегда. Скорее всего, где-то потерялся
noToneили программа застряла вdelay. Перезалейте скетч первого шага — он самый простой. - Звук есть, но высота не меняется. Возможно, вам попался активный зуммер — со встроенным генератором. Такой умеет только один тон, какую частоту ему ни задавай. В наборе идёт обычный, но проверить просто: залейте гамму из третьего шага — если все восемь нот звучат одинаково, зуммер активный.
- Звук тихий и хриплый. Зуммер перевёрнут. Выньте его, найдите знак «+» и вставьте заново.
- Мелодия звучит как один сплошной вой. Пропущена тишина между нотами — посмотрите две последние строки цикла в шестом шаге.
Задания для тренировки
- РазминкаСделайте «обратный отсчёт»: три низких сигнала с паузой в секунду, а затем один длинный высокий — как на старте соревнований.
- ПосложнееСоедините сирену со светодиодом: пусть на высоких частотах он горит ярко, а на низких тускло. Подсказка:
analogWriteиmap— но светодиод возьмите не на выводе 3 или 11. - Со звёздочкой ⭐Сделайте тревогу, которую включает и выключает кнопка. Пока она воет, программа должна оставаться живой — без длинных
delay. Разбор ниже.
Показать разбор «тревога, которая не подвешивает программу»
Приём тот же, что в одиннадцатом уроке: вместо «пищи, потом жди» программа каждый проход спрашивает часы — не пора ли сменить тон. Кнопка ловится по моменту нажатия, иначе тревога будет переключаться, пока палец на кнопке.
const int BUZZER = 12;
const int BUTTON = 2;
const int LED = LED_BUILTIN; // встроенный светодиод платы, ничего паять не надо
bool alarm = false; // тревога включена?
bool wasPressed = false; // кнопка была нажата на прошлом проходе?
bool soundHigh = false; // сейчас звучит высокий тон?
unsigned long lastChange = 0;
void setup() {
pinMode(BUZZER, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(BUTTON, INPUT_PULLUP);
}
void loop() {
bool pressed = (digitalRead(BUTTON) == LOW);
// Ловим момент нажатия, а не удержание.
if (pressed && !wasPressed) {
alarm = !alarm; // восклицательный знак означает «наоборот»
if (!alarm) {
noTone(BUZZER);
digitalWrite(LED, LOW);
}
delay(30); // антидребезг
}
wasPressed = pressed;
// Тревога переключает тон каждые 400 мс — и при этом не мешает
// программе делать что-то ещё: никаких длинных delay.
if (alarm && millis() - lastChange > 400) {
lastChange = millis();
soundHigh = !soundHigh;
if (soundHigh) {
tone(BUZZER, 1400);
digitalWrite(LED, HIGH);
} else {
tone(BUZZER, 900);
digitalWrite(LED, LOW);
}
}
}
Восклицательный знак в строке alarm = !alarm означает «наоборот»: была тревога — стало тихо, было тихо — стало громко. Одна строчка вместо целого if/else.
Светодиод здесь встроенный (LED_BUILTIN, тот самый с буквой L из третьего урока) — ничего дополнительно подключать не нужно. Он мигает в такт сирене и показывает главное: программа продолжает работать, а не стоит в ожидании.
Что мы узнали
- Звук для платы — это частота, число колебаний в секунду. Больше герц — выше звук.
tone(вывод, частота)запускает звук в фоне,noTone(вывод)выключает, а третье число вtoneзадаёт длительность.- Нота — это просто частота с именем. Мелодия — два массива: ноты и длительности, которые читаются одним и тем же номером.
- Между нотами нужна крошечная тишина, иначе одинаковые ноты сливаются.
- У зуммера есть полярность: «плюс» на корпусе идёт к выводу платы.
- Пока идёт звук, плавная яркость не работает на выводах 3 и 11.
В следующем уроке зуммер получит клавиши — точнее, пять фоторезисторов, которые будут играть от тени вашей ладони.
Частые вопросы
Как подключить зуммер к Arduino?
У зуммера есть полярность: на корпусе напечатан знак «плюс», а соответствующая ножка длиннее. Плюс идёт на цифровой вывод платы (в нашем уроке — на вывод 12), вторая ножка — на землю. Резистор не обязателен, но последовательный резистор на 470 Ом или 1 кОм заметно убавит громкость.
Чем tone отличается от digitalWrite?
Команда tone(вывод, частота) запускает на выводе прямоугольный сигнал заданной частоты и делает это в фоне: программа идёт дальше, а звук продолжается. Выключает его noTone(вывод). Третье число в tone задаёт длительность в миллисекундах — тогда плата замолчит сама.
Почему ноты мелодии сливаются в один звук?
Между нотами нужна крошечная пауза. Если сыграть три одинаковые ноты подряд без разрыва, ухо услышит одну длинную. Достаточно после каждой ноты вызвать noTone и подождать примерно пятую часть её длительности.
Почему при звуке перестаёт работать analogWrite?
Команда tone занимает тот же внутренний счётчик платы, что и плавная яркость на выводах 3 и 11. Пока звучит зуммер, analogWrite на этих двух выводах не работает. Все остальные выводы, включая 5, 6, 9 и 10, работают как обычно.
Чем активный зуммер отличается от пассивного?
У активного внутри собственный генератор: он умеет только один тон, какую частоту ему ни задавай. Пассивному частоту задаёт программа — именно такой нужен для мелодий и идёт в наборе. Проверить просто: сыграйте гамму, и если все ноты звучат одинаково, зуммер активный.
