摘要:本文介绍如何使用INMP441模块采集声音

前边介绍了第一个基于I2S通信协议的MAX98357A模块,利用该模块可以播放各种声音文件。今天来介绍如何使用INMP441模块实现声音的采集功能,也就是如何将声音转变成数字信号。

INMP441是一款高性能,低功耗,数字输出的全向MEMS(微型机电系统)麦克风。完整的INMP441由一个MEMS声音传感器,模数转换器(ADC),抗混叠滤波器,电源管理和标准的24位I2S接口组成。I2S接口允许INMP441直接连接到数字处理器,如DSP和微控制器,而无需再使用音频编解码器,极大的降低了开发的难度。INMP441具有高信噪比,是一款出色的近场应用。INMP441具有扁平宽带频率响应,使得采集声音的清晰度很高。

INMP441模块如下图所示:

INMP441具有以下这些特性和规格参数:

1 具有高精度24位数据的数字I2S接口

2 高信噪比为61dBA

3 高灵敏度-26dBFS

4 从60Hz到15kHz的稳定频率响应

5 低功耗:低电流消耗1.4mA

6 电源电压:1.62 V至3.63 V

7 高PSR:-75dBFS

8 尺寸:12mm*14mm

INMP441的接口定义如下所示:

序号

标识

说明

1

SCK

I2S接口的串行数据时钟

2

WS

用于I2S接口的串行数据字选择

3

L/R

左/右声道选择。设置为低电平时,麦克风在I2S帧的左声道输出信号。设置为高电平时,麦克风在右声道输出信号

4

SD

I2S接口的串行数据输出。

5

VCC

输入电源,1.8V至3.3V.

6

GND

电源地

在这里需要注意的是L/R引脚是用来设置本模块属于哪个声道的,也就决定了这个模块在WS信号是高电平还是低电平的时候有输出。一个双声道声音采集系统,如下图所示:

在上图中可以看到左声道的441模块L/R为接地,是低电平状态,右声道的L/R为接电源正极,是高电平状态。这样微处理器在读取数据时,通过控制WS的状态,就可以分别读取左右声道的数据了。

前面的MAX98357A模块的使用借助了第三方的库函数,可以说在开发中基本没有涉及到I2S协议的底层操作。这次通过使用微处理器厂家提供的原生驱动来实现INMP441声音采集后由MAX98357A播放出来的程序。

使用微处理器厂家提供的原始库函数来驱动I2S设备工作,通常需要以下几个步骤:

1.引入头文件

#include <driver/i2s.h>

2.I2S控制器初始化

ESP32处理器内置了2个I2S控制器,因此可以同时与两个音频设备之间传输音频数据。每个I2S控制器都具备以下功能,可由I2S驱动进行配置:

  1. 可用作系统主机或从机
  2. 可用作发射器或接收器
  3. DMA控制器支持流数据采样,CPU无需单独复制每个采样数据

在Arduino中,对I2S控制器进行初始化的方法为:i2s_driver_install()。该方法的主要参数为i2s_config_t类型的结构实例,在该数据结构中,定义了I2S通信的基本参数,主要包括了以下这些属性:

mode:I2S的工作模式。

sample_rate:I2S的采样率

bits_per_sample:I2S的采样位数

channel_format:设置左右声道

communication_format:设置交流格式

dma_buf_count:设置DMA缓冲区的数量

dma_buf_len:设置每个DMA缓冲区的大小

use_apll:设置是否使用精确时钟

intr_alloc_flags:设置如何分配中断

3.设置I2S使用的引脚

使用i2s_set_pin()方法可以设置I2S通信所使用的引脚。该方法所使用的参数为i2s_pin_config_t类型的数据结构,在该结构中定义的了I2S通信所使用的引脚。该结构有如下属性:

bck_io_num:设置串行时钟引脚

ws_io_num:设置左右声道的时钟引脚

data_out_num:设置数据输出引脚

data_in_num:设置数据输入引脚

需要注意的是,在驱动MAX98357A模块的时候,使用的是数据输出引脚,而在驱动INMP441模块的时候,则使用的是输入引脚。不使用的引脚可以赋值-1。ESP32微处理器是支持输入和输出引脚同时使用的,也就是可以同时读入音频数据和输出音频数据。但前提条件是由于收发通道共用一个时钟信号,因此要求两者的配置相同。

4.读入或者输出音频数据。

在前面配置完成后,就可以使用i2s_read()方法读入音频数据,i2s_write()方法输出音频数据了。这两个方法的具体使用,请参照下面的例子。

接下来就看一下这个示例的源代码吧,如下所示:

#include "Arduino.h"

#include <driver/i2s.h>

#define INMP441_WS 22

#define INMP441_SCK 21

#define INMP441_SD 32

#define MAX98357_LRC 27

#define MAX98357_BCLK 26

#define MAX98357_DIN 25

#define SAMPLE_RATE 44100

i2s_config_t i2sIn_config = {

  .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),

  .sample_rate = SAMPLE_RATE,

  .bits_per_sample = i2s_bits_per_sample_t(16),

  .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,

  .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),

  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,

  .dma_buf_count = 8,

  .dma_buf_len = 1024

};

const i2s_pin_config_t i2sIn_pin_config = {

  .bck_io_num = INMP441_SCK,

  .ws_io_num = INMP441_WS,

  .data_out_num = -1,

  .data_in_num = INMP441_SD

};

i2s_config_t i2sOut_config = {

  .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),

  .sample_rate = SAMPLE_RATE,

  .bits_per_sample = i2s_bits_per_sample_t(16),

  .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,

  .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),

  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,

  .dma_buf_count = 8,

  .dma_buf_len = 1024

};

const i2s_pin_config_t i2sOut_pin_config = {

  .bck_io_num = MAX98357_BCLK,

  .ws_io_num = MAX98357_LRC,

  .data_out_num = MAX98357_DIN,

  .data_in_num = -1

};

void setup() {

  // put your setup code here, to run once:

  Serial.begin(115200);

  i2s_driver_install(I2S_NUM_0, &i2sIn_config, 0, NULL);

  i2s_set_pin(I2S_NUM_0, &i2sIn_pin_config);

  i2s_driver_install(I2S_NUM_1, &i2sOut_config, 0, NULL);

  i2s_set_pin(I2S_NUM_1, &i2sOut_pin_config);

}

void loop() {

  // put your main code here, to run repeatedly:

  size_t bytes_read;

  int16_t data[512];

  esp_err_t result = i2s_read(I2S_NUM_0, &data, sizeof(data), &bytes_read, portMAX_DELAY);

  result = i2s_write(I2S_NUM_1, &data, sizeof(data), &bytes_read, portMAX_DELAY);

}

好了,I2S通信协议的使用方法就介绍到这里了。

Logo

更多推荐