Цифровой микрофон INMP441 и ESP32: I2S в Arduino IDE

Перевод статьи ESP32 with INMP441 I2S Omnidirectional Microphone Module (Arduino IDE) — Random Nerd Tutorials.
В этом руководстве разберёмся, как работать с всенаправленным I2S-микрофоном INMP441 на ESP32 в Arduino IDE. Подключим модуль к плате и сделаем три примера: измерим интенсивность звука (RMS), выведем звуковую волну в Serial Plotter и соберём проект «хлопни — включится», в котором светодиод (реле или любой другой выход ESP32) управляется хлопками.
Знакомство с INMP441#
INMP441 — всенаправленный MEMS-микрофон (MEMS — микроэлектромеханическая система). Он улавливает звук и выдаёт 24-битные цифровые аудиоданные по интерфейсу I2S — специальному протоколу для передачи звука.

Модуль INMP441 и его выводы
Микрофон даёт чистый звук при низком энергопотреблении и хорошем соотношении сигнал/шум. Это заметно лучший выбор, чем аналоговые микрофоны: преобразование звука в отфильтрованный цифровой сигнал происходит прямо в модуле.
Штыревые выводы нужно припаять так, как показано на фото. Если модуль стоит на макетке, маленькое отверстие микрофона должно смотреть на вас.
Основные особенности INMP441:
- всенаправленность — ловит звук со всех сторон, так что точно позиционировать его не нужно;
- выход I2S — цифровое аудио сразу по интерфейсу I2S;
- хорошее качество сигнала и низкий уровень шума;
- подходит для встраиваемых проектов — маленький размер, низкое потребление и цифровой интерфейс делают его удачным вариантом для IoT, особенно в паре с ESP32, которая умеет I2S.
Интерфейс I2S#
INMP441 общается по I2S (Inter-IC Sound) — синхронному последовательному протоколу для передачи аудиоданных между двумя цифровыми аудиоустройствами.
В ESP32 есть периферийный блок I2S с драйвером. Его можно настроить как вход — для чтения звука, или как выход — для воспроизведения и передачи звука.
Подробности про I2S на ESP32 есть в официальной документации ESP-IDF: Inter-IC Sound (I2S).
Выводы INMP441#
Модуль подключается к ESP32 по I2S и имеет следующие выводы:
- L/R — выбор левого или правого канала I2S (на GND — левый, на 3V3 — правый). Можно выбрать любой, главное — поправить код соответственно;
- WS — Word Select (он же LRCLK), подключается к GPIO ESP32;
- SCK — Serial Clock (он же BCLK), подключается к GPIO ESP32;
- SD — Serial Data, собственно звук с микрофона, подключается к GPIO ESP32 (вход);
- GND — к GND ESP32;
- VDD — питание модуля, 3,3 В от ESP32.
Подключение INMP441 к ESP32#
В этом руководстве используется ESP32-S3 и следующие GPIO. Если у вас плата с другим чипом ESP32, поменяйте выводы под неё.
| INMP441 | ESP32-S3 |
|---|---|
| L/R | GND |
| WS | GPIO 40 |
| SCK | GPIO 42 |
| SD | GPIO 41 |
| GND | GND |
| VDD | 3V3 |

Подключение INMP441 к ESP32-S3
Жёстко заданных выводов I2S нет — подойдут любые безопасные для использования GPIO ESP32. Полезно почитать: распиновка ESP32-S3 DevKitC и какие выводы ESP32 можно использовать.
Подготовка Arduino IDE#
Перед началом убедитесь, что установлены Arduino IDE и пакет плат ESP32. Если ещё нет — вот инструкция по установке.
1. Интенсивность звука (RMS)#
В этом примере микрофон INMP441 и ESP32 измеряют интенсивность звука, а результат выводится в Serial Plotter в Arduino IDE.
Микрофон непрерывно захватывает звук и отправляет отсчёты в ESP32 по I2S. По этим отсчётам можно посчитать среднеквадратичное значение (RMS, Root Mean Square) — оно показывает силу звука на коротком отрезке времени.
RMS считается так:
- возводим каждый отсчёт в квадрат;
- находим среднее всех квадратов;
- извлекаем из результата квадратный корень.
RMS = √( (x₁² + x₂² + … + xₙ²) / n )
Чем громче звук, тем больше RMS.
Код#
Для получения звука по I2S используем драйвер ESP-IDF driver/i2s.h. Он по умолчанию входит в ядро ESP32 для Arduino, так что сторонние библиотеки не нужны.
Скопируйте код в Arduino IDE:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Подробности проекта: https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
Настоящим любому лицу, получившему копию этого ПО и сопутствующей документации, бесплатно предоставляется разрешение на их использование.
Приведённое выше уведомление об авторских правах и данное разрешение должны быть включены во все копии или существенные части ПО.
*/
#include <driver/i2s.h>
// Настройка выводов
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT с микрофона
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
// Настройка I2S
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
// Настройка выводов
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
// Запуск I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
Serial.println("I2S started.");
Serial.println("Reading microphone...");
}
void loop() {
size_t bytes_read = 0;
// Читаем данные с микрофона
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
double sum = 0;
// Перебираем отсчёты
for (int i = 0; i < samples_read; i++) {
// INMP441 передаёт 24-битный звук, выровненный по левому краю 32-битного слова I2S
int32_t sample = sBuffer[i] >> 8;
//Serial.println(sample);
sum += (double)sample * sample;
}
// Считаем RMS
double rms = sqrt(sum / samples_read);
// Выводим RMS
//Serial.print("RMS: ");
Serial.println(rms);
}
Как работает код#
Сначала подключаем драйвер I2S:
#include <driver/i2s.h>
Выводы I2S. Задаём выводы, к которым подключён микрофон. Если у вас другие — поправьте эти строки:
// Настройка выводов
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT с микрофона
Порт и частота дискретизации. Выбираем периферийный блок I2S номер 0 и задаём частоту дискретизации — сколько отсчётов захватывается в секунду. 16 000 — типичное значение для голоса и звуковых приложений.
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
Размер буфера. Задаём, сколько отсчётов будет участвовать в расчёте RMS, и создаём сам буфер sBuffer:
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
Обратите внимание: буфер рассчитан на 32-битные отсчёты. I2S передаёт данные слотами фиксированной длины, и для INMP441 практичнее всего 32-битный слот, хотя разрешение микрофона — 24 бита. Иными словами, 24 бита данных INMP441 лежат внутри 32-битного слова I2S, и нужные биты потом приходится извлекать.
setup(). Инициализируем последовательный порт на скорости 115200:
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
Структуры настройки I2S. Теперь можно настроить периферию I2S. Создаём структуру типа i2s_config_t с именем i2s_config — в ней частота дискретизации, разрядность отсчёта, канал (левый или правый) и прочие параметры.
// Настройка I2S
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
Другие возможные значения параметров есть в документации ESP-IDF по I2S.
Затем создаём ещё одну структуру, i2s_pin_config_t, с используемыми выводами I2S:
// Настройка выводов
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
И наконец запускаем I2S, передав функциям созданные структуры:
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
loop(). В цикле читаем данные с микрофона и считаем RMS. Функция i2s_read() читает данные с INMP441 и складывает их в sBuffer. После каждого успешного чтения в буфере лежат 512 отсчётов.
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
Затем переводим bytes_read в samples_read, поделив число принятых байт на размер одного отсчёта. Так мы точно знаем, сколько отсчётов в буфере.
int samples_read = bytes_read / sizeof(int32_t);
Следующие строки возводят каждый отсчёт в квадрат и складывают квадраты:
// Перебираем отсчёты
for (int i = 0; i < samples_read; i++) {
// INMP441 передаёт 24-битный звук, выровненный по левому краю 32-битного слова I2S
int32_t sample = sBuffer[i] >> 8;
//Serial.println(sample);
sum += (double)sample * sample;
}
Потом делим сумму на число отсчётов и извлекаем корень:
// Считаем RMS
double rms = sqrt(sum / samples_read);
Обратите внимание на строку ниже. 24-битные данные микрофона лежат внутри 32-битного значения, и сдвиг >> 8 смещает его на 8 бит вправо, правильно выравнивая звук перед расчётом RMS.
int32_t sample = sBuffer[i] >> 8;
В конце выводим RMS. Печатаем только это число, без подписей, чтобы результат было удобно смотреть в Serial Plotter.
Serial.println(rms);
Проверка#
Загрузите код в ESP32, не забыв выбрать правильную плату и COM-порт. В оригинале используется ESP32-S3.
После загрузки откройте Serial Plotter — его значок находится рядом со значком Serial Monitor. В новом окне появится график RMS во времени. Хлопайте, говорите, издавайте то громкие, то тихие звуки — значение будет меняться.

RMS в Serial Plotter: первый пик — хлопок, второй — щелчок пальцами
Посмотрите, какие значения RMS дают звуки разной громкости, и выберите по ним порог. Дальше можно сделать проект, который выполняет какое-то действие, когда RMS превышает этот порог.
2. Отображение звуковой волны#
В этом примере читаем аудиоданные и выводим форму волны в Serial Plotter. Всё просто: получаем данные по I2S и печатаем их в последовательный порт.
Скопируйте код в Arduino IDE:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Подробности проекта: https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
Настоящим любому лицу, получившему копию этого ПО и сопутствующей документации, бесплатно предоставляется разрешение на их использование.
Приведённое выше уведомление об авторских правах и данное разрешение должны быть включены во все копии или существенные части ПО.
*/
#include <driver/i2s.h>
// Настройка выводов
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT с микрофона
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
// Настройка I2S
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
// Настройка выводов
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
// Запуск I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
Serial.println("I2S started.");
Serial.println("Reading microphone...");
}
void loop() {
size_t bytes_read = 0;
// Читаем данные с микрофона
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
// Выводим отсчёты
for (int i = 0; i < samples_read; i++) {
// INMP441 передаёт 24-битный звук, выровненный по левому краю 32-битного слова I2S
int32_t sample = sBuffer[i] >> 8;
Serial.println(sample);
}
}
Как работает код#
Код работает так же, как предыдущий, только не считает RMS. Всё остальное без изменений.
Проходим по всем отсчётам в буфере и печатаем их. Каждый отсчёт — это амплитуда звукового сигнала в конкретный момент времени.
// Выводим отсчёты
for (int i = 0; i < samples_read; i++) {
// INMP441 передаёт 24-битный звук, выровненный по левому краю 32-битного слова I2S
int32_t sample = sBuffer[i] >> 8;
Serial.println(sample);
}
Проверка#
Загрузите код в ESP32 и откройте Serial Plotter. Теперь видна амплитуда звуковой волны в каждый момент. Попробуйте тянуть разные гласные — «аааа», «ээээ», «ииии», «оооо», «уууу» — и посмотрите, как меняется волна.

Разные гласные дают разные сочетания частот, а значит, и разную форму волны
Serial Plotter — не лучший инструмент, чтобы разглядывать форму волны. Можно написать программу на Python с Matplotlib: там удобно менять масштаб и сохранять снимок графика.
Дополнительно: волна в Matplotlib#
- Установите Python (при установке отметьте пункт Add Python to PATH).
- Откройте терминал или командную строку и установите нужные библиотеки:
pip install pyserial matplotlib
- Убедитесь, что на ESP32 работает скетч из этого раздела. Посмотрите в Arduino IDE номер последовательного порта (например, COM5) и закройте Arduino IDE — иначе порт будет занят.
- Создайте новый файл Python — подойдёт даже «Блокнот», главное сохранить с расширением
.py. - Скопируйте в него код ниже (файл в репозитории авторов), укажите свой COM-порт и сохраните, например, на рабочий стол под именем
INMP441-microphone.py.
# Подробности проекта: https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
import serial
import matplotlib.pyplot as plt
PORT = "COM6"
BAUD_RATE = 115200
NUM_SAMPLES = 512
ser = serial.Serial(PORT, BAUD_RATE, timeout=1)
print("Reading samples from ESP32...")
print("Close the plot window to stop.")
plt.ion()
fig, ax = plt.subplots()
while True:
samples = []
while len(samples) < NUM_SAMPLES:
line = ser.readline().decode("utf-8", errors="ignore").strip()
if line:
try:
samples.append(int(line))
except ValueError:
pass
ax.clear()
ax.plot(samples)
ax.set_title("INMP441 Audio Waveform")
ax.set_xlabel("Sample")
ax.set_ylabel("Amplitude")
ax.grid(True)
plt.pause(0.001)
ser.close()
- В терминале перейдите в папку с файлом и запустите программу:
cd Desktop
python INMP441-microphone.py
Откроется окно Matplotlib с графиком звуковой волны.

Та же волна в Matplotlib
3. Управление выходом ESP32 хлопками#
С тем, что мы уже знаем, несложно собрать простой проект, в котором выходы ESP32 управляются хлопками:
- управляем одним GPIO ESP32 — для наглядности светодиодом. Вместо него можно поставить реле и управлять, например, лампой или жалюзи;
- два хлопка инвертируют текущее состояние светодиода.

Светодиод включается и выключается двойным хлопком
При хлопке амплитуда звуковой волны резко растёт, и появляется пик, который хорошо выделяется на фоне окружающего шума. Если за короткое время мы видим два пика выше заданного порога, считаем, что был двойной хлопок, и инвертируем состояние светодиода.

Двойной хлопок — два пика выше порога
Важно: на самом деле проект не распознаёт именно хлопок. Он ловит два последовательных пика звуковой волны выше порога в пределах заданного интервала. Так что сработает и щелчок пальцами, и стук и т. п.
Перед началом подключите к ESP32 светодиод. В оригинале он висит на GPIO 38 (плата ESP32-S3 DevKitC). Для другой платы выберите другой GPIO.
Что понадобится:
- плата ESP32-S3;
- модуль микрофона INMP441;
- резистор 220 Ом (или близкого номинала);
- светодиод;
- макетная плата;
- соединительные провода.

Схема с микрофоном и светодиодом
Собрав схему, скопируйте код:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Подробности проекта: https://RandomNerdTutorials.com/esp32-inmp441-i2s-microphone-arduino/
Настоящим любому лицу, получившему копию этого ПО и сопутствующей документации, бесплатно предоставляется разрешение на их использование.
Приведённое выше уведомление об авторских правах и данное разрешение должны быть включены во все копии или существенные части ПО.
*/
#include <driver/i2s.h>
// Настройка выводов
#define I2S_SCK 42 // BCLK
#define I2S_WS 40 // LRCLK / WS
#define I2S_SD 41 // DOUT с микрофона
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define BUFFER_LEN 512
int32_t sBuffer[BUFFER_LEN];
// Светодиод
#define LED_PIN 38
// Детекция хлопка
#define CLAP_THRESHOLD 1000000
// Максимальное время между первым и вторым хлопком
const unsigned long CLAP_GAP = 700;
// Не даём одному и тому же хлопку засчитаться несколько раз
const unsigned long CLAP_COOLDOWN = 250;
// Переменные состояния
bool ledState = false;
int clapCount = 0;
unsigned long firstClapTime = 0;
unsigned long lastClapTime = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("INMP441 Microphone");
// Настройка светодиода
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Настройка I2S
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // L/R = GND
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = BUFFER_LEN,
.use_apll = false
};
// Настройка выводов
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
// Запуск I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
Serial.println("I2S started.");
Serial.println("Double clap to control LED");
}
void loop() {
size_t bytes_read = 0;
// Читаем данные с микрофона
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
// Ищем самый громкий отсчёт
int32_t peak = 0;
// Перебираем отсчёты
for (int i = 0; i < samples_read; i++) {
int32_t sample = sBuffer[i] >> 8;
int32_t magnitude = abs(sample);
if (magnitude > peak) {
peak = magnitude;
}
}
// Выводим пик
Serial.println(peak);
// Детекция хлопка
unsigned long now = millis();
if (peak > CLAP_THRESHOLD && now - lastClapTime > CLAP_COOLDOWN) {
lastClapTime = now;
// Первый хлопок
if (clapCount == 0) {
clapCount = 1;
firstClapTime = now;
Serial.println("First clap detected");
}
// Второй хлопок
else if (now - firstClapTime <= CLAP_GAP) {
clapCount = 0;
// Двойной хлопок — инвертируем состояние светодиода
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
if (ledState) {
Serial.println("DOUBLE CLAP - LED ON");
}
else {
Serial.println("DOUBLE CLAP - LED OFF");
}
}
// Прошло слишком много времени
else {
// Считаем этот хлопок началом новой пары
clapCount = 1;
firstClapTime = now;
Serial.println("New first clap");
}
}
// Сброс, если второй хлопок не пришёл вовремя
if (clapCount == 1 && now - firstClapTime > CLAP_GAP) {
clapCount = 0;
}
}
Как работает код#
Инициализация I2S и получение звука устроены так же, как в предыдущих примерах.
Управляем GPIO 38 — при необходимости поменяйте номер:
// Светодиод
#define LED_PIN 38
Нужно задать порог хлопка — амплитуду, выше которой считаем, что был хлопок. Он должен заметно превышать амплитуду фонового шума; возможно, значение придётся подобрать под ваши условия.
// Детекция хлопка
#define CLAP_THRESHOLD 1000000
Двойным хлопком считаем два пика выше порога, между которыми прошло не больше 700 мс:
const unsigned long CLAP_GAP = 700;
Пики, пришедшие в течение 250 мс после предыдущего, игнорируем — так один и тот же хлопок не засчитается несколько раз:
const unsigned long CLAP_COOLDOWN = 250;
Запоминаем время первого и последнего хлопка — по ним определяем двойной хлопок. Время хранится в переменных firstClapTime и lastClapTime, а номер хлопка (первый или второй) — в clapCount.
int clapCount = 0;
unsigned long firstClapTime = 0;
unsigned long lastClapTime = 0;
В loop() непрерывно получаем аудиоданные в буфер sBuffer:
// Читаем данные с микрофона
i2s_read(I2S_PORT, sBuffer, sizeof(sBuffer), &bytes_read, portMAX_DELAY);
int samples_read = bytes_read / sizeof(int32_t);
В каждом полученном буфере проверяем модуль (амплитуду) каждого отсчёта и находим пик:
// Ищем самый громкий отсчёт
int32_t peak = 0;
// Перебираем отсчёты
for (int i = 0; i < samples_read; i++) {
int32_t sample = sBuffer[i] >> 8;
int32_t magnitude = abs(sample);
if (magnitude > peak) {
peak = magnitude;
}
}
Запоминаем текущее время и проверяем условия хлопка: пик должен быть выше порога, а с предыдущего пика должно пройти больше времени, чем CLAP_COOLDOWN.
// Детекция хлопка
unsigned long now = millis();
if (peak > CLAP_THRESHOLD && now - lastClapTime > CLAP_COOLDOWN) {
Если условия выполнены, а первого хлопка ещё не было, считаем этот хлопок первым и запоминаем его время в firstClapTime:
// Первый хлопок
if (clapCount == 0) {
clapCount = 1;
firstClapTime = now;
Serial.println("First clap detected");
}
Если же пришёл второй хлопок и интервал между ним и первым меньше CLAP_GAP, инвертируем состояние светодиода и сбрасываем clapCount в 0, чтобы искать следующий двойной хлопок. Если интервал оказался больше, этот хлопок считается первым в новой паре.
// Второй хлопок
else if (now - firstClapTime <= CLAP_GAP) {
clapCount = 0;
// Двойной хлопок — инвертируем состояние светодиода
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
if (ledState) {
Serial.println("DOUBLE CLAP - LED ON");
}
else {
Serial.println("DOUBLE CLAP - LED OFF");
}
}
// Прошло слишком много времени
else {
// Считаем этот хлопок началом новой пары
clapCount = 1;
firstClapTime = now;
Serial.println("New first clap");
}
Если второй хлопок так и не пришёл вовремя, сбрасываем clapCount в 0 и начинаем поиск заново:
// Сброс, если второй хлопок не пришёл вовремя
if (clapCount == 1 && now - firstClapTime > CLAP_GAP) {
clapCount = 0;
}
Проверка#
Загрузите код в ESP32, проверив плату и COM-порт. Хлопните дважды — светодиод загорится. Ещё два хлопка — погаснет. Короткое видео с демонстрацией есть в оригинальной статье.
Если светодиод постоянно мигает, увеличьте порог CLAP_THRESHOLD:
#define CLAP_THRESHOLD 1000000
Если светодиод не реагирует на хлопки — уменьшите его.
Чтобы подобрать подходящее значение, смотрите на амплитуду, которую печатает строка:
Serial.println(peak);
Запишите значения фонового шума (когда вы не хлопаете) и значения при хлопке. Порог должен быть между ними — чуть ниже пика, который даёт хлопок.
Итоги#
Мы подключили микрофонный модуль INMP441 к ESP32 по I2S, настроили шину и научились получать по ней данные.
INMP441 непрерывно отдаёт аудиоданные, которые мы складываем в буфер. Дальше этот буфер можно использовать для отображения звуковой волны или для расчётов вроде RMS.
В звуковых проектах пригодится и усилитель вроде MAX98357 для вывода звука — он тоже работает по I2S. Авторы обещают вскоре выпустить руководство и по нему.