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

文章目录

  • 需求
  • 一、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,停止位1USART_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~15NVIC_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再读DRdata = 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);//vocbreak;case 2:	printf(" 接收02,甲醛指令\r\n");Su03tSendMsg(2,ch2o);//vocbreak;case 3:	printf(" 接收03,Co2指令\r\n");Su03tSendMsg(3,co2);//vocbreak;}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,停止位1USART_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~15NVIC_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再读DRdata = 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);//vocbreak;case 2:	printf(" 接收02,甲醛指令\r\n");Su03tSendMsg(2,ch2o);//vocbreak;case 3:	printf(" 接收03,Co2指令\r\n");Su03tSendMsg(3,co2);//vocbreak;}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.rhkb.cn/news/364423.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GitOps】使用Google工具JIB实现本地无需安装容器推送镜像,加速SpringCloud项目开发

文章目录 一、效果展示二、简介三、安装Jib插件1、区分环境2、安装插件一、效果展示 本地是window系统,无docker环境,没有任何runtime,使用jib工具打包镜像并推送完成,用时20秒 二、简介 Jib 是 Google 开发的一款开源工具,旨在帮助 Java 开发者更高效地将 Java 应用程…

电脑提示vcomp140.dll丢失的几种有效的解决方法,轻松搞定dll问题

在电脑使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是找不到vcomp140.dll。那么&#xff0c;究竟什么是vcomp140.dll呢&#xff1f;为什么会出现找不到vcomp140.dll的情况呢&#xff1f;本文将从vcomp140.dll的定义、常见原因、对电脑的影响以及解…

Echarts地图实现:各省市计划录取人数

Echarts地图实现&#xff1a;各省市计划录取人数 实现功能 本文将介绍如何使用 ECharts 制作一个展示中国人民大学2017年各省市计划录取人数的地图。我们将实现以下图表形式&#xff1a; 地图&#xff1a;基础的地图展示&#xff0c;反映不同省市的录取人数。散点图&#xf…

Redis 7.x 系列【10】数据类型之有序集合(ZSet)

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 常用命令2.1 ZADD2.2 ZCARD2.3 ZSCORE2.4 ZRANGE2.5 ZREVRANGE2.6 ZRANK2.7…

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

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

STM32学习之一:什么是STM32

目录 1.什么是STM32 2.STM32命名规则 3.STM32外设资源 4. STM32的系统架构 5. 从0到1搭建一个STM32工程 学习stm32已经很久了&#xff0c;因为种种原因&#xff0c;也有很久一段时间没接触过stm32了。等我捡起来的时候&#xff0c;发现很多都已经忘记了&#xff0c;重新捡…

数据分析报告制作的结构和思路整理

先画重点&#xff1a;一份分析报告的制作&#xff0c;目前的市场的分析步骤是优先找一些别人的研究报告&#xff0c;现成的东西&#xff0c;重点是要好好总结业务逻辑和潜在运营可能&#xff0c;这也是一位优秀数据分析师的价值体现。 举个例子&#xff0c;以目前小说短剧赛道的…

SQL33 找出每个学校GPA最低的同学 解法详解

题目截图&#xff1a; 建表代码&#xff1a; drop table if exists user_profile; CREATE TABLE user_profile ( id int NOT NULL, device_id int NOT NULL, gender varchar(14) NOT NULL, age int , university varchar(32) NOT NULL, gpa float, active_days_within_30 int…

虚拟服务器ESXI上Win11虚拟机安装EnspPro(Window系统安装EnspPro方法)

华为于2023年6月30日发布EnspPro&#xff0c;因其对部署环境使用较高&#xff08;常见8核16GB电脑支持模拟3~6个设备&#xff0c;如果要模拟多台设备大规模组网&#xff0c;则建议使用高性能服务器部署安装&#xff09;&#xff0c;本次将其部署再虚拟服务器中。 环境&#xf…

MySQL高级-MVCC-基本概念(当前读、快照读)

文章目录 1、MVCC基本概念1.1、当前读1.1.1、创建表 stu1.1.2、测试 1.2、快照读 1、MVCC基本概念 全称Multi-Version Concurrency Control&#xff0c;多版本并发控制。指维护一个数据的多个版本&#xff0c;使得读写操作没有冲突&#xff0c;快照读为MySQL实现MVCC提供了一个…

【motan rpc 懒加载】异常

文章目录 升级版本解决问题我使用的有问题的版本配置懒加载错误的版本配置了懒加载 但是不生效 lazyInit"true" 启动不是懒加载 会报错一次官方回复 升级版本解决问题 <version.motan>1.2.1</version.motan><dependency><groupId>com.weibo…

mysql中in参数过多优化

优化方式概述 未优化前 SELECT * FROM rb_product rb where sku in(1022044,1009786)方案2示例 public static void main(String[] args) {//往list里面设置3000个值List<String> list new ArrayList<>();for (int i 0; i < 3000; i) {list.add(""…

人生最有力,最棒的十句话!

人生最有力&#xff0c;最棒的十句话 1、允许一切事发生&#xff0c;所有一切发生的事不是你能阻挡了的&#xff0c;你接受&#xff0c;他也发生&#xff0c;你不接受&#xff0c;他也发生&#xff0c;你还不如坦然面对接受现实。 2、你焦虑的时候千万不要躺着啥也不干&#xf…

【多维动态规划】Leetcode 97. 交错字符串【中等】

交错字符串 给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子字符串 子字符串 是字符串中连续的 非空 字符序列。 s s1 s2 … snt…

什么是产线工控安全,如何保障产线设备的安全

什么是产线工控安全&#xff1f; 工控&#xff0c;指的是工业自动化控制&#xff0c;主要利用电子电气、机械、软件组合实现。即是工业控制系统&#xff0c;或者是工厂自动化控制。产线工控安全指的是工业控制系统的数据、网络和系统安全。随着工业信息化的迅猛发展&#xff0…

开源项目-商城管理系统

哈喽,大家好,今天主要给大家带来一个开源项目-商城管理系统 商城管理系统分前后端两部分。前端主要有商品展示,我的订单,个人中心等内容;后端的主要功能包括产品管理,门店管理,会员管理,订单管理等模块 移动端页面

J018_冒泡排序

一、排序过程 如果要对一个数组进行升序排序&#xff1a; 每个轮次两两数字进行比较&#xff0c;如果前面的数字大于后面的数字&#xff0c;则交换两个数字的位置&#xff1b;如果前面的数字小于或等于后面的数字&#xff0c;则这两个数字位置不变。直到把数组中所有数字比较…

核方法总结(四)——高斯过程回归学习笔记

一、定义 基于核方法的线性回归模型和传统线性回归一样&#xff0c;可以用未知数据进行预测&#xff0c;但不能确定 预测的可信度。在参考书第二章中可知&#xff0c;基于贝叶斯方法可以实现对未知数据依概率预测&#xff0c;进而可得到预测的可信度。这一方法中&#xff0c;通…

深度解析:机器学习如何助力GPT-5实现语言理解的飞跃

文章目录 文章前言机器学习在GPT-5中的具体应用模型训练与优化机器翻译与跨语言交流&#xff1a;情感分析与问答系统&#xff1a;集成机器学习功能&#xff1a;文本生成语言理解任务适应 机器学习对GPT-5性能的影响存在的挑战及解决方案技术细节与示例 文章前言 GPT-5是OpenAI公…

Kotlin中对空的很多处理

代码图片直观效果 逐行解释Kotlin中对空的各种情况的使用 private fun testNull() {val flag 1var name: String? nullvar user: User? // 有警告, 因为下面的赋值可以和这一行定义合并var zhangUser: User? User()var wangUser: User User() // 提示Explicitly given t…