STM32第八课:Su-03t语音识别模块

news2024/11/26 10:37:37

文章目录

  • 需求
  • 一、SU03T语音识别模块
  • 二、模块配置流程
    • 1.固件烧录
    • 2.配置串口和传输引脚
    • 3.中断函数
    • 4.double类型转换
    • 5 数据发送
    • 6.接收处理
  • 三、该模块完整代码
  • 总结


需求

基于上次完成空气质量传感器,利用SU03T语音识别模块,实现空气质量的语音问答播报。
在这里插入图片描述


一、SU03T语音识别模块

该模块是固件是通过智能公元设计的。
硬件层和协议层以及识别的语音指令也是由固件决定的。
所以使用前需要去该固件的官网进行设计烧录(www.smartpi.cn)

二、模块配置流程

思路:
1.硬件先检测语音指令,将语音指令发送给串口5。(AA 55 XX 55 AA)
2.串口5以10位为一组存到数组中。
3.校验指令是否正确(头尾固定)。
4.提取得到的指令数组中的第三位,进行判断是哪一个指令。
5.根据接收到的指令和外部声明的空气质量数据传输到指令拼接函数中。
6. 制作指令拼接函数,其中要将空气质量的double数据转换为8位16进制的。AA 55 04 00 00 00 00 00 80 37 40 55 AA
7. 将拼接好的数据发送给SU03T语音识别模块,进行播报。

1.固件烧录

1.先去智能公元的官网设计所需的语音指令和接口,本例程选取的以串口5 PC12(TX)和PD2(RX)进行数据的通信。设计完成后会生成一个bin二进制文件。
2.清空板子上的代码,然后利用板子上的ch340进行烧录。
在这里插入图片描述
具体步骤官方也有详细介绍文档,一步一步来就可以。

2.配置串口和传输引脚

该模块的协议层为:
波特率:9600
数据位8位
校验位 0 位
停止位1位

代码如下:

void Su03t_U5Config()//串口5 PC12(TX) PD2(RX)
{
	
		//开时钟U5 PD12(TX) PD2(RX)
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC,ENABLE);
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
	  //配置PC12(TX)
		GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推完输出
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOC,&GPIO_InitStruct);
		//PD2(RX)
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOD,&GPIO_InitStruct);
		
  	//配置串口5  波特率9600 数据位8,校验位0,停止位1
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 9600;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//打开接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(UART5,&USART_InitStruct);
	  //使能串口
		USART_Cmd(UART5,ENABLE);
   	//配置串口5的中断(采用中断接收)
		USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);//使能串口5	的接收非空中断
		USART_ITConfig(UART5,USART_IT_IDLE,ENABLE);//总线空闲中断
		NVIC_SetPriority(UART5_IRQn,6);//设置优先级0~15
		NVIC_EnableIRQ(UART5_IRQn);//使能中断通道
}

3.中断函数

首先,先创建一个结构体方便之后操作。
里面包含需要发送的10位数组、数组下标和数据类型。

typedef struct{
	uint8_t u5_recv[10];//保存数据数组
	uint8_t  u5_cnt;//数组下标
	uint8_t u5_tflag;
}UART5DATA;//数据类型

然后依旧是去启动文件中找到然后复制。
代码如下:

UART5DATA u5_data={0};
void UART5_IRQHandler()//串口5中断执行
{
		uint8_t data=0;
	//判断接收中断是否发生
	if(USART_GetITStatus(UART5,USART_IT_RXNE)==SET)
	{
		data = UART5->DR;
		//USART1->DR = data;//回显
		u5_data.u5_recv[u5_data.u5_cnt]=data;
		u5_data.u5_cnt++;
		u5_data.u5_cnt%=10;
	}
	//触发空闲中断,表示总线空闲,接收完毕
	if(USART_GetITStatus(UART5,USART_IT_IDLE)==SET)
	{
		data = UART5->SR;//清理空闲中断,先读SR再读DR
		data = UART5->DR;	
		u5_data.u5_tflag=1;
	}
}

该处串口5的中断用来接收数据,并把数据传送给数组里,每十个为一组。
空闲中断用来进行标志位置1,方便之后的程序进行判断。
u5_data.u5_tflag为1时,代表一组数据传输完成。

4.double类型转换

由于该串口接收的空气质量数据为double类型,而传输类型为8字节16进制,所以此时需要进行数据转换。

//将double数据转换成8位类型存放到数组arr中
void DoubleToUint8(double data,uint8_t *arr)
{
	
	uint8_t *p = (uint8_t *)&data;
	uint8_t i=0;
	for(i=0;i<8;i++)
	{
		arr[i]=p[i];
	printf("%02x ",*(p+i));
	}
	printf("\r\n");
	return;
}

5 数据发送

根据该语音模块要求进行数据拼接
在这里插入图片描述

//拼接指令函数 AA 55 04 00 00 00 00 00 80 37 40 55 AA
void Su03tSendMsg(uint8_t cmd,double data)
{
	uint8_t msg[13]={0};//存放要发送的指令
	msg[0]=0xAA;
	msg[1]=0x55;
	msg[2]=cmd;
	DoubleToUint8(data,&msg[3]);
	msg[11]=0x55;
	msg[12]=0xAA;
	//通过串口5发送
	U5_Sendarr(msg,13);
}

cmd为指令,data为数据。
不同的指令对应不同的语音播报数据
在这里插入图片描述
要将整合的数据进行发送,此时还需要构造两个串口5的发送函数

//串口5发送单字节函数
void Uart5Senddata(uint8_t data)
{
	//等待发送完成
	while(USART_GetFlagStatus(UART5,USART_FLAG_TC)==0);
	//如果上次发送完成,就发送
	USART_SendData(UART5,data);
}

//串口5发送数组函数
void U5_Sendarr(uint8_t * data,uint32_t len)
{
	uint32_t i=0;
	for(i=0;i<len;i++){
		Uart5Senddata(*data);
		data++;
	}
}

6.接收处理

将kqm处理后的数据进行外部声明,再判断头尾的固定值,查看是否有误,然后进行数据类型标志位判断,判断收到的指令要播报那个数据,最后记得释放结构体,防止重复播报。

extern float voc;
extern float ch2o;
extern float co2;
int Su03tDealData()
{
	
	if(u5_data.u5_tflag!=1)
	{
		return 1;
	}
	
	if(u5_data.u5_recv[0]!=0xAA||u5_data.u5_recv[1]!=0x55)
	{
		printf("数据帧头出错\r\n");
		return 2;
	}
		if(u5_data.u5_recv[4]!=0xAA||u5_data.u5_recv[3]!=0x55)
	{
		printf("数据帧尾出错\r\n");
		return 3;
	}	
	switch(u5_data.u5_recv[2])
	{
		case 1:printf("接收01,空气质量指令\r\n");
			Su03tSendMsg(1,voc);//voc
		break;
		case 2:	printf(" 接收02,甲醛指令\r\n");
		Su03tSendMsg(2,ch2o);//voc
			break;
		case 3:	printf(" 接收03,Co2指令\r\n");
		Su03tSendMsg(3,co2);//voc
			break;
	}
  memset(&u5_data,0,sizeof(u5_data));
	return 0;	
}

完成后在主函数中调用 :
Kqm_U4Config();//空气质量检测
Su03t_U5Config();//语音播报

在while(1)中调用:
KQM_DealData();//空气质量处理
Su03tDealData();
即可实现

三、该模块完整代码

su03t.c

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
#include "su03t.h"

typedef struct{
	uint8_t u5_recv[10];//保存数据数组
	uint8_t  u5_cnt;//数组下标
	uint8_t u5_tflag;
}UART5DATA;//数据类型

void Su03t_U5Config()//串口5 PC12(TX) PD2(RX)
{
	
		//开时钟U5 PD12(TX) PD2(RX)
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC,ENABLE);
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
	  //配置PC12(TX)
		GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推完输出
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOC,&GPIO_InitStruct);
		//PD2(RX)
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOD,&GPIO_InitStruct);
		
  	//配置串口5  波特率9600 数据位8,校验位0,停止位1
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 9600;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//打开接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(UART5,&USART_InitStruct);
	  //使能串口
		USART_Cmd(UART5,ENABLE);
   	//配置串口4的中断(采用中断接收)
		USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);//使能串口4	的接收非空中断
		USART_ITConfig(UART5,USART_IT_IDLE,ENABLE);//总线空闲中断
		NVIC_SetPriority(UART5_IRQn,6);//设置优先级0~15
		NVIC_EnableIRQ(UART5_IRQn);//使能中断通道
}

//串口5发送单字节函数
void Uart5Senddata(uint8_t data)
{
	//等待发送完成
	while(USART_GetFlagStatus(UART5,USART_FLAG_TC)==0);
	//如果上次发送完成,就发送
	USART_SendData(UART5,data);
}

//串口5发送数组函数
void U5_Sendarr(uint8_t * data,uint32_t len)
{
	uint32_t i=0;
	for(i=0;i<len;i++){
		Uart5Senddata(*data);
		data++;
	}
}

UART5DATA u5_data={0};
void UART5_IRQHandler()//串口5中断执行
{
		uint8_t data=0;
	//判断接收中断是否发生
	if(USART_GetITStatus(UART5,USART_IT_RXNE)==SET)
	{
		data = UART5->DR;
		//USART1->DR = data;//回显
		u5_data.u5_recv[u5_data.u5_cnt]=data;
		u5_data.u5_cnt++;
		u5_data.u5_cnt%=10;
	}
	//触发空闲中断,表示总线空闲,接收完毕
	if(USART_GetITStatus(UART5,USART_IT_IDLE)==SET)
	{
		data = UART5->SR;//清理空闲中断,先读SR再读DR
		data = UART5->DR;	
		u5_data.u5_tflag=1;
	}
}

//将double转换成8位类型数组arr
void DoubleToUint8(double data,uint8_t *arr)
{
	
	uint8_t *p = (uint8_t *)&data;
	uint8_t i=0;
	for(i=0;i<8;i++)
	{
		arr[i]=p[i];
	printf("%02x ",*(p+i));
	}
	printf("\r\n");
	return;
}

extern float voc;
extern float ch2o;
extern float co2;
int Su03tDealData()
{
	
	if(u5_data.u5_tflag!=1)
	{
		return 1;
	}
	
	if(u5_data.u5_recv[0]!=0xAA||u5_data.u5_recv[1]!=0x55)
	{
		printf("数据帧头出错\r\n");
		return 2;
	}
		if(u5_data.u5_recv[4]!=0xAA||u5_data.u5_recv[3]!=0x55)
	{
		printf("数据帧尾出错\r\n");
		return 3;
	}	
	switch(u5_data.u5_recv[2])
	{
		case 1:printf("接收01,空气质量指令\r\n");
			Su03tSendMsg(1,voc);//voc
		break;
		case 2:	printf(" 接收02,甲醛指令\r\n");
		Su03tSendMsg(2,ch2o);//voc
			break;
		case 3:	printf(" 接收03,Co2指令\r\n");
		Su03tSendMsg(3,co2);//voc
			break;
	}
  memset(&u5_data,0,sizeof(u5_data));
	return 0;
}

//拼接指令函数 AA 55 04 00 00 00 00 00 80 37 40 55 AA
void Su03tSendMsg(uint8_t cmd,double data)
{
	uint8_t msg[13]={0};//存放要发送的指令
	msg[0]=0xAA;
	msg[1]=0x55;
	msg[2]=cmd;
	DoubleToUint8(data,&msg[3]);
	msg[11]=0x55;
	msg[12]=0xAA;
	//通过串口5发送
	U5_Sendarr(msg,13);
}

su03t.h

#ifndef _SU03T_H_
#define _SU03T_H_
#include "stm32f10x.h"
void Su03t_U5Config();
void Uart5Senddata(uint8_t data);
void U5_Sendarr(uint8_t * data,uint32_t len);
void UART5_IRQHandler();
void DoubleToUint8(double data,uint8_t *arr);
int Su03tDealData();
void Su03tSendMsg(uint8_t cmd,double data);
#endif
		

总结

1.学会了如何配置半成品模块。
2.学会了如何根据需求进行数据处理和类型转换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1875349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

240622_昇思学习打卡-Day4-ResNet50迁移学习

240622_昇思学习打卡-Day4-ResNet50迁移学习 我们对事物的认知都是一点一点积累出来的&#xff0c;往往借助已经认识过的东西&#xff0c;可以更好地理解和认识新的有关联的东西。比如一个人会骑自行车&#xff0c;我们让他去骑摩托车他也很快就能学会&#xff0c;比如已经学会…

STM32开发方式的演变与未来展望

一、STM32开发方式的演变 自2007年STM32微控制器首次亮相以来&#xff0c;其开发方式经历了从寄存器到标准库&#xff0c;再到HAL&#xff08;硬件抽象层&#xff09;的演变。 1.寄存器开发&#xff08;2007年-2010年代初&#xff09; 最初&#xff0c;由于初期缺乏足够的软…

Cyuyanzhong的内存函数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、memcpy函数的使用与模拟实现二、memmove函数的使用和模拟实现三、memset函数与memcmp函数的使用&#xff08;一&#xff09;、memset函数&#xff08;内存块…

Qt creator实现一个简单计算器

目录 1 界面设计 2 思路简介 3 代码 目录 1 界面设计 ​2 思路简介 3 代码 3.1 widget.h 3.2 widget.c 4 完整代码 在这里主要记载了如何使用Qt creator完成一个计算器的功能。该计算器可以实现正常的加减乘除以及括号操作&#xff0c;能实现简单的计算器功能。 1 界…

.NET使用CsvHelper快速读取和写入CSV文件

前言 在日常开发中使用CSV文件进行数据导入和导出、数据交换是非常常见的需求&#xff0c;今天我们来讲讲在.NET中如何使用CsvHelper这个开源库快速实现CSV文件读取和写入。 CsvHelper类库介绍 CsvHelper是一个.NET开源、快速、灵活、高度可配置、易于使用的用于读取和写入C…

Spring Boot集成vavr快速入门demo

1.什么是vavr&#xff1f; 初闻vavr&#xff0c;感觉很奇怪&#xff0c;咋这个名字&#xff0c;后面看到它的官网我沉默了&#xff0c;怀疑初创团队付费资讯了UC震惊部如何取名字&#xff0c;好家伙&#xff0c;vavr就是java这四个字倒过来&#xff0c;真的是’颠覆’了java……

如何成为-10x工程师:反向教学大数据开发实际工作中应如何做

10x 工程师可能是神话&#xff0c;但 -10x 工程师确实存在。要成为 -10x 工程师&#xff0c;只需每周浪费 400 小时的工程时间。结合以下策略&#xff1a; 目录 如何使 10 名工程师的输出无效化改变需求大数据开发示例 创建 400 小时的繁忙工作任务示例大数据开发示例 创建 400…

心理辅导平台系统

摘 要 中文本论文基于Java Web技术设计与实现了一个心理辅导平台。通过对国内外心理辅导平台发展现状的调研&#xff0c;本文分析了心理辅导平台的背景与意义&#xff0c;并提出了论文研究内容与创新点。在相关技术介绍部分&#xff0c;对Java Web、SpringBoot、B/S架构、MVC模…

Unable to get expected results using BM25 or any search functions in Weaviate

题意&#xff1a;使用 Weaviate 中的 BM25 或任何搜索函数都无法获得预期结果 问题背景&#xff1a; I have created a collection in Weaviate, and ingested some documents into the Weaviate database using LlamaIndex. When I used the default search, I found that it…

高精度除法的实现

高精度除法与高精度加法的定义、前置过程都是大致相同的&#xff0c;如果想了解具体内容&#xff0c;可以移步至我的这篇博客&#xff1a;高精度加法计算的实现 在这里就不再详细讲解&#xff0c;只讲解主体过程qwq 主体过程 高精度除法的原理和小学学习的竖式除法是一样的。 …

Chrome导出cookie的实战教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

备份SQL Server数据库并还原到另一台服务器

我可以将SQL Server数据库备份到另一台服务器吗&#xff1f; 有时您可能希望将 SQL数据库从一台服务器复制到另一台服务器&#xff0c;或者将计算机复制到计算机。可能的场景包括测试、检查一致性、从崩溃的机器恢复数据库、在不同的机器上处理同一个项目等。 是的&#xff0c…

Vue+Proj4Leaflet实现地图瓦片(Nginx代理本地地图瓦片为网络url)加载并实现CRS投影转换(附资源下载)

场景 Leaflet中加载离线OSM瓦片地图(使用OfflineMapMaker切割下载离线png地图文件)&#xff1a; Leaflet中加载离线OSM瓦片地图(使用OfflineMapMaker切割下载离线png地图文件)_offline map maker-CSDN博客 Leaflet快速入门与加载OSM显示地图&#xff1a; Leaflet快速入门与…

等保测评练习卷14

等级保护初级测评师试题14 姓名&#xff1a; 成绩&#xff1a; 判断题&#xff08;10110分&#xff09; 1. 方案编制活动中测评对象确定、测评指…

sql想查询一个数据放在第一个位置

sql想查询一个数据放在第一个位置 背景:比如在查询后台账号的时候想将管理员账号始终放在第一个,其他账号按照创建时间倒序排序, 可以这样写sql: SELECTid,create_time FROMuser ORDER BY CASEWHEN id 1 THEN1 ELSE 2 END ASC, create_time DESC 运行截图: 可以看到id…

企业源代码加密软件丨透明加密技术是什么

在一个繁忙的软件开发公司中&#xff0c;两位员工小李和小张正在讨论源代码安全的问题。 “小张&#xff0c;你有没有想过我们的源代码如果被泄露了怎么办&#xff1f;”小李担忧地问。 “是啊&#xff0c;这是个大问题。源代码是我们的核心竞争力&#xff0c;一旦泄露&#…

CentOS 8 Stream 上安装 Docker 遇到的一些问题

curl 命令无法连接到 URL&#xff0c;可能是由于网络问题或 IPv6 配置问题。我们可以使用以下方法来解决这个问题&#xff1a; 强制使用 IPv4&#xff1a; 尝试使用 curl 强制使用 IPv4 进行连接&#xff1a; curl -4 -fsSL https://get.docker.com -o get-docker.sh 检查网络…

Python28-2 机器学习算法之SVM(支持向量机)

SVM&#xff08;支持向量机&#xff09; 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种用于分类和回归分析的监督学习模型&#xff0c;在机器学习领域中被广泛应用。SVM的目标是找到一个最佳的分割超平面&#xff0c;将不同类别的数据分开&…

【详细】CNN中的卷积计算是什么-实例讲解

本文来自《老饼讲解-BP神经网络》https://www.bbbdata.com/ 目录 一、 CNN的基础卷积计算1.1.一个例子了解CNN的卷积计算是什么1.2.卷积层的生物意义 二、卷积的拓展&#xff1a;多输入通道与多输出通道2.1.多输入通道卷积2.2.多输出通道卷积 三、卷积的实现3.1.pytorch实现卷积…

夏令营1期-对话分角色要素提取挑战赛-第①次打卡

零基础入门大模型技术竞赛 简介&#xff1a; 本次学习是 Datawhale 2024 年 AI 夏令营第一期&#xff0c;学习活动基于讯飞开放平台“基于星火大模型的群聊对话分角色要素提取挑战赛”开展实践学习。 适合想 入门并实践大模型 API 开发、了解如何微调大模型的学习者参与 快来…