首页 > Python资料 博客日记
STM32 使用IIS实现INMP441模块全速音频采样(附python上位机)
2024-07-07 17:00:05Python资料围观206次
前言
本文在stm32平台上,利用IIS协议和INMP441模块,实现了对于音频的采样,并通过串口将数据实时返回电脑
本文只是一个初学者的经验分享,希望为同样刚接触相关协议的朋友提供一些帮助,有错误的地方还请包涵
本文是在另一位大佬工作基础上的改进版,建议先阅读该文章
使用STM32的I2S协议读取麦克风INMP441-CSDN博客
在其中已经将IIS协议、工程基本配置讲的非常详细,一些基础的内容本文不再赘述
最后,本文附上了笔者使用的python上位机,里面实现了一些基础功能
需要强调的基本概念
需要提前说明的是,UART速率过慢,不适合用于音频到上位机的实时传输,本文仅处于初级开发阶段,因此未作深入。如果要做相关开发,可以采用IIS采集 - IIS发送,等等方法。
此外,不要使用性能过差的平台做音频相关的深度开发,内存、处理速度、接口资源都是问题。
1.IIS周期
IIS个三根通信相关的引脚,时钟SCK、帧选择WS、数据SD
帧选择信号WD控制左右声道,当WD=0时,设置为左声道的模块输出;WD=1时,右声道输出;帧的大小受IIS帧格式影响,如果是24bit data on 32 frame的格式,帧大小就是32bit,如果是16bit data on 16 bit frame格式,帧大小就是16bit;
在CUBEMX中的IIS配置界面,有一个参数Audio frequency,这个参数等于采样频率
那么有:
采样频率Fs = audio frequency
帧选择信号WS = Fs
时钟信号SCK = Fs * 2 * 帧大小,即一个采样周期里,左右声道各采集一帧
2.实时上传的信号速率
在IIS的采样频率为Fs = 8khz情况下,要实现音频数据的实时上传,需要满足两个条件:
① 同上位机的通讯速率大于采样数据的产生速率:
假设使用USART上传,并且只采集单声道数据,对于INMP441的24位ADC数据,我们需要使用uint32型发送数据,那么数据产生速率为:
32 * 8000 = 256000 bit/s
UART发送一字节数据,最少需要1个开始位和1个停止位,那么UART串口波特率必须满足:
256000 / 8 * 10 = 320000 bit/s,
对于其他通讯协议,同理
②中断处理时间小于采样数据产生时间:
HAL库处理中断需要绕很大一个圈子:
触发中断 - 进入DMA通道IRQ - 进入具体DMA连接IRQ - 各种判断 - 进入半完成/完成中断
这个过程非常耗时,再加上UART传输比较慢,很可能无法及时处理中断,如下图
这里就是处理速度过慢,即使用了双缓冲,也不得不抛弃一半的数据,只能达到4khz的数据回报率
解决方法
对于问题1,我们提高串口波特率即可,对于本文所使用的STM32f103,可以在CUBEMX中观察到最大波特率范围,我们这里设置为360000bit/s
对于问题2,我们可以通过增大缓冲区的方式,将中断处理耗时平摊到每一次采集上。但如果还想给程序加上RTOS,或者临时去处理些其他任务,还是用更好的芯片吧
将缓冲区大小增加到512后,可以从图中看到,不再出现无法及时响应中断的问题,跑满了8khz
程序实现
请结合之前贴出的文章阅读,这里只指出修改了的地方
首先,DMA传输方式用half word就可以了
程序中用增加半完成中断的方式做了双缓冲
uint16_t dma_buffer[512];
uint32_t val24[2][64];
int val32[2][64];
int cb_cnt=0;
extern UART_HandleTypeDef huart1;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//一组采样数据,左通道2个u16,右通道2个u16
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
if (hi2s == &hi2s2) {
cb_cnt++;
// 选择当前使用的缓冲区
int offset = 0;
for (int i = 0; i < 64; i++) {
val24[0][i] = dma_buffer[offset + 4 * i];
val24[0][i] = val24[0][i] << 8;
val24[0][i] = val24[0][i] + (dma_buffer[offset + 4 * i + 1] >> 8);
if (val24[0][i] & 0x800000) {
val32[0][i] = 0xff000000 | val24[0][i];
} else {
val32[0][i] = val24[0][i];
}
}
HAL_UART_Transmit(&huart1, (uint8_t*)&val32[0][0], 256, 0xff);
}
}
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
if (hi2s == &hi2s2) {
cb_cnt++;
// 选择当前使用的缓冲区
int offset = 256;
for (int i = 0; i < 64; i++) {
val24[1][i] = dma_buffer[offset + 4 * i];
val24[1][i] = val24[1][i] << 8;
val24[1][i] = val24[1][i] + (dma_buffer[offset + 4 * i + 1] >> 8);
if (val24[1][i] & 0x800000) {
val32[1][i] = 0xff000000 | val24[1][i];
} else {
val32[1][i] = val24[1][i];
}
}
HAL_UART_Transmit(&huart1, (uint8_t*)&val32[1][0], 256, 0xff);
}
}
最后,主函数中仅对DMA开启函数的调用做了一些修改
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2S2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_I2S_Receive_DMA(&hi2s2, (uint16_t*)dma_buffer, 512); // 双缓冲区,共512个16位数据
while (1)
{
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
上位机
注意,带上位机版本的stm32程序与前文中不同,请和上位机一同下载
上位机所需库:pyserial、wave、numpy、scipy(如果要做fft)
工程文件及功能:
server.py - 主程序,包括了菜单支持
SerialRec.py - 包含串口通讯类,在这里修改串口通讯参数
txt2wave.py - 将txt文件转换成音频,做了一个简单的高通滤波,不过没什么用
txt_fft_viewer.py / wav_fft_viewer - 两个用来观察频域的文件,不是很有用,真要做相关操作还是自己写吧
使用:
运行server.py,键盘根据提示输入,直到打开串口
串口参数可以在SerialRec.py里面修改全局变量,默认用的360000波特率
先使用功能1接收采样数据,接收数据量由 单片机完成中断中的停止条件 决定
最后的判断就是终止条件,这里设置调用半完成+完成中断共1000次,每次发送64次采样,即发送64000个采样数据,在8000hz采样率下,共发送8s
接收完毕后使用功能2将原始数据转换成整型
最后使用功能3将数据保存到txt文件,默认保存到txtEaxample文件夹下
txt2wave.py中,修改文件名,并按情况修改采样率,音量调节值,和高通滤波器截至频率
运行该文件,转换后的音频保存到waveExample下
8000hz采样率下的音质还是不错的
最后,贴出下载链接,偷懒就放百度网盘了
删除链接中的中文即可
链接:https://pan.baidu.co防m/s/1EY5Y_uJyCt吞V2BngGNeJH3A?pwd=ais2
提取码:ais2
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Anaconda版本和Python版本对应关系(持续更新...)
- Python与PyTorch的版本对应
- Windows上安装 Python 环境并配置环境变量 (超详细教程)
- Python pyinstaller打包exe最完整教程