【Follow me第二季第4期】PDM 数据打印及音频波形
[复制链接]
本帖最后由 garoa 于 2024-12-21 11:58 编辑
PDM 简介
PDM(Pulse Density Modulation:脉冲密度调制)是一种数字信号调制方式,通过调整脉冲的密度来表示模拟信号的幅度。与常见的 PWM(脉宽调制)相比,PDM 的工作原理更加精简,它是通过不同的 “1” 和 “0” 信号密度来表示音频信号的强度。
PDM 的工作原理
在 PDM 中,音频信号被转换为一系列的脉冲,脉冲的数量和频率对应音频信号的强弱。举个例子,如果音频信号的幅度较大,那么 PDM 信号中 “1” 的脉冲会比较频繁;如果音频信号的幅度较小,则 “1” 的脉冲密度较低。
与传统的模拟信号相比,PDM 信号优点
易于数字化处理:PDM 信号本身已经是数字信号,可以直接送入数字处理器进行后续处理。
抗噪能力强:由于信号是通过高频率的脉冲来传输,PDM 对噪声的抗干扰能力较强。
低功耗:通常,PDM 麦克风的功耗较低,适合于便携式设备。
MP34DT06JTR 简介
Arduino Nano RP2040 Connect 板载的麦克风 ST MP34DT06JTR 是一颗单声道麦克风,由意法半导体(STMicroelectronics)生产。详细资料见 ST 官方数据手册 Datasheet - MP34DT06J 。
特点
传感器类型:基于MEMS(微机电系统)技术,拥有高灵敏度和低功耗。
输出格式:提供PDM(脉冲密度调制)信号输出,这种格式适合直接接入微控制器的PDM解码接口。
频率范围:能够捕捉20Hz到20kHz的声音,非常适合用于语音识别、音频采集等场景。
供电电压:支持 1.8V 到 3.6V 的宽电压范围。
方向性:全向(Omnidirectional),意味着它能够均匀捕捉来自各方向的声音。
工作原理
MP34DT06JTR 通过拾取声波振动,生成对应的数字PDM信号。微控制器通过解码PDM信号,转换为音频样本。
在 Arduino 平台上使用 PDM 麦克风
Arduino Nano RP2040 Connect 提供了对 PDM 麦克风的支持,Arduino 官方有专门的 PDM 库,文档参考 PDM Library。
初始化
:PDM初始化
注:channels 为通道数量,1 为单声道,2 为立体声;sampleRate 为采样率。
获取数据:
:获取可读字节数
:接收 PDM 数据
注:buffer 为用于存储 PDM 数据的数组;size 为读取的字节数。
演示视频
示例代码
因为板载的麦克风是一颗单声道麦克风,所以 channels = 1。PDM 采样率为 20000 Hz。
#include <PDM.h>
// 声道数量(仅支持单声道,固定为 1)
static const char channels = 1;
// PDM 数据的采样率(单位:Hz)
static const int frequency = 20000;
// 用于存储音频样本的缓冲区,每个样本是 16 位
short sampleBuffer[512];
// 读取到的音频样本数量,使用 volatile 修饰以确保线程安全
volatile int samplesRead;
void setup() {
// 初始化串口,用于调试和打印信息
Serial.begin(9600);
// 等待串口连接(仅用于调试模式)
while (!Serial);
// 配置 PDM 麦克风的数据接收回调函数
PDM.onReceive(onPDMdata);
// 初始化 PDM 麦克风
if (!PDM.begin(channels, frequency)) {
Serial.println("PDM 初始化失败!");
while (1); // 如果初始化失败,则进入死循环
}
}
void loop() {
// 检查是否有新的音频样本
if (samplesRead > 0) {
// 遍历并打印读取到的样本数据
for (int i = 0; i < samplesRead; i++) {
Serial.println(sampleBuffer[i]); // 打印单声道样本值
}
// 清除样本读取计数
samplesRead = 0;
}
}
/**
* 回调函数,用于处理 PDM 麦克风采集的数据。
* 注意:该函数在中断服务程序(ISR)中执行,必须保持简洁高效。
*/
void onPDMdata() {
// 查询缓冲区中可用字节数
int bytesAvailable = PDM.available();
// 从缓冲区读取音频数据到样本缓冲区
PDM.read(sampleBuffer, bytesAvailable);
// 每个样本为 16 位(2 字节),计算样本数量
samplesRead = bytesAvailable / 2;
}
|