摘要:本文介绍如何使用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驱动进行配置:
- 可用作系统主机或从机
- 可用作发射器或接收器
- 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通信协议的使用方法就介绍到这里了。
版权归原作者 一起玩儿科技 所有, 如有侵权,请联系我们删除。