Библиотека PDM
Библиотека PDM позволяет работать с PDM-микрофонами, встроенными на платах Arduino Nano RP2040 Connect и Nano 33 BLE Sense.
Обзор
Библиотека PDM предназначена для работы с PDM-микрофонами (Pulse-density modulation), в том числе со встроенным микрофоном MP34DT05 на плате Arduino Nano 33 BLE Sense.
Чтобы подключить библиотеку в скетч:
#include <PDM.h>
Библиотека берёт на себя всю работу с аудиопотоком, который также становится доступен через библиотеку ArduinoSound.
Как это работает
PDM (Pulse-Density Modulation) — метод представления аналогового сигнала в виде последовательности импульсов. Микрофоны на его основе компактны, потребляют мало энергии и отлично подходят для встраивания прямо в плату. Библиотека принимает поток данных от микрофона, накапливает его в буфере и уведомляет скетч через callback-функцию, когда данные готовы к чтению.
---
Функции
begin()
Описание
Инициализирует PDM-интерфейс и запускает приём данных с микрофона.
Синтаксис
PDM.begin(channels, sampleRate)
Параметры
channels— количество каналов: 1 для моно, 2 для стерео- sampleRate — частота дискретизации в Гц
Возвращает
1 при успехе, 0 при ошибке
Пример
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
Практическое замечание. Вызывайте
begin()только после того, как задалиsetBufferSize()и зарегистрировали callback черезonReceive(). Еслиbegin()вернул0, проверьте, правильно ли выбрана плата в Arduino IDE — библиотека PDM поддерживается только на совместимых платах (Nano 33 BLE Sense, Nano RP2040 Connect и аналогичных).
---
end()
Описание
Останавливает PDM-интерфейс и освобождает занятые ресурсы.
Синтаксис
PDM.end()
Параметры
Отсутствуют
Возвращает
Ничего
Пример
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
//
PDM.end();
---
available()
Описание
Возвращает количество байт, доступных для чтения из PDM-буфера. Это данные, которые уже поступили от микрофона и сохранены в буфере приёма.
Синтаксис
PDM.available()
Параметры
Отсутствуют
Возвращает
Количество байт, готовых к чтению
Пример
// буфер для чтения сэмплов, каждый сэмпл 16-битный
short sampleBuffer[256];
// количество считанных сэмплов
volatile int samplesRead;
//
// запрос количества доступных байт
int bytesAvailable = PDM.available();
// чтение в буфер сэмплов
PDM.read(sampleBuffer, bytesAvailable);
Типичная ошибка. Не вызывайте
available()в основном цикле без callback — данные могут появляться нерегулярно. Лучший подход: проверятьavailable()внутри функции, зарегистрированной черезonReceive().
---
read()
Описание
Читает данные из PDM-буфера в указанный массив.
Синтаксис
PDM.read(buffer, size)
Параметры
buffer— массив для хранения принятых PDM-данныхsize— количество байт для чтения
Возвращает
Фактическое количество прочитанных байт
Пример
// буфер для чтения сэмплов, каждый сэмпл 16-битный
short sampleBuffer[256];
// количество считанных сэмплов
volatile int samplesRead;
//
// запрос количества доступных байт
int bytesAvailable = PDM.available();
// чтение в буфер сэмплов
Int bytesRead = PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 байта на сэмпл
samplesRead = bytesRead / 2;
Практическое замечание. Данные поступают в виде 16-битных сэмплов (
int16_t). Если вы объявляете буфер как массивshortилиint16_t, передавайте вsizeзначениеsizeof(buffer), а не количество элементов — иначе прочитаете вдвое меньше данных, чем ожидаете.
---
onReceive()
Описание
Регистрирует callback-функцию, которая вызывается автоматически, когда новая порция PDM-данных готова к чтению.
Синтаксис
PDM.onReceive(callback)
Параметры
callback — функция без параметров и возвращаемого значения, вызываемая при поступлении новых данных
Возвращает
Ничего
Пример
// буфер для чтения сэмплов, каждый сэмпл 16-битный
short sampleBuffer[256];
// количество считанных сэмплов
volatile int samplesRead;
//
// настройка callback-функции приёма данных
PDM.onReceive(onPDMdata);
// инициализация PDM:
// - один канал (моно режим)
// - частота дискретизации 16 kHz
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
//
void onPDMdata() {
// запрос количества доступных байт
int bytesAvailable = PDM.available();
// чтение в буфер сэмплов
Int bytesRead = PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 байта на сэмпл
samplesRead = bytesRead / 2;
}
Как проверить результат. Добавьте в callback-функцию вывод в
Serial.print()— если данные поступают, вы увидите ненулевые значенияavailable(). Отсутствие вызовов callback обычно означает, чтоbegin()не был выполнен успешно.
---
setGain()
Описание
Устанавливает коэффициент усиления (gain) PDM-интерфейса. Влияет на громкость и чувствительность микрофона.
Синтаксис
PDM.setGain(gain)
Параметры
gain — значение усиления от 0 до 255; если не задано, используется значение по умолчанию — 20
Возвращает
Ничего
Пример
// при необходимости задайте усиление, по умолчанию 20
PDM.setGain(30);
// инициализация PDM:
// - один канал (моно режим)
// - частота дискретизации 16 kHz
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
Практическое замечание. Слишком высокий
gainприводит к клиппингу (искажению) сигнала: сэмплы будут «упираться» в максимальные значенияint16_t. Начните с 20–40 и увеличивайте постепенно, наблюдая за формой сигнала.
---
setBufferSize()
Описание
Задаёт размер буфера (в байтах), используемого PDM-интерфейсом. Должна вызываться до PDM.begin(). Если не вызывать, используется буфер по умолчанию — 512 байт, что достаточно для хранения 256 16-битных сэмплов.
Синтаксис
PDM.setBufferSize(size)
Параметры
size — размер буфера в байтах
Возвращает
Ничего
Пример
PDM.setBufferSize(1024);
// инициализация PDM:
// - один канал (моно режим)
// - частота дискретизации 16 kHz
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
Практическое замечание. Увеличение буфера снижает частоту вызовов callback и уменьшает нагрузку на процессор, но увеличивает задержку обработки. Для задач реального времени (например, определения уровня звука) буфер по умолчанию обычно оптимален. Для записи и FFT-анализа имеет смысл увеличить его до 1024 или 2048 байт.