小智ai,esp32

MIC : microphone : 麦克风,话筒

把外界说话,环境声音这种模拟声波转换成电信号,是音频采集输入设备

声音 ---》 mic采集声波 ---》 转换为数字音频(PDM自带模数转换) ---》 i2s总线送入esp32 ---》 完成录音

PDM : 数字麦 INMP441

speaker : 扬声器,喇叭,,音频输出设备,,,把芯片输出的数字电信号,还原成能听见的声波

i2s : inter-ic sound : 集成电路内置音频总线,,, i two s

专门用来传输数字音频信号的通信协议,,只传声音数据,不做控制指令,,,解决芯片和麦克风或功放之间的音频传输

c 复制代码
#include <stdio.h>

#include "driver/i2s_common.h"
#include "driver/i2s_std.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

// 共用时钟
#define I2S_BCLK 5
#define I2S_WS 6

// max98357
#define I2S_SPK_DOUT 7

// INMP441 输入
#define I2S_MIC_DIN 8


#define audio_buf_len 1024

#define SAMPLE_RATE 16000

// 播放通道
static i2s_chan_handle_t tx_handle = NULL;
// 录音通道
static i2s_chan_handle_t rx_handle = NULL;

esp_err_t ret;
void i2s_init(void) {

    i2s_chan_config_t chan_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0,I2S_ROLE_MASTER);

     ret = i2s_new_channel(&chan_config,&tx_handle,&rx_handle);
    printf("new_channel=%d\n", ret);

    // ESP_ERROR_CHECK();
}

// 初始化max98357
void speaker_init(void) {
    i2s_std_config_t tx_config = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
        .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,I2S_SLOT_MODE_MONO),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED, // master clk,,  外界立体codec声卡时,必须分配一个gpio输出MCK
            .bclk = I2S_BCLK, // 时钟线,, 一个周期传一个 音频单位
            .ws = I2S_WS, // write select
            .dout = I2S_SPK_DOUT,
            .din = I2S_GPIO_UNUSED,
            .invert_flags = {// 硬件布线 / 电平相位错位  需要反转
                .mclk_inv = false,// MCK主时钟是否反转
                .bclk_inv = false,
                .ws_inv = false,
            }


        }
    };


    tx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道


    // ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle,&tx_config));
    ret = i2s_channel_init_std_mode(tx_handle, &tx_config);
    printf("tx_init=%d\n", ret);

    // ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    ret = i2s_channel_enable(tx_handle);
    printf("tx_enable=%d\n", ret);
}

/**
 * INMP441原生输出 24bit,,  如果配置16bit,,只会取其中16bit,,音量特别小,全是噪音,数据错位,,一般用32Bit
 */
void microphone_init(void) {
    i2s_std_config_t rx_config = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
        .slot_cfg = I2S_STD_MSB_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_GPIO_UNUSED,
            .din = I2S_MIC_DIN,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false
            }
        }
    };

    rx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道




    // ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle,&rx_config));

    ret = i2s_channel_init_std_mode(rx_handle, &rx_config);
    printf("rx_init=%d\n", ret);
    // ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
    ret = i2s_channel_enable(rx_handle);
    printf("rx_enable=%d\n", ret);

}


size_t audio_read(void *buf,size_t len) {

    size_t bytes_read;

    /**
     *@param2 : 存储读取到的PCM
     *@param3 : 缓冲区总字节数
     *@param4 : 本次实际读取字节数
     **/
    i2s_channel_read(rx_handle,buf,len,&bytes_read,portMAX_DELAY);


    return bytes_read;

}


void audio_write(void *buf,size_t len) {
    size_t bytes_write;
    i2s_channel_write(tx_handle,buf,len,&bytes_write,portMAX_DELAY);
}


#define AUDIO_FRAME_SIZE 1024
int16_t mic_buffer[AUDIO_FRAME_SIZE];
int16_t spk_buffer[AUDIO_FRAME_SIZE];


void audio_loopback(void) {
    size_t bytes_read;
    size_t bytes_write;
    static int cnt = 0;

    while(1) {
       //  i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);
       //
       //
       //  // 读了多少个样本
       // int sample_count =  bytes_read / sizeof(int32_t);
       //
       //  for(int i=0;i<sample_count;i++) {
       //      spk_buffer[i] =
       //          (int16_t)(mic_buffer[i] >> 14);
       //  }
       //
       //  cnt++;
       //  if (cnt==100) {
       //      printf("%ld\n", mic_buffer[0]);
       //      cnt=0;
       //  }
       //
       //
       //
       //  i2s_channel_write(tx_handle,spk_buffer,sample_count * sizeof(int16_t),&bytes_write,portMAX_DELAY);





        printf("before read \n");
         ret = i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);


        // int sample_count = bytes_read / sizeof(int16_t);

        // 读多少,写多少
        i2s_channel_write(tx_handle,mic_buffer, bytes_read,&bytes_write,portMAX_DELAY);
        //
        // printf("after read ret=%d bytes=%d\n", ret, (int)bytes_read);
        // uint32_t *p=(uint32_t*)mic_buffer;


        // for(int i = 0; i < 32; i++)
        // {
        //     printf("%d\n", (int16_t)mic_buffer[i]);
        // }

        for(int i = 0; i < 32; i += 2)
        {
            printf("%6d\n", mic_buffer[i]);
        }
        printf("\n");

        vTaskDelay(pdMS_TO_TICKS(100));


    }
}

void app_main(void)
{

    i2s_init();
    speaker_init();
    microphone_init();


    printf("audio loopback start...\n");

    audio_loopback();

}

没有杂音:

c 复制代码
#include <stdio.h>

#include "driver/i2s_common.h"
#include "driver/i2s_std.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

// 共用时钟
#define I2S_BCLK 5
#define I2S_WS 6

// max98357
#define I2S_SPK_DOUT 7

// INMP441 输入
#define I2S_MIC_DIN 8


#define audio_buf_len 1024

#define SAMPLE_RATE 16000

// 播放通道
static i2s_chan_handle_t tx_handle = NULL;
// 录音通道
static i2s_chan_handle_t rx_handle = NULL;

esp_err_t ret;
void i2s_init(void) {

    i2s_chan_config_t chan_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0,I2S_ROLE_MASTER);

     ret = i2s_new_channel(&chan_config,&tx_handle,&rx_handle);
    printf("new_channel=%d\n", ret);

    // ESP_ERROR_CHECK();
}

// 初始化max98357
void speaker_init(void) {
    i2s_std_config_t tx_config = {
        .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, // master clk,,  外界立体codec声卡时,必须分配一个gpio输出MCK
            .bclk = I2S_BCLK, // 时钟线,, 一个周期传一个 音频单位
            .ws = I2S_WS, // write select
            .dout = I2S_SPK_DOUT,
            .din = I2S_GPIO_UNUSED,
            .invert_flags = {// 硬件布线 / 电平相位错位  需要反转
                .mclk_inv = false,// MCK主时钟是否反转
                .bclk_inv = false,
                .ws_inv = false,
            }


        }
    };


    tx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道


    // ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle,&tx_config));
    ret = i2s_channel_init_std_mode(tx_handle, &tx_config);
    printf("tx_init=%d\n", ret);

    // ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    ret = i2s_channel_enable(tx_handle);
    printf("tx_enable=%d\n", ret);
}

/**
 * INMP441原生输出 24bit,,  如果配置16bit,,只会取其中16bit,,音量特别小,全是噪音,数据错位,,一般用32Bit
 */
void microphone_init(void) {
    i2s_std_config_t rx_config = {
        .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_GPIO_UNUSED,
            .din = I2S_MIC_DIN,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false
            }
        }
    };

    rx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道




    // ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle,&rx_config));

    ret = i2s_channel_init_std_mode(rx_handle, &rx_config);
    printf("rx_init=%d\n", ret);
    // ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
    ret = i2s_channel_enable(rx_handle);
    printf("rx_enable=%d\n", ret);

}


size_t audio_read(void *buf,size_t len) {

    size_t bytes_read;

    /**
     *@param2 : 存储读取到的PCM
     *@param3 : 缓冲区总字节数
     *@param4 : 本次实际读取字节数
     **/
    i2s_channel_read(rx_handle,buf,len,&bytes_read,portMAX_DELAY);


    return bytes_read;

}


void audio_write(void *buf,size_t len) {
    size_t bytes_write;
    i2s_channel_write(tx_handle,buf,len,&bytes_write,portMAX_DELAY);
}


#define AUDIO_FRAME_SIZE 1024
int16_t mic_buffer[AUDIO_FRAME_SIZE];
int16_t spk_buffer[AUDIO_FRAME_SIZE];


void audio_loopback(void) {
    size_t bytes_read;
    size_t bytes_write;
    static int cnt = 0;

    while(1) {
       //  i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);
       //
       //
       //  // 读了多少个样本
       // int sample_count =  bytes_read / sizeof(int32_t);
       //
       //  for(int i=0;i<sample_count;i++) {
       //      spk_buffer[i] =
       //          (int16_t)(mic_buffer[i] >> 14);
       //  }
       //
       //  cnt++;
       //  if (cnt==100) {
       //      printf("%ld\n", mic_buffer[0]);
       //      cnt=0;
       //  }
       //
       //
       //
       //  i2s_channel_write(tx_handle,spk_buffer,sample_count * sizeof(int16_t),&bytes_write,portMAX_DELAY);





        printf("before read \n");
         ret = i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);


        int sample_count = bytes_read / sizeof(int16_t);

        for(int i=0;i<sample_count;i++) {
            // int32_t sample = mic_buffer[i] >> 16;
            // sample /= 8; // 衰减4-8倍
            // spk_buffer[i] = (uint16_t)sample;


            int16_t sample = mic_buffer[i];
            sample /= 8;
            spk_buffer[i] = sample;
        }


        // 读多少,写多少
        i2s_channel_write(tx_handle,spk_buffer, sample_count*sizeof(int16_t),&bytes_write,portMAX_DELAY);
        //
        // printf("after read ret=%d bytes=%d\n", ret, (int)bytes_read);
        // uint32_t *p=(uint32_t*)mic_buffer;


        // for(int i = 0; i < 32; i++)
        // {
        //     printf("%d\n", (int16_t)mic_buffer[i]);
        // }

        for(int i = 0; i < 8; i ++)
        {
            printf("%6d\n", spk_buffer[i]);
        }
        printf("\n");

        // vTaskDelay(pdMS_TO_TICKS(100));


    }
}

void app_main(void)
{

    i2s_init();
    speaker_init();
    microphone_init();


    printf("audio loopback start...\n");

    audio_loopback();

}
相关推荐
Mr-pn-junction11 小时前
clk_gate
单片机·嵌入式硬件·fpga开发
李永奉19 小时前
杰理可视化SDK开发-【BUG】配置“TWS两边同时按消息使能”功能后,按键单击功能无效失灵
开发语言·单片机·嵌入式硬件·物联网·bug
执迷不悟82319 小时前
51单片机--中断/定时/PWM
单片机·嵌入式硬件·51单片机
A小调的码农21 小时前
OPENOCD+MSYS+VSCODE:从“灯不亮“到“终于亮了“
ide·vscode·stm32·单片机·编辑器
Dlrb12111 天前
单片机通信协议---串口及串口通信
单片机·嵌入式硬件·串口·uart·modbus·波特率·主机从机
嵌入式-老费1 天前
esp32开发与应用(用好ttl转485模块)
stm32·单片机·嵌入式硬件
謓泽1 天前
【6.30】芯片 Bring-up 三步核心|从短路检查到 SPI 排障全拆解!
单片机·嵌入式硬件
KaifuZeng1 天前
模电面试问题汇总四
单片机·嵌入式硬件·面试·模电
csg11071 天前
PIC单片机PWM信号生成与控制
单片机·嵌入式硬件·物联网·自动化