Меандр #
Самый простой способ генерации звука микроконтроллером - квадратный сигнал (меандр), по сути классический пример с миганием светодиода раз в секунду является меандром с частотой в 1 Гц.
При уменьшении значения задержек частота сигнала будет увеличиваться - чтобы сигнал оставался квадратным, значения задержек должны быть одинаковыми.
// мигает светодиод на плате. Можно задать частоту
#define FREQ 2 // частота в Гц
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delayMicroseconds(1000000 / FREQ / 2);
digitalWrite(LED_BUILTIN, LOW);
delayMicroseconds(1000000 / FREQ / 2);
}
Зуммер #
Для того, чтобы "послушать" сигнал, нужен динамик или пьезоэлектрическая "пищалка" - зуммер, он же баззер (buzzer). Его можно снять со старого корпуса компьютера, материнской платы или найти в Ардуино-наборе:
Зуммеры бывают двух видов - активные и пассивные, отличить их можно подключив питание 5V (или меньше) от платы Arduino:
- Активные издают громкий писк просто при подаче питания - у них фиксированная звуковая частота: внутри находится плата, которая генерирует звук. Таким зуммером не получится воспроизводить свой сигнал
- Пассивные при подаче питания просто щёлкают - такой зуммер сможет издавать звук заданной частоты с МК
Для уменьшения нагрузки на пин подключим зуммер через резистор на пару сотен Ом или через потенциометр для регулировки громкости:
Загрузим код, который будет выдавать сигнал с частотой 500 Гц:
#define FREQ 500 // частота в Гц
#define BUZ_PIN 2 // пин зуммера
void setup() {
pinMode(BUZ_PIN, OUTPUT);
}
void loop() {
digitalWrite(BUZ_PIN, HIGH);
delayMicroseconds(1000000 / FREQ / 2);
digitalWrite(BUZ_PIN, LOW);
delayMicroseconds(1000000 / FREQ / 2);
}
Зуммер пищит! В схеме с потенциометром можно изменять громкость рукояткой. Поэкспериментируйте с частотой звука.
Изменение частоты #
Давайте подключим второй потенциометр на аналоговый пин A0
- пусть он изменяет частоту звука от 500 Гц до "бесконечности". Вот схема и код:
#define BUZ_PIN 2
#define POT_PIN A0
void setup() {
pinMode(BUZ_PIN, OUTPUT);
}
void loop() {
int val = analogRead(POT_PIN);
// макс. период - 1023*2 мкс, частота - 489 Гц
digitalWrite(BUZ_PIN, HIGH);
delayMicroseconds(val);
digitalWrite(BUZ_PIN, LOW);
delayMicroseconds(val);
}
Проблема такого способа генерации звука в том, что МК занят только одной задачей - генерировать звук. Если нужно выполнять ещё какой-то код, то он будет "спотыкаться" о задержки, а если он будет долго выполняться и вносить свои задержки - частота начнёт "плавать" и звук будет искажаться. В примере выше у нас есть analogRead
- он выполняется около 120 мкс на Nano, это означает что частота будет ограничена примерно 8 кГц, т.к. во время опроса потенциометра звук не "воспроизводится". А также нарушится форма волны - перестанет быть квадратной. Это не так важно, но это факт.
Функция tone #
В Arduino есть функция tone
, которая позволяет генерировать звук асинхронно, независимо от задержек и прочих блокирующих конструкций. В AVR Arduino генерацией звука занимается аппаратный таймер. Достаточно вызвать tone(пин, частота)
для запуска генерации и noTone(пин)
для отключения:
#define BUZ_PIN 2
void setup() {
// писк 500 Гц на 3 секунды
tone(BUZ_PIN, 500);
delay(3000);
noTone(BUZ_PIN);
}
void loop() {
}
Функция tone
может принимать и третий аргумент - время сигнала в мс, т.е. звук отключится сам по асинхронному таймеру:
#define BUZ_PIN 2
void setup() {
// писк 500 Гц на 3 секунды
tone(BUZ_PIN, 500, 3000);
}
void loop() {
}
Пример с настройкой частоты:
#define BUZ_PIN 2
#define POT_PIN A0
void setup() {
}
void loop() {
int hz = analogRead(POT_PIN) * 20; // до 20 кГц
tone(BUZ_PIN, hz);
delay(10);
}