esp32开发与应用(边采样边播放音频)

发布时间:2026/7/25 1:57:33
esp32开发与应用(边采样边播放音频) 【 声明版权所有欢迎转载请勿用于商业用途。 联系信箱feixiaoxing 163.com】前面说到了音频的播放一般采用i2s的格式也就是bclk、lrclk、sda。今天来学一下麦克风。如果是播放音乐没有麦克风也是可以的。但很多时候我们还是有麦克风采样、录制的需求。所以这个时候就要学一下麦克风采样。1、麦克风接口一般mic有两种接口一种是pdm接口也就是只有clk和data。还有一种就是i2s接口这种就和之前的音乐播放一样的接口即3个pinlrclk、bclk和sda。2、管脚分配如果是mic一般走4和5如果是i2s一般走26、25、22。3、电压分配3.3v即可。4、芯片选型这次采用的麦克风mic采样芯片和前面一篇文章其实是一块板子使用的芯片是lm2718。5、示例代码考虑到之前学习过音频播放这里采用的方式是一边采样、一边播放的方式。这样既可以巩固原来的知识点又可以学习到新的mic采样知识。整个就是一个扩音器的效果。#include stdint.h #include stdlib.h #include freertos/FreeRTOS.h #include freertos/task.h #include esp_log.h #include driver/i2s_std.h #include driver/i2s_pdm.h static const char *TAG MIC_LOOPBACK; #define SAMPLE_RATE 16000 // ---- Mic (PDM RX) pins ---- #define PDM_CLK_GPIO GPIO_NUM_4 #define PDM_DATA_GPIO GPIO_NUM_5 // ---- Speaker (I2S STD TX, NS4168) pins ---- #define I2S_BCLK GPIO_NUM_26 #define I2S_WS GPIO_NUM_25 #define I2S_DOUT GPIO_NUM_22 #define READ_CHUNK_SAMPLES 512 // ~32ms per chunk 16kHz, controls latency static i2s_chan_handle_t rx_chan NULL; // mic static i2s_chan_handle_t tx_chan NULL; // speaker // ---------- Mic: PDM RX on I2S_NUM_0 ---------- static void mic_init(void) { i2s_chan_config_t chan_cfg I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(chan_cfg, NULL, rx_chan)); i2s_pdm_rx_config_t pdm_rx_cfg { .clk_cfg I2S_PDM_RX_CLK_DEFAULT_CONFIG(SAMPLE_RATE), .slot_cfg I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg { .clk PDM_CLK_GPIO, .din PDM_DATA_GPIO, .invert_flags { .clk_inv false }, }, }; pdm_rx_cfg.slot_cfg.slot_mask I2S_PDM_SLOT_LEFT; // try _RIGHT if silent/noisy ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_chan, pdm_rx_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(rx_chan)); ESP_LOGI(TAG, Mic (PDM RX) ready on I2S_NUM_0, CLK%d DATA%d, PDM_CLK_GPIO, PDM_DATA_GPIO); } // ---------- Speaker: standard I2S TX on I2S_NUM_1 (same as your NS4168 code) ---------- static void speaker_init(void) { i2s_chan_config_t chan_cfg I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(chan_cfg, tx_chan, NULL)); i2s_std_config_t std_cfg { .clk_cfg I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE), .slot_cfg I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg { .mclk I2S_GPIO_UNUSED, .bclk I2S_BCLK, .ws I2S_WS, .dout I2S_DOUT, .din I2S_GPIO_UNUSED, }, }; ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, std_cfg)); ESP_ERROR_CHECK(i2s_channel_enable(tx_chan)); ESP_LOGI(TAG, Speaker (I2S STD TX) ready on I2S_NUM_1, BCLK%d WS%d DOUT%d, I2S_BCLK, I2S_WS, I2S_DOUT); } // ---------- Loop: read from mic, write straight to speaker ---------- static void loopback_task(void *arg) { int16_t *buf malloc(READ_CHUNK_SAMPLES * sizeof(int16_t)); if (!buf) { ESP_LOGE(TAG, malloc failed); vTaskDelete(NULL); return; } // Optional software gain: raw PDM mic level is often quiet. // Adjust or set to 1.0f if it clips/distorts. const float GAIN 4.0f; while (1) { size_t bytes_read 0; esp_err_t ret i2s_channel_read(rx_chan, buf, READ_CHUNK_SAMPLES * sizeof(int16_t), bytes_read, portMAX_DELAY); if (ret ! ESP_OK || bytes_read 0) { continue; } int samples bytes_read / sizeof(int16_t); for (int i 0; i samples; i) { int32_t v (int32_t)(buf[i] * GAIN); if (v INT16_MAX) v INT16_MAX; if (v INT16_MIN) v INT16_MIN; buf[i] (int16_t)v; } size_t bytes_written 0; ESP_ERROR_CHECK( i2s_channel_write(tx_chan, buf, bytes_read, bytes_written, portMAX_DELAY) ); } free(buf); vTaskDelete(NULL); } void app_main(void) { ESP_LOGI(TAG, Mic - Speaker realtime loopback starting); mic_init(); speaker_init(); xTaskCreate(loopback_task, loopback_task, 4096, NULL, 5, NULL); }6、测试和验证测试的话就是等程序烧入之后看看对着mic说话的时候听听喇叭里面有没有声音就好。