小智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();

}
相关推荐
女神下凡2 小时前
芯参谋(38):NAND_MCP_电路设计指南
arm开发·单片机·嵌入式硬件·设计规范
嵌入式学习菌2 小时前
FreeRTOS 中断管理实战:BASEPRI 寄存器实验
单片机·嵌入式硬件
HRTOS3 小时前
HRTOS:一个名字背后的目标——不断逼近硬实时
经验分享·单片机·系统架构·51单片机
UrSpecial5 小时前
GPIO 是什么?
单片机·嵌入式硬件
修船大队长8 小时前
配置接受报文每个报文对应一个mailbox配置流程记录
网络·单片机·mcu
搁浅小泽9 小时前
二极管选型技术规范
单片机·嵌入式硬件·汽车
搁浅小泽10 小时前
电感选型技术规范
单片机·嵌入式硬件·汽车
..Dauntless..10 小时前
【stm32】串口——在MCU内部的工作过程
stm32·单片机·嵌入式硬件
lzqrzpt11 小时前
临沂LED驱动电源工程选型标准与工艺对比解析
python·单片机·嵌入式硬件·物联网
小黄蚁11 小时前
使用LVGL模拟示波器创建正弦函数波形
单片机·学习