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说话,喇叭这边就能听到有声音输出,声音相对模糊

更多推荐