ESP32-S3-CAM:连接 INMP441 麦克风实现音频回环
·
1、认识硬件:引脚说明与引脚分配
| 引脚 | 功能 | 接 ESP32-S3 |
|---|---|---|
| LR | 左右声道选择 | GND 接地 负极 |
| WS | 字选择(LRCK) | GPIO 1 |
| SCK | 位时钟(BCLK) | GPIO 2 |
| SD | 串行数据 | GPIO 42 |
| VDD | 电源(1.8-3.3V) | 3.3V 正极 |
| GND | 地 | GND 接地 负极 |
2、面包板连接硬件


刚开始忘记接GND接地了,好像也能工作,正确接法

3、写代码测试
1)用AI工具写demo代码
提示词:
我通过面包板将ESP32-S3-CAM主板上连接了一个INMP441 麦克风,引脚设置如下:
SD连接G42,WS连接G1,SCK连接G2,写一段极简初始化和自动检测代码
AI提示注意:GPIO1 和 GPIO2 是 Strapping 引脚,启动时会影响下载模式。如果下载困难,建议改用其他引脚(如 GPIO41/45/47)。
因为mic使用时我们并不会下载程序,因此影响有限,是可以用的。
AI生成的代码:程序一直在采集音量大小然后输出
#include <driver/i2s.h>
#define MIC_SCK 2
#define MIC_WS 1
#define MIC_SD 42
void setup() {
Serial.begin(115200);
// I2S配置
i2s_config_t cfg = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = 16000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = 64
};
i2s_driver_install(I2S_NUM_0, &cfg, 0, NULL);
i2s_pin_config_t pins = {
.bck_io_num = MIC_SCK,
.ws_io_num = MIC_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = MIC_SD
};
i2s_set_pin(I2S_NUM_0, &pins);
Serial.println("麦克风初始化完成");
}
void loop() {
int16_t buf[64];
size_t n;
i2s_read(I2S_NUM_0, buf, sizeof(buf), &n, portMAX_DELAY);
int sum = 0;
for (int i = 0; i < n / 2; i++) sum += abs(buf[i]);
Serial.print("音量: ");
Serial.println(sum / (n / 2));
delay(100);
}
2)运行效果
一直不断有输出,说话声音大点 数值变大,说明运行正常。

4、进阶功能:音频回环测试
1)功能:将 MIC录音后再通过功放和喇叭播放出来
2)引脚分配说明
尽量都用通用口,避开使用与SD卡冲突的,与摄像头冲突,与系统默认占用的口都避开,但是这样 走线比较丑陋。
// 功放引脚(输出)- 保持不变
#define AMP_LRC 41 // ✅
#define AMP_BCLK 47 // ✅
#define AMP_DIN 21 // ✅
// 麦克风引脚(输入)- 修正冲突
#define MIC_WS 5 // 改为 5,避开 UART0
#define MIC_BCLK 2 // ✅ 保持
#define MIC_DOUT 8 // 改为 8,避开 SD_D3 (GPIO42)
3)硬件布局

4)代码
/*
* ESP32-S3 音频回环 - 降噪优化版
* 解决嗡嗡声/电源干扰
*/
#include <driver/i2s.h>
#define AMP_LRC 41
#define AMP_BCLK 47
#define AMP_DIN 21
#define MIC_WS 5
#define MIC_BCLK 2
#define MIC_DOUT 8
#define I2S_TX I2S_NUM_0
#define I2S_RX I2S_NUM_1
#define SAMPLE_RATE 48000
#define BUFFER_SIZE 512
// 降噪参数
#define NOISE_GATE_THRESHOLD 500 // 噪声门限(低于此值静音)
#define HIGH_PASS_ALPHA 0.95f // 高通滤波系数(滤除直流/50Hz工频)
#define AGC_MAX_GAIN 5 // 最大自动增益
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("\n=== 音频回环(降噪版)===");
if (!initMicrophone()) return;
if (!initAmplifier()) return;
Serial.println("✅ 就绪");
Serial.println("命令: s=开始, x=停止, +/-=调整噪声门限");
Serial.printf("当前噪声门限: %d\n", NOISE_GATE_THRESHOLD);
}
bool running = false;
int noiseGate = NOISE_GATE_THRESHOLD;
float prevSample = 0; // 高通滤波历史值
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c == 's') {
running = true;
Serial.println("▶️ 开始(带降噪)");
}
else if (c == 'x') {
running = false;
i2s_zero_dma_buffer(I2S_TX);
Serial.println("⏹️ 停止");
}
else if (c == '+' && noiseGate < 2000) {
noiseGate += 100;
Serial.printf("噪声门限: %d\n", noiseGate);
}
else if (c == '-' && noiseGate > 100) {
noiseGate -= 100;
Serial.printf("噪声门限: %d\n", noiseGate);
}
}
if (running) loopbackAudioFiltered();
}
bool initMicrophone() {
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_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = BUFFER_SIZE,
.use_apll = false
};
i2s_driver_install(I2S_RX, &cfg, 0, NULL);
i2s_pin_config_t pins = {
.bck_io_num = MIC_BCLK,
.ws_io_num = MIC_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = MIC_DOUT
};
i2s_set_pin(I2S_RX, &pins);
return true;
}
bool initAmplifier() {
i2s_config_t cfg = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = BUFFER_SIZE,
.use_apll = true,
.tx_desc_auto_clear = true
};
i2s_driver_install(I2S_TX, &cfg, 0, NULL);
i2s_pin_config_t pins = {
.bck_io_num = AMP_BCLK,
.ws_io_num = AMP_LRC,
.data_out_num = AMP_DIN,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_set_pin(I2S_TX, &pins);
i2s_zero_dma_buffer(I2S_TX);
return true;
}
// 带降噪的回环处理
void loopbackAudioFiltered() {
int16_t rxBuffer[BUFFER_SIZE];
size_t bytesRead = 0;
if (i2s_read(I2S_RX, rxBuffer, sizeof(rxBuffer), &bytesRead, 0) != ESP_OK) return;
if (bytesRead == 0) return;
int samples = bytesRead / 2;
int16_t txBuffer[BUFFER_SIZE * 2];
for (int i = 0; i < samples; i++) {
int16_t raw = rxBuffer[i];
// 1. 高通滤波:滤除直流偏置和50/60Hz工频干扰
float filtered = raw - prevSample * (1.0f - HIGH_PASS_ALPHA);
prevSample = raw;
// 2. 噪声门:小信号静音(消除底噪)
int32_t sample = (int32_t)filtered;
if (abs(sample) < noiseGate) {
sample = 0; // 静音
}
// 3. 自动增益(可选)
// sample = sample * AGC_MAX_GAIN / 2;
// 4. 硬限幅
if (sample > 32767) sample = 32767;
if (sample < -32768) sample = -32768;
// 双声道输出
txBuffer[i * 2] = (int16_t)sample;
txBuffer[i * 2 + 1] = (int16_t)sample;
}
size_t written = 0;
i2s_write(I2S_TX, txBuffer, samples * 4, &written, portMAX_DELAY);
}
5)运行结果
代码上传完毕后,在串口监视器里输入 s 表示开始 回环,喇叭离mic远一点,要不然有干扰
开始后就可以对着mic说话,喇叭这边就能听到有声音输出,声音相对模糊

更多推荐
所有评论(0)