Мелодия Марио на Arduino: ноты для зуммера и tone()
Тема из Марио — первый мотив, который хочется сыграть на ардуине, и самый обидный провал новичка: заказал «зуммер для ардуино», подал HIGH — а он умеет только ровное «пи». Активный зуммер с генератором внутри мелодию не сыграет никогда; нужен пассивный пьезозуммер (KY-006 или пьединг из набора), которым частоту задаёт сам скетч. Мелодия при этом — не магия, а два массива: частоты нот в герцах и длительности в миллисекундах, прогоняемые циклом через tone().
В нашем симуляторе пьезозуммер — карточка «Пьезо-зуммер KY-006» из палитры «Макетка»: ставится кликом на цифровой пин, и tone() в ней исполняется по-настоящему — на карточке видно текущую частоту в герцах, а Serial печатает ноты по мере игры. Слышно мелодию только на живой плате: браузер частоту не озвучивает. Ниже — таблица частот, проверенный скетч вступления Марио и грабли таймеров.
Частоты нот: вся музыкальная теория, которая нужна
tone() принимает частоту в герцах, поэтому мелодия начинается с таблицы. Каждая нота — это частота колебания мембраны; октава вверх — частота вдвое больше. Для вступления Марио хватает нот первой-четвёртой октавы: E5 (659 Гц), C5 (523), G4 (392), G5 (784), C5, E5, A5 (880), B5 (988), A5, G5, E5, C5, D5 (587), B4 (494). Пауза — это не нота, а нулевая частота и delay: пишите в массив частот 0 и пропускайте tone(). Пьезомембрана честно играет и ниже 30 Гц, и выше 20 кГц — за границами слышимости ухо просто не услышит, рантайм разницы не заметит.
| Нота | Частота, Гц | Нота | Частота, Гц |
|---|---|---|---|
| C4 (до) | 262 | C5 (до) | 523 |
| D4 (ре) | 294 | D5 (ре) | 587 |
| E4 (ми) | 330 | E5 (ми) | 659 |
| G4 (соль) | 392 | G5 (соль) | 784 |
| A4 (ля) | 440 | A5 (ля) | 880 |
| B4 (си) | 494 | B5 (си) | 988 |
Скетч: вступление Марио на двух массивах
Схема одна на любой мотив: массив частот, массив длительностей, цикл с tone() и паузой. Тон с третьим аргументом — tone(пин, частота, длительность) — блокирующий: скетч стоит на нём заданное время, как на delay, поэтому темп мелодии честный и не плывёт. Разделительная пауза между нотами — полторы длительности: без неё ноты сливаются в кашу.
const int NOTY[] = { 659, 659, 0, 659, 0, 523, 659, 0, 784, 0, 0, 0, 392 };const int DLIT[] = { 150, 150, 100, 150, 100, 150, 150, 100, 300, 100, 100, 100, 250 };const int PIN_PIEZO = 8;const int VSEGO = 13; // длина обоих массивов void setup() { pinMode(PIN_PIEZO, OUTPUT); Serial.begin(9600); Serial.println("mario start");} void loop() { for (int i = 0; i < VSEGO; i++) { if (NOTY[i] > 0) { Serial.print("nota "); Serial.println(NOTY[i]); tone(PIN_PIEZO, NOTY[i], DLIT[i]); // блокирует на DLIT[i] delay(DLIT[i] / 2); // разделяющая пауза noTone(PIN_PIEZO); // тишина между нотами } else { delay(DLIT[i]); // нулевая частота = пауза } } delay(2000); // мотив закончился — тишина}Прогон в симуляторе: карточка пьезозуммера мигает нотами — «tone: 659 Гц», «tone: 784 Гц», в эти же моменты Serial печатает частоты; смена нот идёт в темпе длительностей. Звука в браузере нет, это честная граница: частоту и тайминг видно глазами, играют мелодию ушами уже на живой плате — где скетч собирается без единой правки. Хотите другой мотив — меняйте два массива целиком, цикл не трогается.
Грабли: таймеры, активный зуммер и слипшиеся ноты
- Активный зуммер молчит на tone() частотах или пищит ровно: у него генератор внутри, частоту с пина он не читает. Для мелодий — только пассивный KY-006 или голая пьезопластинка.
- tone() и analogWrite() делят таймеры Uno: зуммер на пине 3 или 11 уронит ШИМ на соседних. Разнесите пины или разберите конфликт в лендинге про таймеры.
- Без разделительной паузы ноты одной высоты сливаются в непрерывный писк: между повторами 659-659 обязателен разрыв, у Марио он ритмически важен.
- tone() один на весь скетч: второй вызов на другом пине перехватит таймер и заглушит первую ноту — полифонию одним Uno не сделать.