概述
最近在做一个功能类似于对讲机通话的功能,本来在网上感觉很容易找到同样的案例复刻,结果发现大多数都是用esp32,或者说电脑作为上位机传输wav音频解码播放的效果,也有很相仿的,但是都测试结果不尽人意,经过不断摸索下面是我给出的方案。
但是本篇文章只限于单片机mcu芯片通过i2s读取麦克风inmp441的音频数据再通过i2s传输给MAX98357功放芯片(i2s转dac),这个功放芯片再连接到扬声器并进行播放,整体我已经测试过 效果很好
I2S协议
注意这虽然很像i2c协议 但是并不是,i2s协议是一种音频传输的协议,用来传输音频数据,i2s一般是三个引脚 分别是SD SCK WS
其中SCK用来提供时钟信号 ,WS协议是用于指示当前数据位是左声道还是右声道,一般来说低电平是左,高是右。SD是串行数据线传输音频数据。像i2c一样 i2s上应该也可以连接多个设备,比如一对麦克风和扬声器, 只需要做的是SCK和WS连接相同引脚 而SD作为数据输出单独联机一个引脚。不过在本文里面 为了方便读者理解,我使用了两个i2s总线 一个负责读取麦克风数据 一个负责播放麦克风。关于i2s协议的更多信息在网上已经有很详细的解释了可以很方便查阅到。
INMP441麦克风
价格8R(我买的这样的)
目前我找了很多麦克风方案,就这一款方案应该是全网比较多的类型,这个麦克风是直接使用i2s协议读取的,直接连接到芯片即可。另外特别要提到的是这个麦克风是全向麦克风,很容易捕捉到噪声,所以其实不太建议把扬声器和麦克风放在一起使用,会引起啸叫
引脚定义:
VDD | 3.3v电源 |
---|---|
GND | 接地 |
SD | I2S协议的SD引脚用来数据输出 |
SCK | I2S协议里面的时钟 信号输入 |
WS | I2S协议的字选择引脚 |
L/R | 用来区分这个麦克风是左声道还是右声道 没有要求的话就直接接地就行了 |
MAX98357
价格:4.7R
这是一个音频功放芯片并且他具有i2s转DAC的功能(重点),支持扬声器的阻抗4欧姆到8欧姆,最大提供功率是3W
类型:D类音频放大器
引脚定义
VDD | 电源引脚,通常连接到5v |
---|---|
GND | 接地 |
DIN | i2s协议的数据输入引脚SD |
BCLK | i2s协议的时钟引脚SCK |
LRC | I2S协议的字选择引脚WS,代表左声道还是右声道 |
OUT+ | 音频输出正极,连接扬声器的正极 |
OUT- | 音频输出负极,连接扬声器的负极 |
GAIN | 增益引脚,可浮空 |
SD | 静音引脚,可浮空 |
如果你对扬声器没有太大的要求 其实1 块2块的扬声器就已经够用了
主控芯片stm32f407vet6
我使用的这个芯片其实是GD32f407vet6但是实际上所有的引脚类型什么的跟stm同类型的完全没有区别 ,而且我也是拿cubeide开发的所以完全不影响。
需要单独说一下的是,你自己的芯片需要至少一个i2s协议的片上外设,我不知道有没有软件i2s的东西。
连线图
根据上面的引脚定义把红色框框的是i2s2的三根线 蓝色框框的是I2S_3的三根线
红色连接到麦克风的i2s的三根线 蓝色则对应的是MAX98357
开始配置
首先根据引脚定义连接inmp441模块,max98357模块
1:配置I2S_2总线 配置这个是用来读取麦克风INMP441数据的总线
注意按照我红色框框的地方配置, 特别要说的一点是inmp441这个模块输出的是24位 所以只能选择我这个Data and Frame Format的配置
下面48HZ是采样率 根据你自己的情况选择就行了 只不过在下面的i2s 3也要配置成一样的采样率
2.配置i2s2的dma
同样按照我的配置方式配置
3.配置I2S 3总线 这个总线是把i2s 2接受到的数据传输给MAX98357功放模块
注意这里因为是发送数据 所以要把 Transmission Mode配置为 Mode Master Transmit
4.配置I2S_3的dma
5:接着生成代码后 只需要在main.c里面写简单两个函数就行了
这里dma的数组大小最好是1024 ,如果太小,那么每次传输的数据就比较小 效果就会变差 失真也比较高
一般来说到这一步就已经成功完成了,烧录进芯片就可以实现功能效果了
过程经历(Debug)
首先要说一个我最开始遇到的一个认知理解问题。
最开始当我了解到i2s读取麦克风数据并传输给芯片的时候的, 因为i2s读取的数据是有正负性的 而且数据范围也很大,而我 拿到手上的麦克风是只有正负极,正极是要通过DAC模拟电压值变化来进行播放声音的。
很显然地可以理解到我可以在单片机上接收到i2s的音频数据再把这个数据映射到0-4095范围(DAC一般是12位的)然后把DAC的输出引脚接在扬声器的正极 负极接地。
我确实也是这样做的,音频确实是传输有效果了,但是音质差的不行,别说人声了 连一点稍微有规律的音乐都听不出来。我最开始是以为是电源的噪音,或者要做数据滤波,但是都试过了都没有办法解决这个问题,拖了很长时间。
而当时为什么我没有想到功放呢,是因为我当时的理解是功放只是放大音频信号,普通的功放芯片不具备滤波效果会把噪音一并放大,而且我当时想做的功能类似于耳机,并不需要把声音放的有多大,这就导致我一开始完全没有想到用功放芯片。
但是我在网上找了很多资料和视频,他们大多数没有做任何的滤波,简单地把Inmp441的麦克风数据传输给电脑播放出来的声音效果特别好,所以基本上可以排查麦克风的优劣问题,而电源的噪音我也拿示波器测试过了 是比较稳定的 不至于影响到噪音特别大。然后我以为是扬声器的问题,一开始扬声器是1块钱一个的,后面换成2块钱一个了 但是效果一样很差。
然后直到我刷到一个博主用esp32读取Inmp441数据并传输给 MAX98357播放出来的声音特别好,我就去查了这个功放芯片的东西。我惊讶地发现他可以把I2S的数据转成DAC数据输出 而不需要我软件中间把I2S数据转成DAC。虽然我不知道两者有什么差别,但是我还是买回来试了一下。一开始我写好代码配置好引脚后,虽然说噪音少了一些了,信噪比更高了,但是奇怪的是 声音仿佛断断续续导致失真很严重。
然后我开始重新审查软件代码的问题,我发现我的dma的缓冲区的大小写的4(因为一开始软件i2s的数据转dac的时候这样每一次都处理映射成dma[0]和dma[1]进行位操作会比较方便),而现在我不需要软件转了 直接把数据给max98357芯片不就好了吗 ,然后我删除了这部分的代码,直接配置好两个i2s的协议的配置相同,把麦克风数据直接传给max98357,然后dma的数组定义成1024大小。一调试,发现成功了,音质也很好,效果也非常不错。
参考链接:
使用STM32的I2S协议读取麦克风INMP441-CSDN博客
标签:i2s,inmp441,麦克风,引脚,芯片,音频,I2S,stm32 From: https://blog.csdn.net/2303_77827093/article/details/143452382