早上好啊,大佬们。前不久出于一些机缘巧合接触了一款MP3语音播报模块,但是当时学习这个的时候在网上没有找到什么关于它的文章,所以我研究了一下这个语音播报模块,然后写了这篇文章,也作为自己之后复习用的材料,可能会有遗漏的地方,各位大佬们也小白兔修正修正。
先来看看它长什么样子吧!~
这个模块的使用很简单,咱们一点点来介绍。
接口介绍
它有四处接口,microUSB接口,排针接口,3.5mm接口,TF卡接口,P2喇叭接口,我们一个个来讲讲。
microUSB接口
排针接口
A1到A9共9个触发口
普通模式9个触发口对应触发9首音频; 编码模式可以触发31首音频
3.5mm接口
TF卡接口
P2喇叭接口

相关参数
播放模式
单播放模式:
编码触发模式
例如说:要播放第10首,那就是 01010 也就是 A2 和 A4 置低电平。
TF卡文件存放
首先,先让电脑能够读取到TF卡,可以采取两种方式—— microUSB连接 || 读卡器读取。
然后在TF卡里创建两个文件夹,一个是01,另一个是99。这个名字一定不能换。
01文件夹 —— 后续引脚触发的音频文件夹
99文件夹 —— 通电就触发的音频文件夹
后面的任务就是准备我们所需要播放的音频文件。
可以直接下载音乐,或者如果你想要用自定义的语音,可以直接在下面的网站里进行文字转语音。
就是这么个使用方法。
99文件夹
先来讲一下99文件夹吧,这个比较简单。
这个只需要你在99的文件夹下放上音频,然后通上电就会播放了。
ok,这个文件夹就没什么好说的了。
下面来说说01文件夹的播放。
单播放模式
接线:
将 lx-trig-mp3-v6.0 的 5V 和 GND 接到stm32的 5V 和 GND 然后从stm32的GND引出一条线
5V可以使用st-link上面的5V,芯片提供的5V电压一般还是3V3的,虽然也能用,但还是5V的会更好一点。
将喇叭接到P2口上。
TF内容
操作
将GND引出来的线分别接触A1,A2,A3。然后就会分别播放001,002,003三个音频。
但是用芯片供电不是特别的好,建议还是用电源模块供电。
stm32控制下的单播放模式
到这里,我们就已经尝试了它的单播放模式,但是我们也可以用stm32的GPIO改变高低电平进行控制,那这又是怎么个事儿呢,下面我们来写写看吧。
首先,我们先复制一个工程模板。然后在Hardware文件夹下新建 MP3.c 和 MP3.h 两个文件夹。
我准备了三个音频,在TF卡中的存储如下:
第一步,打开我们需要用的GPIO口,也就是 stm32上 连接 MP3模块上的A1等引脚 的口。在这里我们使用stm32上的 PB5,PB6,PB7。
这个在前面我们已经学了,来看看怎么个事儿吧~
MP3.c ——
#include "stm32f10x.h" // Device header
void MP3_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //打开GPIOB的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO的模式改为推挽输出。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5); // MP3的这些引脚初始需要为高电平
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
}
然后,我们就可以通过改变GPIO口的高低电平实现播放控制。
在MP3.h里对MP3_Init() 进行声明;
MP3.h ——
#ifndef __MP3_H
#define __MP3_H
void MP3_Init(void);
#endif
main.h ——
#include "stm32f10x.h" // Device header
#include "MP3.h" //导入MP3.h
int main()
{
MP3_Init(); //打开MP3引脚的GPIO口的初始化
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //将PB5的电平拉低,也就是播放音频。
while(1)
{
}
}
这样我们就能播放第一个音频了。
然后我们将准备3个音频都播放一下吧。
main.c ——
#include "stm32f10x.h" // Device header
#include "MP3.h" //导入MP3.h
int main()
{
MP3_Init(); //打开MP3引脚的GPIO口的初始化
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //将PB5的电平拉低,也就是播放音频。
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
while(1)
{
}
}
大家看这个代码,应该没错吧,但是大佬们会发现我们的MP3只会播放第一个音频,后面的两个音频还是不会播放。
一次触发命令
这是因为——
模块上电后A1-A10脚默认都是高电平,也就是有5V的电压,如果要触发其中的某个脚,就必须在这个脚为高电平的状态下, 再拉低电平50毫秒以上 (大于50ms就可以,就是拉低一天也是算一个触发),这时就算一个触发命令,如果该脚要再次触发, 必须保证触发前该脚高电平状态下超过50毫秒以上 。
也就是说,它需要50ms的时间去反应我们的信号输入,而且,他需要我们将电平拉高之后才会去处理我们的下一个信号。
那么,也就是说我们如果想要播放多个音频,现在需要做的就是写一个将电平拉高的语句,并且每个语句之间需要50ms的延时。
说到延时,我们就需要用到之前写的Delay函数了,不知道的大佬们可以看看小白兔之前的一篇文章,也就是讲Delay()函数的那一篇。
stm32教程:Delay函数 及 引脚复用重定义_stm32 寄存器delay-CSDN博客https://blog.csdn.net/sikimayi/article/details/143496013?spm=1001.2014.3001.5501那么我们后面的思路就很清晰了。
代码修改
首先导入Delay的代码。
main.c ——
#include "stm32f10x.h" // Device header
#include "MP3.h" //导入MP3.h
#include "Delay.h"
int main()
{
MP3_Init(); //打开MP3引脚的GPIO口的初始化
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //将PB5的电平拉低,也就是播放音频。
Delay_ms(100); //给100ms的延时,略多于50ms即可
GPIO_SetBits(GPIOB,GPIO_Pin_5); //将PB5的电平拉高,便于下一次的触发
Delay_ms(100);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
Delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
Delay_ms(100);
while(1)
{
}
}
大家把这个代码再烧进去,会发现还是只会播放一个音频,但是现象变了,它播放的是最后一个音频,但是在播放之前会有一些杂音。
其实这个很容易就明白,前面的那些杂音就是前两个音频,因为,我们中间的延时太短,在前面的音频播放完之前就会被后面的音频覆盖掉,最后一个音频会因为后面没有将它覆盖的音频,所以会被播放出来。
但是,现在对于代码而言,我们已经成功了。
那如果我们需要播放完整的音频,只需要将中间的延时加长到能够播放完音频就可以。
例如说,我的第一个音频时长是3s,那我只需要将第一个和第二个信号传递之间的时间加长到3s就可以了。
main.c ——
#include "stm32f10x.h" // Device header
#include "MP3.h" //导入MP3.h
#include "Delay.h"
int main()
{
MP3_Init(); //打开MP3引脚的GPIO口的初始化
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //将PB5的电平拉低,也就是播放音频。
Delay_ms(100); //给100ms的延时,略多于50ms即可
GPIO_SetBits(GPIOB,GPIO_Pin_5); //将PB5的电平拉高,便于下一次的触发
Delay_s(3);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
Delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
Delay_ms(100);
while(1)
{
}
}
这样我的第一个音频就能完整播放了。
OK,那么我们单播放模式就讲完了,下面我们来说说编码模式吧~
编码模式
MP3模块通电之后默认打开的是单播放模式,那么我们需要使用编码模式,第一步就是在通电的时候将 A10口接地。
接线:
5V —— st-link 的 5V
GND —— stm32 的 GND
A1 —— PB5
A2 —— PB6
A3 —— PB7
A4 —— PB8
A5 —— PB9
A10 —— stm32 的 GND
其余引脚不用接
TF卡内容,和前面一样,大家需要多少就准备多少即可,可以不用按照顺序。
不用一定一个个编码下来。
代码
MP3.c ——
#include "stm32f10x.h" // Device header
#include "Delay.h"
void MP3_Reset(void) //便于重置引脚口,直接写一个所有引脚全部重置的函数
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
GPIO_SetBits(GPIOB,GPIO_Pin_9);
}
void MP3_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //打开GPIOB的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO的模式改为推挽输出。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
MP3_Reset();
}
void A1_ON(void)
{
// 1 的二进制是 00001,也就是只需要将 A1 拉低即可。
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
Delay_ms(100);
MP3_Reset();
}
void A2_ON(void)
{
// 2 的二进制是 00010
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
MP3_Reset();
}
void A3_ON(void)
{
// 3 的二进制是 00011
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
MP3_Reset();
}
void A12_ON(void)
{
// 12 的二进制是 01100
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
Delay_ms(100);
MP3_Reset();
}
void A25_ON(void)
{
// 25 的二进制是 11001
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
GPIO_ResetBits(GPIOB,GPIO_Pin_9);
Delay_ms(100);
MP3_Reset();
}
然后在MP3.h上进行声明,也就是——
MP3.h ——
#ifndef __MP3_H
#define __MP3_H
void MP3_Reset(void); //MP3_Reset在后面几乎不会用,可以选择不声明也没事
void MP3_Init(void);
void A1_ON(void);
void A2_ON(void);
void A3_ON(void);
void A12_ON(void);
void A25_ON(void);
#endif
然后,我们就能在main.c里面开始播放我们的音频了。
main.c ——
#include "stm32f10x.h" // Device header
#include "MP3.h" //导入MP3.h
#include "Delay.h"
int main()
{
MP3_Init(); //打开MP3引脚的GPIO口的初始化
A12_ON(); //播放第4个音频
Delay_s(1);
A25_ON(); //播放第5个音频
Delay_s(1);
A1_ON(); //播放第1个音频
Delay_s(3);
A2_ON(); //播放第2个音频
Delay_s(1);
A3_ON(); //播放第3个音频
Delay_s(1);
while(1)
{
}
}
OK了,到这里大佬们应该都会用LX-TRIG-MP3这个模块了吧。
然后下面我们在来说一下它的其它一些内容,也就是BY口和KEY两个BY
BY口
首先对于BY口,它是一个输出口,也就是播放状态指示,播放输出低电平,不播报输出高电平。
那么我们可以初始化一个GPIO口,将它改为上拉输入模式。
为了更好地看现象,我们加上一个OLED来显示BY口的输出。
接线:
5V —— st-link 的 5V
GND —— stm32 的 GND
A1 —— PB5
A2 —— PB6
A3 —— PB7
A4 —— PB8
A5 —— PB9
A10 —— stm32 的 GND
BY —— PA1
其余引脚不用接
代码
下面来看代码吧,直接——
MP3.c ——
#include "stm32f10x.h" // Device header
#include "Delay.h"
void MP3_Reset(void) //便于重置引脚口,直接写一个所有引脚全部重置的函数
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
GPIO_SetBits(GPIOB,GPIO_Pin_9);
}
void MP3_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //打开GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //打开GPIOA的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO的模式改为推挽输出。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //GPIO的模式改为上拉输入。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
MP3_Reset();
}
/*
单播放模式
*/
void A1_ON(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
Delay_ms(100);
MP3_Reset();
}
void A2_ON(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
MP3_Reset();
}
void A3_ON(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
Delay_ms(100);
MP3_Reset();
}
/*
编码模式
*/
/*
void A1_ON(void)
{
// 1 的二进制是 00001,也就是只需要将 A1 拉低即可。
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
Delay_ms(100);
MP3_Reset();
}
void A2_ON(void)
{
// 2 的二进制是 00010
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
MP3_Reset();
}
void A3_ON(void)
{
// 3 的二进制是 00011
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
Delay_ms(100);
MP3_Reset();
}
void A12_ON(void)
{
// 12 的二进制是 01100
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
Delay_ms(100);
MP3_Reset();
}
void A25_ON(void)
{
// 25 的二进制是 11001
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
GPIO_ResetBits(GPIOB,GPIO_Pin_9);
Delay_ms(100);
MP3_Reset();
}
*/
int BY_Get(void)
{
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1);
}
MP3.h ——
#ifndef __MP3_H
#define __MP3_H
void MP3_Reset(void); //MP3_Reset在后面几乎不会用,可以选择不声明也没事
void MP3_Init(void);
/*
单播放模式
*/
void A1_ON(void);
void A2_ON(void);
void A3_ON(void);
/*
编码模式
*/
/*
void A1_ON(void);
void A2_ON(void);
void A3_ON(void);
void A12_ON(void);
void A25_ON(void);
*/
int BY_Get(void);
#endif
main.c ——
#include "stm32f10x.h" // Device header
#include "MP3.h" //导入MP3.h
#include "Delay.h"
#include "OLED.h"
int by;
int main()
{
MP3_Init(); //打开MP3引脚的GPIO口的初始化
OLED_Init(); //打开OLED的初始化
OLED_ShowString(1, 1, "BY:", OLED_8X16);
by = BY_Get();
OLED_ShowNum(1, 16, by, 1, OLED_8X16);
OLED_Update();
Delay_s(10);
A1_ON(); //播放第1个音频
by = BY_Get();
OLED_ShowNum(8, 16, by, 1, OLED_8X16);
OLED_Update();
while(1)
{
}
}
大家可以试一下,在一开始输出为1, 后面为0。
key口的内容,我没有看得很懂,在商家给的pdf中说用按键来控制,但我没有理解什么意思,这里就不丢人显眼了,希望路过的大佬能教一下小白兔。
这里最后提一个东西,本篇文章就结束了。
就是在lx-mp3上有个焊点,将这里焊上,它就是单曲循环模式,就是原本是播放完就会停下来,但是焊上之后它在播放完会重新进行播放。
总结
那么,本篇的内容就是这些,总体来说lx-MP3还是比较容易的一个语音播报模块,大佬们如果需要MP3播报的话,可以考虑一下这个模块,但是它没有语音识别的功能,还是有些限制的。
按照惯例,小白兔在这里提供一下本期所写的代码,以及商家提供的资料。
链接:https://pan.quark.cn/s/dea0672b3b9a
提取码:VBVC
那么Bye Bye~,我们下期见咯。