INMP441 I2S 数字麦克风
| 器材 | 数量 | 参考 |
|---|---|---|
| INMP441 I2S 麦克风模块 | 1 | — |
价格随渠道波动,以购买页实时为准。
想给 ESP32 做一个能听懂你说话的语音助手,或者做个能录音、能声控开灯的小东西,第一件事都是先有一个"耳朵"——一个把声音变成数据的麦克风。问题是,你随手买的那种三个脚的小麦克风(模拟麦)插上去,读出来全是噪声、嗡嗡声,根本听不清人话。要让 AI 听得清,你需要的是 INMP441 这类数字麦克风:声音在芯片内部就已经变成了干净的数字信号,沿着三根线直接灌进 ESP32,主控拿到的就是一段段现成的音频采样。几乎所有自制语音助手、ESP32 录音项目,都从它开始。
工作原理
INMP441 里面是一片极小的 MEMS 振膜。声音是空气的压力波动,振膜感受到声压就会跟着微微振动,这一步和所有麦克风一样,把声音变成了一个微弱的模拟电信号。
关键的不同在下一步。普通模拟麦克风到这里就结束了——它直接把这个微弱的模拟信号从引脚送出去,你得在 ESP32 那头再接一个 ADC(模数转换器)把它数字化。这条模拟信号在杜邦线上跑的一路上,电源纹波、Wi-Fi 干扰、其它信号串扰,全都会叠加上去,等到了 ADC 已经脏得不行,再加上 ESP32 内置 ADC 本身精度有限,最后录到的就是一片噪声里隐约的人声。
INMP441 把转换这一步搬到了芯片内部。振膜出来的模拟信号在芯片里就直接被一个高质量的转换器变成了数字信号(PCM 采样),然后通过 I2S 总线以纯数字的方式送出去。数字信号只有 0 和 1,沿途有点干扰也不影响判读,所以 INMP441 给 ESP32 的音频干净、稳定、信噪比高(约 61 dB),而且你不用再外接任何 ADC。这就是为什么做 AI 语音的人几乎清一色用数字麦——AI 要识别的是人声的细节,输入越干净,识别率越高。关于模拟和数字的根本差别,可以看模拟与数字。
I2S 是专门传音频的数字总线,INMP441 用到三根信号线:
- SCK(位时钟,也叫 BCK):每一个数据位对齐一个时钟节拍,由 ESP32 产生。
- WS(字选择,也叫 LRCLK):标记当前传的是左声道还是右声道的采样,由 ESP32 产生。INMP441 是单声道麦克风,靠它来对齐采样。
- SD(串行数据):INMP441 把 PCM 采样一位一位串行送出来,这是真正的音频数据。
ESP32 不停地给出时钟,INMP441 就跟着节拍把音频采样一段段吐出来,主控把它们攒进缓冲区,就得到了一段可以分析、可以保存、可以送去识别的数字音频。
接线
| INMP441 | ESP32 | 说明 |
|---|---|---|
| VDD | 3.3V | 只能 3.3V,不要接 5V |
| GND | GND | 共地 |
| SCK | GPIO14 | I2S 位时钟(BCK),ESP32 输出 |
| WS | GPIO15 | I2S 字选择(LRCLK),ESP32 输出 |
| SD | GPIO32 | I2S 数据,麦克风输出给 ESP32 |
| L/R | GND | 选声道:接 GND = 左声道,接 VDD = 右声道 |
引脚不是固定死的,ESP32 的 I2S 可以映射到大多数 GPIO,上表只是一组常用配置,代码里要和它对上。
L/R 脚是个容易踩的坑。 它决定 INMP441 把自己的采样放在左声道还是右声道的时隙里。接 GND 时它在左声道说话,接 VDD 时在右声道。这一脚必须接死(接 GND 或 VDD),千万别悬空——悬空时声道不确定,你会发现读出来一半是数据、一半是 0,或者干脆全 0。最常见做法是接 GND(左声道),代码里也按左声道读。
完整代码
下面用 ESP32 的 I2S 驱动配置成 16kHz 采样、单声道,循环读音频缓冲并算出当前音量(RMS,均方根,反映声音大小)打到串口。
#include <driver/i2s.h>
// —— I2S 引脚,和接线表对应 ——
#define I2S_SCK 14 // 位时钟 BCK
#define I2S_WS 15 // 字选择 LRCLK
#define I2S_SD 32 // 数据 SD
#define SAMPLE_RATE 16000 // 采样率 16kHz,语音够用
#define I2S_PORT I2S_NUM_0
#define BUF_SAMPLES 512 // 每次读多少个采样
// INMP441 每个采样是 32 位,有效数据在高位
int32_t samples[BUF_SAMPLES];
void setupI2S() {
i2s_config_t cfg = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // INMP441 按 32 位读
.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 = 4,
.dma_buf_len = BUF_SAMPLES,
.use_apll = false,
};
i2s_pin_config_t pins = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE, // 只收不发
.data_in_num = I2S_SD,
};
i2s_driver_install(I2S_PORT, &cfg, 0, NULL);
i2s_set_pin(I2S_PORT, &pins);
}
void setup() {
Serial.begin(115200);
setupI2S();
Serial.println("I2S 麦克风就绪,对着说话试试");
}
void loop() {
size_t bytesRead = 0;
i2s_read(I2S_PORT, samples, sizeof(samples), &bytesRead, portMAX_DELAY);
int n = bytesRead / sizeof(int32_t);
if (n == 0) return;
// 算 RMS 音量
double sum = 0;
for (int i = 0; i < n; i++) {
// INMP441 有效数据在高 24 位,右移把它对齐成正常幅值
int32_t s = samples[i] >> 11;
sum += (double)s * s;
}
double rms = sqrt(sum / n);
Serial.printf("RMS 音量: %.0f\n", rms);
delay(50);
}
I2S 的 API 在 ESP-IDF 不同版本、Arduino-ESP32 不同版本之间有差异:新版 ESP-IDF 已改用
driver/i2s_std.h这套新接口,上面用的是兼容性更好的旧driver/i2s.h。具体函数名、结构体字段以你装的 ESP-IDF / Arduino-ESP32 版本头文件为准,不要照抄函数名硬套。
你应该看到什么
打开串口监视器(115200),程序会不停打印 RMS 音量值:
- 安静环境、不出声:RMS 是一个很小的基底值(比如几十到一两百),上下小幅波动,这是环境底噪。
- 对着麦克风说话:你一开口,RMS 立刻蹿高,说话越大声、麦克风越近,数值越大;停下又落回基底。
- 拍手或敲桌子:会看到一个瞬间的尖峰然后回落。
只要数值能跟着你的声音明显起伏,就说明麦克风、I2S 配置、声道都对上了。如果说话时数值纹丝不动、或者一直是 0,往下看故障排查。
读数解读
i2s_read 读回来的是一段 PCM 采样数组——把连续的声波按每秒 16000 次(采样率)的频率"切片",每一片用一个整数记录那一刻的振幅。32 位是位深,决定每个采样的精度,INMP441 实际有效的是高 24 位。这一串数字连起来,就是一段可以还原成声音的数字音频。
拿到这串采样,你能做很多事:
- 算音量:像代码里那样求 RMS,就能知道现在吵不吵、有没有人在说话。
- 做 VAD(语音活动检测):靠音量和过零率判断"现在有人在说话 / 现在是静音",只在有人说话时才往下处理,省电省算力。
- 存成 WAV 录音:给 PCM 数据加个 WAV 文件头写到 SD 卡,就是一段录音。
- 送去识别:把音频流送给云端或本地的语音识别,变成文字或指令,这就是语音助手的入口,详见唤醒词与语音识别与合成。
选型 / 避坑
| 类型 | 代表型号 | 接口 | 定位 |
|---|---|---|---|
| 数字 I2S 麦 | INMP441 / ICS-43434 | I2S | AI 语音首选,数字直出、噪声低、无需 ADC |
| 模拟麦 + ADC | MAX9814 | 模拟(接 ADC) | 接线简单,但要外接/用片内 ADC,噪声大 |
| 数字 PDM 麦 | 多种 PDM 模块 | PDM | 另一种数字接口,单线脉冲密度,需主控支持 PDM |
核心区别:模拟麦(MAX9814 这类)给的是脆弱的模拟信号,要靠 ADC 数字化,ESP32 片内 ADC 精度有限、又容易吃干扰,录人声噪声明显,做着玩可以、做 AI 语音不够看。PDM 麦也是数字输出,但用的是单线脉冲密度调制,需要主控有 PDM 接口、还要做抽取滤波,没 I2S 直观。INMP441 这类 I2S 数字麦干净、好接、库多,是做语音识别、录音、语音助手的标准选择。
三个最常翻车的点。① L/R 脚必须接死:接 GND 取左声道、接 VDD 取右声道,悬空会读到一半 0 或全 0,而且代码里的 channel_format(取左还是取右)要和它对上。② I2S 引脚要和代码一一对应:SCK/WS/SD 接到哪个 GPIO,代码里的 bck_io_num/ws_io_num/data_in_num 就得填哪个,接反读不出。③ 采样率和位深要匹配:INMP441 按 32 位读,bits_per_sample 设 32 位再在算的时候右移取高位;位深设错幅值就乱。另外,认真做语音项目建议直接上 ESP32-S3——它算力更强、自带向量指令,跑唤醒词和本地识别比老 ESP32 从容得多。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 读到的采样全是 0 | L/R 悬空 / 声道选错 / SD 没接对 | L/R 接死并和 channel_format 对上;查 SD 接到 data_in_num 那个脚 |
| 说话音量值不变、不响应 | I2S 引脚和代码对不上 / 麦克风没供电 | 核对 SCK/WS/SD 与代码引脚;确认 VDD 是 3.3V |
| 录音全是噪声、听不清 | 采样率或位深设错 / 取高位没右移 | 按 32 位读、采样率 16kHz,算幅值时右移取有效高位 |
| 声音忽大忽小或断续 | DMA 缓冲太小 / 读取间隔太久 | 加大 dma_buf_count,loop 里别 delay 太长 |
| 一接 5V 就不工作甚至发热 | INMP441 只能 3.3V | 立即改回 3.3V 供电 |
进阶 / 变体
在 loop() 里用 RMS 加一道阈值,就是最简单的 VAD(语音活动检测)——只在有人说话时才点亮处理流程,平时省电待机:
const double VOICE_THRESHOLD = 800; // 阈值按你的环境底噪调
void loopVAD() {
size_t bytesRead = 0;
i2s_read(I2S_PORT, samples, sizeof(samples), &bytesRead, portMAX_DELAY);
int n = bytesRead / sizeof(int32_t);
if (n == 0) return;
double sum = 0;
for (int i = 0; i < n; i++) {
int32_t s = samples[i] >> 11;
sum += (double)s * s;
}
double rms = sqrt(sum / n);
if (rms > VOICE_THRESHOLD) {
Serial.println("检测到有人说话 → 开始录音/识别");
// 在这里把这段音频攒起来,送去语音识别
}
}
把检测到的这段音频接上语音识别,就从"听见声音"升级到"听懂话",这正是 AI 语音助手的核心链路——可以顺着语音识别与合成和唤醒词往下做。开源项目小智 AI 语音助手就是用 ESP32 + I2S 麦克风跑通了从听到说的完整闭环,是很好的实战参照。
典型应用
- 语音助手:I2S 麦做"耳朵",配合唤醒词、语音识别,做一个能对话的硬件。
- 录音设备:PCM 直接存 WAV 到 SD 卡,干净无杂音。
- 声控开关:靠音量或简单识别,拍手、喊一声就开灯关灯。
- 噪声监测:长期统计 RMS,做环境噪声分贝监测仪。
- AI 语音交互:音频流送本地或云端模型,做实时对话、语音控制智能家居。
小结 · 相关
INMP441 是一颗数字麦克风:声音在芯片里就变成干净的 PCM,通过 I2S 三根线(SCK/WS/SD)直送 ESP32,无需外接 ADC、抗干扰、信噪比高,是 AI 语音项目的标准"耳朵"。用好它记住三件事:L/R 脚接死并和声道配置对上、I2S 引脚和代码一一对应、采样率和位深匹配。做认真的语音项目,优先选算力更强的 ESP32-S3。
参数以 datasheet 为准;本页公开资料整理,接线与代码请结合实物验证。