stm32实战之su-03t语音模块固件的制作与烧录

目录

su-03t简介

管脚定义

​​智能公元语音固件制作​​

账号注册

创建产品

产品配置

唤醒词自定义

命令词自定义

发音人配置

其他配置

生成和下载语音固件

固件烧录

下载SDK固件烧录工具

SU-03T驱动分享


su-03t简介

SU-03T 是一款低成本、低功耗、小体积的离线语音识别模组,能快速应用于智能家居,各类智能小家电,86 盒,玩具,灯具等需要语音操控的产品,SU-03T也具备强大的软件开发能力,我们可以在“​​智能公元​​”平台上实现语音固件的零代码开发,提高工作效率。

管脚定义

其中需要注意的是UART0的B0、B1是调试器的语音固件烧录口,串口烧录则选择UART1的B6、B7引脚,当固件烧录完成之后则可以使用UART1的B2、B3 引脚和MCU进行通信。

​​智能公元语音固件制作​​

账号注册

打开​​智能公元​​网页进行账号注册

创建产品

产品配置

创建产品成功后会进入产品配置,在大部分情况下都可以使用默认配置,我们只需要关注以下几个配置即可:

唤醒词自定义

唤醒词自定义可以定义语音模块的唤醒词以及唤醒之后的回复,用于唤醒语音模块,开始使用自定义命令词与模块进行语音交互

命令词自定义

命令词自定义可以自己定义的关键词来控制语音模块,例如“开灯”、“关灯”等,免唤醒的命令词可以不需要使用唤醒词直接和模块进行交互。

发音人配置

发音人配置可以用来配置语音模块的音色、音调和语速。

其他配置

生成和下载语音固件

固件烧录

下载SDK固件烧录工具

在SDK固件包的 uni_hb_m_solution-121028-20230920\uni_hb_m_solution\image_demo\Hummingbird-M-Update-Tool 下可以看到以下文件

UniOneUpdateTool.exe为串口烧录工具

USB_Update_Tool_User_Guide.pdf为烧录指导书,写的很详细,跟着烧录即可

SU-03T驱动分享

#include "su_03t.h"

uint8_t usart_su_RXdata;		//存放接收数据寄存器的值
uint8_t usart_su_RXflag;		//接收数据标志位
uint8_t usart_su_RXpacket[6] = {0};	//hex数据包接收数组
uint8_t usart_su_TXpacket[14] = {0};	//hex数据包接收数组

/**
  * @brief  配置串口 PC10 发送复用推挽    PC11 接收浮空模式  
  * @param  None
  * @retval None
  */
void su_o3t_init(void){
	//初始化GPIO口
	//PA9复用推挽
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  	GPIO_InitTypeDef GPIO_InitStructure;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  	GPIO_Init(GPIOC, &GPIO_InitStructure);
	//PA10浮空
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	  GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	//串口初始化
	//开启串口时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
	//初始化串口
	USART_InitTypeDef USART_InitStruct = {0};
	USART_InitStruct.USART_BaudRate = 115200;	//设置波特率
	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;	//字长选择8位
	USART_Init(UART4, &USART_InitStruct);
	
	//开启串口中断
	USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
	
		//初始化NVIC
		//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  	NVIC_InitTypeDef NVIC_InitStruct;
  	NVIC_InitStruct.NVIC_IRQChannel = UART4_IRQn;
  	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 4;
  	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
  	NVIC_Init(&NVIC_InitStruct);
	
	//使能串口
	USART_Cmd(UART4, ENABLE);
}

/**
  * @brief  串口一中断服务函数,接收一个字节的数据,并将标志位置1
	*       hex数据包		长度  6 		开始标志位 0xAA 
  * @param  None
  * @retval None
  */
void UART4_IRQHandler(void){
	static uint8_t RX_su_State = 0;
	static uint8_t su_pRXpacket = 0;
	//usart_init();
	if(USART_GetITStatus(UART4, USART_IT_RXNE) == SET){
		USART_ClearITPendingBit(UART4, USART_IT_RXNE);
			//usart_send_string("y");

		usart_su_RXdata = USART_ReceiveData(UART4);
		//判断接收的数据包头
		if(RX_su_State == 0){	
			if(usart_su_RXdata == 0XAA){	//接收到的使hex文件
				usart_su_RXpacket[0] = usart_su_RXdata;
				RX_su_State = 1;	
				su_pRXpacket = 1;
			}
		}
			else if(RX_su_State == 1){	//接收hex文件的内容
				usart_su_RXpacket[su_pRXpacket] = usart_su_RXdata;
				su_pRXpacket++;
				if(su_pRXpacket >= 5){		//接收数据包长度位4的数据
					RX_su_State = 2;
				}
			}
			else if(RX_su_State == 2){	//判断hex数据包结束标志位
				if(usart_su_RXdata == 0XAA){
					usart_send_array(USART1, usart_su_RXpacket,6);
					usart_su_RXpacket[su_pRXpacket] = usart_su_RXdata;
					RX_su_State = 0;
					usart_su_RXflag = 1;
				}
				else{
					RX_su_State = 0;
					usart_su_RXflag = 0;
					usart_send_array(USART1, usart_su_RXpacket,6);
					usart_su_RXpacket[su_pRXpacket] = usart_su_RXdata;
					//usart_send_string("$");
				}
			}
	}
}

/**
  * @brief  获取usart_su_flag的值
  * @param  None
  * @retval usart_su_RXflag 串口2接收标志位 
  */
uint8_t usart_get_su_RXflag(void){
	if(usart_su_RXflag == 1){
		usart_su_RXflag = 0;
		return 1;
	}
	return 0;
}
/**
  * @brief  处理su_03t的数据
  * @param  None
  * @retval None
  */
void vioce_analysis(void){
	//usart_send_array(usart_su_RXpacket, 5);

	time_t rawtime;
	struct tm *info = NULL;
	//info = localtime(&rawtime);
	if(usart_get_su_RXflag() == 1){
		//char str[5] = {0};
		switch(usart_su_RXpacket[3]){
			case 0x01: //温度
				usart_su_TXpacket[0] = 0XAA;
				usart_su_TXpacket[1] = 0X55;
				usart_su_TXpacket[3] = dht_data.tmp;
				usart_su_TXpacket[4] = dht_data.tmp_flo;
				usart_su_TXpacket[5] = 0X55;
				usart_su_TXpacket[6] = 0XAA;
				if(dht_data.tmp_flag == 0){	//温度为正
					usart_su_TXpacket[2] = 0x02;
				}
				else{
					usart_su_TXpacket[2] = 0x09;
				}
				usart_send2su_array(usart_su_TXpacket, 6); 
				break;
			case 0x02://湿度
				usart_su_TXpacket[0] = 0XAA;
				usart_su_TXpacket[1] = 0X55;
				usart_su_TXpacket[2] = 0X03;
				usart_su_TXpacket[3] = dht_data.hum;
				usart_su_TXpacket[4] = 0X55;
				usart_su_TXpacket[5] = 0XAA;
				usart_send2su_array(usart_su_TXpacket, 6);
				break;
			case 0x03://空气成分
				
				usart_su_TXpacket[0] = 0XAA;
				usart_su_TXpacket[1] = 0X55;
				usart_su_TXpacket[2] = 0X01;
				usart_su_TXpacket[6] = 0X55;
				usart_su_TXpacket[7] = 0XAA;
				//sprintf(str,"0x%x",(int)(kqm_data.VOC * 100));
				//usart_su_TXpacket[4] = atoi(str);
				usart_su_TXpacket[3] = (uint8_t)(kqm_data.VOC * 100);
			//	printf("%d", usart_su_TXpacket[3]);
				usart_su_TXpacket[4] = (uint8_t)(kqm_data.CHO * 100);
				//printf("%d", usart_su_TXpacket[4]);
				usart_su_TXpacket[5] = kqm_data.CO2;
			//	printf("%d", usart_su_TXpacket[5]);
				usart_send2su_array(usart_su_TXpacket, 8);
			//	usart_send_array(usart_su_TXpacket,8);
				break;
			case 0x04://开灯
				led_enable(LED1);
				break;
			case 0x05://关灯
				led_disable(LED1);
				break;
			case 0x06://甲烷
				usart_su_TXpacket[0] = 0XAA;
				usart_su_TXpacket[1] = 0X55;
				usart_su_TXpacket[3] = (uint8_t)(kqm_data.CHO * 100);
				usart_su_TXpacket[4] = 0X55;
				usart_su_TXpacket[5] = 0XAA;
				if(kqm_data.CHO <0.03){
					usart_su_TXpacket[2] = 0x04;
				}
				else if(kqm_data.CHO >=0.03 && kqm_data.CHO <0.1){
					usart_su_TXpacket[2] = 0x05;
				}
				else{
					usart_su_TXpacket[2] = 0x06;
				}
				usart_send2su_array(usart_su_TXpacket, 6);
				break;
			case 0x07://开启蜂鸣器
				buzzer_enable();
				break;
			case 0x08://关闭蜂鸣器
				buzzer_disable();
				break;
			case 0x9://二氧化碳
				usart_su_TXpacket[0] = 0XAA;
				usart_su_TXpacket[1] = 0X55;
				usart_su_TXpacket[2] = 0x07;
				usart_su_TXpacket[3] = kqm_data.CO2;
				usart_su_TXpacket[4] = 0X55;
				usart_su_TXpacket[5] = 0XAA;
				usart_send2su_array(usart_su_TXpacket, 6);
				break;
			case 0x10://时间
				rawtime = RTC_GetCounter();
				info = localtime(&rawtime);
				
				//info=gmtime(&rawtime);
				usart_su_TXpacket[0] = 0XAA;
				usart_su_TXpacket[1] = 0X55;
				usart_su_TXpacket[2] = 0x08;
				usart_su_TXpacket[3] = (info->tm_year + 1900) / 1000;
				usart_su_TXpacket[4] = ((info->tm_year + 1900) / 100) % 10;
				usart_su_TXpacket[5] = ((info->tm_year + 1900) / 10) % 100;
				usart_su_TXpacket[6] = (info->tm_year + 1900) % 10;
				usart_su_TXpacket[7] = info->tm_mon + 1;
				usart_su_TXpacket[8] = info->tm_mday;
				usart_su_TXpacket[9] = info->tm_hour;
				usart_su_TXpacket[10] = info->tm_min;
				usart_su_TXpacket[11] = info->tm_sec;
				usart_su_TXpacket[12] = 0X55;
				usart_su_TXpacket[13] = 0XAA;
				usart_send_array(USART1, usart_su_TXpacket, 14);
				printf("%d\t%d\t%d\t%d\t", info->tm_year, info->tm_mon, info->tm_mday, info->tm_hour);
				usart_send2su_array(usart_su_TXpacket, 14);
				break;
		}
	}
}

/**
	* @brief  发送一个数组
	* @param  uint8_t *array 需要发送的数组
	* @param	uint16_t len	发送的数组长度
  * @retval None
  */
void usart_send2su_array(uint8_t *array, uint16_t len){
	uint16_t i = 0;
	for(i = 0; i < len; i++){
		usart_send2su_bit(array[i]);
	}
}

/**
  * @brief  发送单个字节
* @param  uint8_t data	需要发送的字节
  * @retval None
  */
void usart_send2su_bit(uint8_t data){
	while(USART_GetFlagStatus(UART4, USART_FLAG_TC) != 1); //等待上一次数据发送完成
	USART_SendData(UART4, data);	//发送数据
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

平衡二叉树,力扣

目录 前序遍历与后续遍历 题目地址&#xff1a; 题目&#xff1a; 我们直接看题解吧&#xff1a; 审题目事例提示&#xff1a; 解题方法&#xff1a; 难度分析&#xff1a; 解题方法分析&#xff1a; 解题分析&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; 补充说明…

idea 社区版 Database Navigator插件 列显示顺序错乱解决办法

idea 社区版 Database Navigator插件 列显示顺序错乱 影响&#xff1a;MyBatisCodeHelperPro插件生成代码字段顺序错乱 解决办法&#xff1a;将COLUMN 的排序方式由Name改为Position方式之后&#xff0c;reload即可&#xff01;

Spring Security 6.x 系列(14)—— 会话管理之源码分析

一、前言 在上篇 Spring Security 6.x 系列(13)—— 会话管理之会话概念及常用配置 Spring Security 6.x 系列(14)—— 会话管理之会话固定攻击防护及Session共享 中了清晰了协议和会话的概念、对 Spring Security 中的常用会话配置进行了说明,并了解会话固定攻击防护…

SCT52240Q双路 4A/4A 高速MOSFET/IGBT栅极驱动器, 可并联输出,替代UCC27524

• 4.5-24V宽供电电压 • 4A 峰值驱动拉电流和灌电流 • 双通道并联输出&#xff0c;增强驱动能力 • 低至-5V负压输入 • 支持TTL低压逻辑输入 • 13ns传输延迟 • 快速上升下降时间&#xff08;典型值8ns&#xff09; • 双通道1ns典型值延迟匹配时间 • 55uA静态功耗 • 输入…

巨杉数据库荣登2023胡润全球猎豹企业榜

胡润研究院与广州南沙联合发布《2023胡润全球猎豹企业榜》&#xff0c;这是胡润研究院首次发布“全球猎豹企业”。榜单列出了全球成立于2000年后&#xff0c;五年内最有可能达到独角兽级十亿美金估值的高成长性企业。巨杉数据库凭借在分布式文档型数据库领域的创新突破&#xf…

SpringMVC-视图

SpringMVC中的视图实现了View接口&#xff0c;作用是渲染数据&#xff0c;将Model中的数据展示给用户。render是渲染方法&#xff0c;可以看到渲染的视图是一个View类型的对象。 SpringMVC视图的种类有很多&#xff0c;默认有转发视图和重定向视图。 如果配置了Thymeleaf视图解…

Java 新手如何使用Spring MVC 中的查询字符串和查询参数

目录 前言 什么是查询字符串和查询参数&#xff1f; Spring MVC中的查询参数 处理可选参数 处理多个值 处理查询参数的默认值 处理查询字符串 示例&#xff1a;创建一个RESTful服务 总结 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家…

el-table表格动态添加列。多组数据拼接和多层级数据的处理

提示&#xff1a;el-table表格动态添加列 文章目录 前言一、多组数据拼接二、多层级处理三、实际应用中&#xff0c;为避免闪屏&#xff0c;可以表格数据统一渲染总结 前言 需求&#xff1a;富文本编辑器 一、多组数据拼接 <template><div class"test">…

WEB 3D技术 three.js 几何体uv属性讲解与基本演示

本文 我们来说说uv 那么 它是什么呢&#xff1f; 首先 比如 我们几何体 贴一个图 那么 为什么我们图的四个边就能正好贴到几何体的边 为什么不可以图就在几何体中间呢&#xff1f; 中心为什么能对齐 它就不能偏一点吗&#xff1f; 这是第一个问题 还有我们 gltf 这种文件 其实…

14:00面试,14:06就出来了,问的问题真的变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到5月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

分布式图文详解!

分布式理论 1. 说说CAP原则&#xff1f; CAP原则又称CAP定理&#xff0c;指的是在一个分布式系统中&#xff0c;Consistency&#xff08;一致性&#xff09;、 Availability&#xff08;可用性&#xff09;、Partition tolerance&#xff08;分区容错性&#xff09;这3个基本…

springCould中的Hystrix【上】-从小白开始【7】

目录 1.简单介绍❤️❤️❤️ 2.主要功能 ❤️❤️❤️ 3.正确案例❤️❤️❤️ 4.使用jmeter压测 ❤️❤️❤️ 5.建模块 80❤️❤️❤️ 6.如何解决上面问题 ❤️❤️❤️ 7.对8001进行服务降级❤️❤️❤️ 8.对80进行服务降级 ❤️❤️❤️ 9.通用降级方法❤️❤️…

数据中台建设之路

数据中台是在政企数字化转型过程中&#xff0c;对各业务单元业务与数据的沉淀&#xff0c;构建包括数据技术、数据治理、数据运营等数据建设、管理、使用体系&#xff0c;实现数据赋能。数据中台&#xff0c;是新型信息化应用框架体系中的核心。 1、什么是数据中台 随着企业数…

被客户骂咋办?客服请看这些处理方式

客户骂人的常见类型 1.没来得及回复就辱骂 绝大多数客户都非常反感机器人自动回复。但人工回复需要一定的回复时间&#xff0c;如果自己打字速度不快&#xff0c;则建议搭配使用快捷回复软件(客服宝) 2.说我们服务态度不好 回复上可以多加一些感叹后缀词&#xff0c;如“好…

【GO语言卵细胞级别教程】01.GO基础知识

01.GO基础知识 目录 01.GO基础知识1.GO语言的发展历程2.发展历程3.Windowns安装4.VSCode配置5.基础语法5.1 第一段代码5.2 GO执行的流程5.3 语法规则5.4 代码风格5.5 学习网址 1.GO语言的发展历程 Go语言是谷歌公司于2007年开始开发的一种编程语言&#xff0c;由Robert Griese…

PTA——逆序的三位数

程序每次读入一个正3位数&#xff0c;然后输出按位逆序的数字。注意&#xff1a;当输入的数字含有结尾的0时&#xff0c;输出不应带有前导的0。比如输入700&#xff0c;输出应该是7。 输入格式&#xff1a; 每个测试是一个3位的正整数。 输出格式&#xff1a; 输出按位逆序…

洛谷P1024[NOIP2001 提高组] 一元三次方程求解(cpp)(二分查找)

目录 1.题目 2.思路 3.AC 1.题目 # [NOIP2001 提高组] 一元三次方程求解 ## 题目描述 有形如&#xff1a; 这样的一个一元三次方程。给出该方程中各项的系数&#xff08;a,b,c,d 均为实数&#xff09;&#xff0c;并约定该方程存在三个不同实根&#xff08;根的范围在 -…

【每日论文阅读】单目深度估计 近期进展

红外场景单目深度估计的难点 缺乏准确的深度参考标准&#xff1a;红外场景下的深度估计通常需要依赖于大量的输入图像和对应的深度值作为训练的约束。然而&#xff0c;获取准确的深度参考标准是一个挑战&#xff0c;目前常用的方法是使用红外传感器&#xff08;如Kinect&#…

熔断、隔离、重试、降级、超时、限流,高可用架构流量治理核心策略全掌握

可用性的定义 在探讨高可用架构之前&#xff0c;让我们以 O2 系统为例&#xff0c;解释一下何谓可用性。O2 是腾讯内部的一个广告投放系统&#xff0c;专注于提升投放效率、分析广告效果&#xff0c;拥有自动化广告投放、AIGC 自动化素材生产等多种功能。 其整体架构概览如下&…

prometheus grafana redis安装配置监控

文章目录 前传安装redis-exporterredis_exporter参数配置参考配置prometheus查看promethues redis job节点grafana配置外传 前传 prometheus grafana的安装使用&#xff1a;https://nanxiang.blog.csdn.net/article/details/135384541 本文说下监控nginx&#xff0c;promethe…