В этой статье мы подробно разберём, как собрать диктофон на базе цифрового микрофона INMP441 и микроконтроллера ESP32 с сохранением записей в формате WAV на microSD-карту.
INMP441 — это популярный и доступный микрофонный модуль, который обеспечивает чистый звук с низким уровнем шума. Благодаря цифровому I2S-интерфейсу, он избавляет от проблем аналоговых микрофонов (искажений, наводок, использование отдельного аналого-цифрового преобразователя для оцифровки сигнала) и отлично подходит для:
— простых диктофонов,
— систем акустического мониторинга,
— голосовых ассистентов,
— «умных» колонок.
В этой статье Вы найдёте:
✅ описание INMP441 и его преимуществ перед аналоговыми микрофонами;
✅ схему подключения преобразователя звука и microSD-карты к ESP32;
✅ настройку Arduino IDE для работы с ESP32;
✅ готовый код для записи звука с подробными комментариями.

Преимущества цифрового микрофона перед аналоговыми
Для построения аудиосистем в качестве чувствительного элемента часто применяются различные модули на базе электретного преобразователя звука и микросхем усилителей, таких как MAX4466 или MAX9814. Они являются аналоговыми, поэтому необходимо производить оцифровку сигнала посредством аналого-цифрового преобразователя (АЦП).
Контроллер ESP32 имеет встроенный 12-битный АЦП последовательного приближения. Но он имеет ряд ограничений:
— рекомендуемый диапазон входного сигнала: 0,1–2,5 В (при 3,3 В питании), так как значения близкие к 0 В и 3,3 В могут искажаться;
— нелинейность и шум: учитывая предыдущий пункт, АЦП также обладает значительной нелинейностью на крайних значениях;
— ограниченная полоса пропускания: до 6 кГц при стандартных настройках, поскольку более высокие частоты сглаживаются посредством внутреннего RC-фильтра.
Таким образом, выбор цифрового преобразователя звука является оптимальным вариантом, поскольку всей оцифровкой занимается сама микросхема, а уже дальнейшая работа по обработке цифрового потока данных перекладывается на микроконтроллер.
Описание и характеристики микрофона INMP441
INMP441 — это микросхема всенаправленного цифрового микрофона с интерфейсом I2S, разработанная компанией InvenSense.
Основные параметры:

Модуль, который мы будем использовать в эксперименте, представляет собой печатную плату, на которой распаяны сама микросхема, фильтрующий конденсатор питания на 100 нФ и резистор подтяжки на 100 кОм, а также штыревые разъёмы:

Ниже представлена таблица распиновки модуля:

Для общего понимания ниже представлены цоколёвка микросхемы акустического датчика и её схема включения на плате:


Обратим внимание, что у чипа есть контакт L/R — что означает левый или правый канал. Для записи стереозвука необходимо, соответственно, два таких устройства. При подключении их к управляющему контроллеру один аудиодатчик определяется как правый канал, а другой — левый.
Чувствительный элемент в составе INMP441 представляет собой MEMS-сенсор, который преобразует акустические колебания в цифровой сигнал с помощью встроенного АЦП. Далее оцифрованный сигнал проходит фильтрацию и передаётся на внешние устройства (в нашем случае отладочная плата NodeMCU-32S) посредством встроенного I2S-контроллера. Для наглядности ниже представлена блок-схема чипа:

Микросхема работает в режиме slave, и для работы I2S-интерфейса требует внешнего тактового сигнала от микроконтроллера.
Схема подключения INMP441 и microSD-карты к ESP32
Для работы с аудиодатчиком будем использовать аппаратный I2S-интерфейс на отладочной плате NodeMCU-32S (38 pin), построенная на базе ESP-WROOM-32. Ниже представлена таблица подключений INMP441 к отладочной плате:

Так как мы строим диктофон, то для сохранения записываемых аудиотреков применим microSD-карту памяти. Для неё необходим соответствующий адаптер, который подключается к отладочной плате по SPI-интерфейсу:

Отметим, что для наилучшего результата рекомендуется использовать карту памяти объёмом не более 32 ГБ, форматированную в файловую систему FAT32. Далее представлена таблица подключений адаптера карты памяти к отладочной плате:

Обратите внимание, что для питания адаптера требуется +5 В, поскольку на нём установлен понижающий стабилизатор напряжения на 3,3 В. Так как отладочная плата будет питаться от компьютера через USB-кабель, можно занять пин “Vin 5V”.
Ниже представлена общая схема подключения акустического преобразователя и адаптера microSD-карты памяти к контроллеру, а также фотография собранного макета:

Настройка среды разработки Arduino IDE
В качестве среды разработки воспользуемся Arduino IDE 2. И для работы с отладочными платами ESP32 необходимо убедиться, что среда разработки имеет необходимые настройки. Для этого в главном меню «Файл» из выпадающего списка выберите раздел «Параметры»:
В поле «Дополнительный ссылки для Менеджера плат» вставьте указанную ниже ссылку, после чего нажмите кнопку «OK»:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Далее переходим к загрузке библиотек для отладочных плат. Для этого в меню «Инструменты» выбираем «Плата» -> «Менеджер плат»:
Откроется менеджер плат, в котором нужно найти по запросу библиотеку «Arduino ESP32 Boards». Устанавливаем её:
В процессе установки появится окно с предложением установить драйвера — устанавливаем:
По завершению установки выбираем целевую плату DOIT ESP32 DEVKIT V1, которая соответствует NodeMCU-32S (38 pin) на базе ESP-WROOM-32:
Программный код (скетч)
Теперь перейдём к коду программы. Ниже представлен полный листинг кода с подробными комментариями:
#include <Arduino.h> // Основная библиотека Arduino
#include <driver/i2s.h> // Драйвер для работы с I2S (цифровые аудиоустройства)
#include <SD.h> // Библиотека для работы с microSD-картой
#include <SPI.h> // Библиотека для работы с интерфейсом SPI
// Настройки I2S микрофона
#define I2S_WS 25 // Пин для сигнала Word Select (выбор слова)
#define I2S_SD 33 // Пин для сигнала Serial Data (последовательные данные)
#define I2S_SCK 32 // Пин для сигнала Serial Clock (последовательные тактовые импульсы)
#define I2S_PORT I2S_NUM_0 // Используемый порт I2S (на ESP32 их два: I2S_NUM_0 и I2S_NUM_1)
// Настройки microSD-карты
#define SD_CS 5 // Пин для выбора microSD-карты (Chip Select)
#define SPI_MOSI 23 // Пин MOSI (Master Out Slave In) для SPI
#define SPI_MISO 19 // Пин MISO (Master In Slave Out) для SPI
#define SPI_SCK 18 // Пин SCK (Serial Clock) для SPI
// Настройки кнопки
#define BUTTON_PIN 0 // Встроенная кнопка на NodeMCU-32S 38pin (расположена справа от USB-разъёма)
// Настройки записи
#define SAMPLE_RATE 44100 // Частота дискретизации (44.1 кГц - стандартная для аудио)
#define BUFFER_SIZE 1024 // Размер буфера для хранения сэмплов
File audioFile; // Объект для работы с файлом на microSD-карте
int16_t i2sBuffer[BUFFER_SIZE]; // Буфер для хранения аудиоданных (16-битные целые числа)
volatile bool isRecording = false; // Флаг состояния записи (volatile для работы в прерываниях)
volatile bool buttonPressed = false; // Флаг нажатия кнопки (volatile для работы в прерываниях)
int fileNumber = 0; // Счетчик для нумерации файлов
// Функция обработки прерывания кнопки
void IRAM_ATTR buttonISR() {
buttonPressed = true; // Устанавливаем флаг при нажатии кнопки
// IRAM_ATTR указывает, что функция должна быть размещена в RAM (а не во flash) для быстрого выполнения
}
// Функция записи заголовка WAV файла
void writeWavHeader(File file, int sampleRate, uint32_t totalSamples) {
// Рассчитываем необходимые параметры для заголовка
uint32_t byteRate = sampleRate * 2; // 16-bit = 2 bytes per sample
uint32_t totalDataSize = totalSamples * 2; // Общий размер данных в байтах
uint32_t totalSize = totalDataSize + 36; // Общий размер файла (данные + заголовок)
// RIFF header (основной заголовок файла)
file.write('R'); file.write('I'); file.write('F'); file.write('F'); // "RIFF" метка
// Размер файла (минус 8 байт для "RIFF" и размера)
file.write((uint8_t)(totalSize & 0xFF)); // Младший байт
file.write((uint8_t)((totalSize >> 8) & 0xFF)); // Следующий байт
file.write((uint8_t)((totalSize >> 16) & 0xFF)); // ...
file.write((uint8_t)((totalSize >> 24) & 0xFF)); // Старший байт
file.write('W'); file.write('A'); file.write('V'); file.write('E'); // "WAVE" метка
// fmt subchunk (описание формата данных)
file.write('f'); file.write('m'); file.write('t'); file.write(' '); // "fmt " метка
file.write(16); file.write(0); file.write(0); file.write(0); // Subchunk1Size = 16 (для PCM)
file.write(1); file.write(0); // AudioFormat = PCM (линейный несжатый)
file.write(1); file.write(0); // NumChannels = 1 (моно)
// Частота дискретизации
file.write((uint8_t)(sampleRate & 0xFF));
file.write((uint8_t)((sampleRate >> 8) & 0xFF));
file.write((uint8_t)((sampleRate >> 16) & 0xFF));
file.write((uint8_t)((sampleRate >> 24) & 0xFF));
// Байтрейт (байт в секунду)
file.write((uint8_t)(byteRate & 0xFF));
file.write((uint8_t)((byteRate >> 8) & 0xFF));
file.write((uint8_t)((byteRate >> 16) & 0xFF));
file.write((uint8_t)((byteRate >> 24) & 0xFF));
file.write(2); file.write(0); // BlockAlign = 2 (байт на сэмпл для моно 16-бит)
file.write(16); file.write(0); // BitsPerSample = 16 (16-битное аудио)
// data subchunk (начало блока данных)
file.write('d'); file.write('a'); file.write('t'); file.write('a'); // "data" метка
// Размер данных в байтах
file.write((uint8_t)(totalDataSize & 0xFF));
file.write((uint8_t)((totalDataSize >> 8) & 0xFF));
file.write((uint8_t)((totalDataSize >> 16) & 0xFF));
file.write((uint8_t)((totalDataSize >> 24) & 0xFF));
}
// Функция начала записи
void startRecording() {
// Создание нового файла с уникальным именем
char filename[20];
do {
sprintf(filename, "/recording%d.wav", fileNumber++); // Формируем имя файла
} while(SD.exists(filename)); // Проверяем, не существует ли уже файл с таким именем
// Открываем файл для записи
audioFile = SD.open(filename, FILE_WRITE);
if(!audioFile) {
Serial.println("Ошибка создания файла!");
return;
}
// Записываем временный заголовок WAV файла (с нулевым размером данных)
// Фактический размер данных будет обновлен при остановке записи
writeWavHeader(audioFile, SAMPLE_RATE, 0);
// Устанавливаем флаг записи
isRecording = true;
Serial.println("Начало записи...");
}
// Функция остановки записи
void stopRecording() {
// Сбрасываем флаг записи
isRecording = false;
if (audioFile) {
// Вычисляем количество записанных сэмплов
// Размер файла минус размер заголовка (36 байт), деленный на 2 (16 бит = 2 байта на сэмпл)
uint32_t totalSamples = (audioFile.size() - 36) / 2;
// Переходим к началу файла и обновляем заголовок с правильным размером данных
audioFile.seek(0);
writeWavHeader(audioFile, SAMPLE_RATE, totalSamples);
// Закрываем файл
audioFile.close();
Serial.println("Запись завершена.");
Serial.print("Записано сэмплов: ");
Serial.println(totalSamples);
}
}
// Функция инициализации
void setup() {
Serial.begin(9600); // Инициализация последовательного порта для отладки
delay(1000); // Даем время для стабилизации
// Настройка 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_16BIT, // 16 бит на сэмпл
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // Только левый канал (моно)
.communication_format = I2S_COMM_FORMAT_STAND_I2S, // Стандартный формат I2S
.intr_alloc_flags = 0, // Флаги прерываний (по умолчанию)
.dma_buf_count = 8, // Количество буферов DMA
.dma_buf_len = BUFFER_SIZE, // Размер каждого буфера DMA
.use_apll = false // Не использовать APLL для тактирования
};
// Конфигурация пинов I2S
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK, // Пин тактового сигнала
.ws_io_num = I2S_WS, // Пин выбора слова
.data_out_num = -1, // Не используется (мы только принимаем данные)
.data_in_num = I2S_SD // Пин входных данных
};
// Установка драйвера I2S
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
// Настройка пинов I2S
i2s_set_pin(I2S_PORT, &pin_config);
// Инициализация microSD-карты
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); // Инициализация SPI с указанными пинами
if (!SD.begin(SD_CS)) { // Инициализация microSD-карты с указанным пином выбора
Serial.println("Ошибка инициализации microSD-карты!");
while(1); // Бесконечный цикл при ошибке
}
Serial.println("microSD-карта инициализирована.");
// Настройка кнопки
pinMode(BUTTON_PIN, INPUT_PULLUP); // Вход с подтягивающим резистором
// Настройка прерывания на спад сигнала (нажатие кнопки)
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);
Serial.println("Готов к работе. Нажмите кнопку для начала записи.");
}
// Основной цикл программы
void loop() {
// Обработка нажатия кнопки
if (buttonPressed) {
buttonPressed = false; // Сбрасываем флаг
delay(50); // Задержка для подавления дребезга контактов
// В зависимости от текущего состояния, начинаем или останавливаем запись
if (!isRecording) {
startRecording();
} else {
stopRecording();
}
}
// Если идет запись, читаем данные с I2S и записываем на microSD-карту
if (isRecording) {
size_t bytesRead = 0;
// Чтение данных из I2S в буфер
i2s_read(I2S_PORT, &i2sBuffer, BUFFER_SIZE * sizeof(int16_t), &bytesRead, portMAX_DELAY);
// Если данные прочитаны, записываем их в файл
if (bytesRead > 0) {
audioFile.write((const uint8_t*)i2sBuffer, bytesRead);
}
}
}
Сохраняем скетч под своим названием и компилируем код, нажав кнопку в виде галочки «Проверить» в верхнем левом углу окна (под кнопкой меню «Файл»):
В первый раз процесс компиляции займет некоторое время (около 30 секунд), но потом пересборка будет выполняться быстрее.
Рассмотрим общую структуру и алгоритм работы кода. Приложение выполняет следующие основные функции:
1) после подачи питания на контроллер осуществляется инициализация оборудования и периферии (настраивается I2S-интерфейс для работы с аудиосенсором, инициализируется microSD-карта по SPI, назначается кнопка с прерыванием;
2) в основном бесконечном цикле программы ожидается нажатие кнопки, которая расположена на отладочной плате справа от USB-разъёма;

3) при кратковременном нажатии на кнопку стартует процесс записи аудиоданных на карту памяти;
4) запись длится до тех пор, пока не будет вновь кратковременно нажата кнопка. Данные считываются с аудиомодуля блоками по 1024 сэмпла (2048 байт);
5) каждая новая запись сохраняется в новый файл в формате WAV (44,1 кГц, PCM, 16 бит, моно) под именем «recordingX», где X — порядковый номер записи.
Отдельно выделим некоторые особенности работы программы:
— буферизация данных за счёт использования DMA-буферов (DMA — Direct Memory Access, прямой доступ к памяти) позволяет эффективно обрабатывать аудиопоток без потерь;
— реагирование на нажатие кнопки через прерывание гарантирует своевременный отклик системы, не нагружая основной поток выполнения программы лишним опросом вывода микроконтроллера;
— запись в стандартном формате WAV обеспечивает простоту воспроизведения на других устройствах;
— автоматическая нумерация файлов предотвращает перезапись предыдущих аудиотреков.
Заключение
В рамках этого эксперимента наглядно рассмотрен практический пример использования модуля всенаправленного цифрового микрофона INMP411.
Данный аудиодатчик с минимальными искажениями и шумами оцифровывает звук и передаёт данные на управляющий контроллер по I2S-интерфейсу. Правильная настройка и дополнительная цифровая обработка сигнала позволяют получить достаточно неплохое качество записи. Рассмотренный аудиосенсор отлично подходит для организации голосового управления, построения диктофона или системы акустического мониторинга.










