SU03T(语音识别播报模块)
- 注意:学习模块的方法是最重要的
目录
[查找资料 - SU03T](#查找资料 - SU03T)
查找资料 - SU03T
- 先从网上查找资料,找到官方资料
-- 最好找到开发该模块的公司,从而找到官方资料
-- 如果这个简单的文档资料找不到你想应用的功能,那就取文档中心查看
-- 这里面的文档就会比较丰富,有的模块还会有对应的视频,方便你学习
-- 还有相应的智能公元平台,可以去b站看使用方法
配置固件
1、进入智能公元,并注册登入
2、点击对应的模块,创建产品
3、随便选择一个产品类别,这里选择RGB
4、点击下一步后进入配置,降噪可选可不选
5、配置引脚
- 后来会用这个引脚来下载一个空工程
6、唤醒词配置
- 这里写的数据用来唤醒语音识别模块,可以说唤醒词来唤醒
7、唤醒回复
- 你说唤醒词时,该模块会唤醒并播报你设置的内容
8、命令词自定义
- 当触发方式选择的是命令词时
- 配置控制
- 点击添加控制
- 选择端口输出(这里选择端口输出的意思是,该语音模块听到命令词时,该模块会向单片机发送数据)
-
配置参数
-
参数应写成相应的协议格式,已知协议包括帧头,消息,帧尾三部分,其中帧头和帧尾是固定的,消息是可变的,这里我们只发送一个数据,所以消息部分就写一个数据即可。而帧头和帧尾可以自己定义
- 关灯跟开灯的配置一样
- 下面配置播报co2溶度,因为播报co2溶度不仅要发给单片机让单片机将数据传给语音模块,还要让语音模块播报数据,所以这里需要配置两个控制
-- 这里的数据对应的操作,单片机编程的时候会写
-
配置控制,跟关灯一样,注意数据要有区分,除了帧头和帧尾相同
-
再添加一条,用来单片机向语音模块发送co2
-
这里选择添加触发,收到语音后,语音模块会向单片机发送数据,单片机收到数据后,再向语音模块发送数据,
- 添加控制,语音模块收到数据后,播报数据
- 配置发音人,随机
- 配置开机播报
- 之后分别点击保存,检查配置,发布版本
- 点击快速测试版本即可
- 之后等待生成
- 生成后将该压缩包放在没有中文路径之下,并解压
-
打开串口下载器
-
下载
-
接线,将模块与单片机相连
-
注意:一样要断电接线
-
先向单片机里下载一个空工程,下载完后,将固件烧录到模块中
-
点击烧录,注意这里点击烧录后,要将该语音播报模块重新上电,也就是将5v重新插一下,就开始烧录了,直到下载完成,关闭串口下载器即可
-
之后将固件生成的.c和.h文件放到工程中
- 移代码
- 之后在.c中添加如下代码,将数据发送给语音模块
-
然后将co2数据转换的函数写进解析数据函数中
-
之后再将语音播报模块重新插线将Rx和Tx插到uart5对应的引脚上,分别是PC12和PD2
- 开始编写代码
编程
1、初始化函数
- 这里用的是UART5,直接在上一个kqm6600的基础上更改即可
cs
void su03t_init(void)
{
//时钟 C\D端口 UART5(外设自身也有时钟)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); //看数据手册在哪条线上 - APB1 //注意串口名字
//IO PC10,PC11
GPIO_InitTypeDef GPIO_InitStructure = {0}; //定义结构体变量,并且将结构体变量赋初值
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOD, &GPIO_InitStructure);
//外设
USART_InitTypeDef USART_InitStructure = {0};
USART_InitStructure.USART_BaudRate = 9600; //波特率 常用的是4800 9600 115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位长度
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位长度
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验(这里写不使用)
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制失能(不使用硬件流控制)
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//模式
USART_Init(UART5, &USART_InitStructure);
USART_Cmd(UART5,ENABLE);//开启串口 //使能或者失能 UART5外设(一般外设都要写这个)
//使能中断源 //串口有10个,用哪一个就要开哪一个中断源
USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);
//中断
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能(使能哪个中断通道,就要写哪个(必须写)中断服务函数)
NVIC_Init(&NVIC_InitStructure);
}
2、中断服务函数
- 这里用的是UART5,直接在上一个kqm6600的基础上更改即可
cs
//中断服务函数
void UART5_IRQHandler()//每次收到一个字节就会触发一次中断
{
//判断接收中断是否发生
if(USART_GetITStatus(UART5, USART_IT_RXNE) == SET)
{
//处理中断:保存数据
su03t.rxbuff[su03t.rxlen++] = USART_ReceiveData(UART5);
if(su03t.rxlen == 3)//触发了3次中断
su03t.rxflag = 1;
su03t.rxlen %= 5;//对5求余,他就一直会小于10
//清理终端
USART_ClearITPendingBit(UART5,USART_IT_RXNE);
}
}
3、发送已一个字节函数
cs
//发送
void uart5_tx(uint8_t data)//参数就是要发送的数据
{
while(USART_GetFlagStatus(UART5, USART_FLAG_TXE )== RESET){}
//上次的数据发送完成,为空表示上个数据已经发送完成
//等待的时候是还没有发送,一旦发送完成,就变成1了
USART_SendData(UART5, data);
}
4、发送不定长数组
cs
//发送不定长数组
void uart5_txbuff(uint8_t *buff,uint8_t len)
{
for(uint8_t i=0;i<len;i++)
uart5_tx(buff[i]);
}
5、数据解析函数
//数据解析函数的模板:
//1、判断数据是否接收完毕
//2、错误判断(预热、校验。。。)
//3、解析数据
//4、清除接收缓冲区
cs
void su03t_data_parsing(void)//解析
{
//1、判断数据是否接收完毕
if(su03t.rxflag == 1)
{
if(su03t.rxlen !=3){ //因为发过来的数据为3位
printf("数据长度错误\r\n");
goto AAA;
}
//2、错误判断(预热、校验。。。)
if(su03t.rxbuff[0] != 0xff || su03t.rxbuff[2] != 0xAA)
{
printf("校验错误\r\n");
goto AAA;
}
//3、解析数据
switch(su03t.rxbuff[1])
{
case 1:
LED1(1);
break;//开灯
case 2:
LED1(0);
break;//关灯
case 3:
_uart_co22(kqm.co2);
//printf("co2:%.2fPPM\r\n",kqm.co2);
break;//播报二氧化碳
}
AAA:
memset(su03t.rxbuff,0,10);
su03t.rxlen = 0;
su03t.rxflag = 0;
}
//4、清除接收缓冲区
}
1、判断数据是否接收完毕,首先是前面已经说过了,发送到单片机的数据为3位,并且由前面的中断服务函数可以知道,每次接收到一个字节就会触发一次中断,所以当接收到3个字节的时候,rxflag就会变成1,所以这里就是判断rxflag是否为1,如果为1就表示数据接收完毕了。
2、错误判断,如果数据不是3位,如果帧头和帧尾不正确
3、解析数据,对应的数据对应不同的操作
4、如果出现错误,就要清空数据
- su03t.h中定义结构体
cs
#ifndef _SU03T_H_
#define _SU03T_H_
#include "stdio.h"
#include "STM32f10x.h"
void su03t_init(void);
typedef struct {
uint8_t rxbuff[5];//接收缓冲区 因为那里面传输了3字节
uint8_t rxlen; //接收计数值
uint8_t rxflag;
float voc;//空气质量
float co2;//二氧化碳
float hcho;//甲醛
}SU03T;
void uart5_txbuff(uint8_t *buff,uint8_t len);
void su03t_data_parsing(void);
#endif
6、在主函数中调用响应函数
cs
int main()
{
su03t_init();
led_init();
kqm6600_init();
SysTick_Config(72000);
usart_init();
while(1)
{
if(sutime >=100)
{
sutime =0 ;
su03t_data_parsing();
}
if(kqmtime >= 500)
{
kqmtime =0 ;
kqm_data_parsing();
if(kqm.voc >= 7)
{
relay_on();
Delay_nms(100);
relay_off();
}
//printf("1\r\n");
}
}
}
- 之后下载程序,就可以控制该模块了