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

news2025/5/26 7:59:53

目录

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);	//发送数据
}

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

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

相关文章

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

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

本地监控jar包可视化性能数据

一、机器申请 二、maven项目jar打包 三、机器性能监控 1.jdk版本配置 本地下载的机器虽自带jdk&#xff0c;但是jdk版本过低&#xff0c;需重新安装jdk 参考&#xff1a; Linux系统安装JDK1.8 详细流程_linux安装jdk1.8-CSDN博客 2.jvm参数修改 需修改jvm堆内存 栈内存信…

【Java期末】学生成绩管理系统

诚接计算机专业编程任务(C语言、C、Python、Java、HTML、JavaScript、Vue等)10/15R&#xff0c;如有需要请私信我&#xff0c;或者加我的企鹅号&#xff1a;1404293476 本文资源下载地址&#xff1a;https://download.csdn.net/download/weixin_47040861/88697244 —————…

环境监测LoRa网关解决方案应用空气质量监控

随着全球工业化和城镇化的快速发展&#xff0c;空气质量问题越来越受到关注。环境监测技术的发展&#xff0c;可以有效地帮助我们监测和改善空气质量。而LoRa网关则是一种可以帮助我们实现远距离、低功耗通信的无线通信技术&#xff0c;它的应用可以为空气质量监测提供解决方案…

Linux软连接的创建、删除、修改

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 软连接介绍 软链接&#xff08;Soft Link&#xff09;也称为符号链接&#xff08;Symbolic Link&#xff09;.Linux里面的软链接…

Python+Selenium+ChromeDriver的配置和问题解决

安装前的准备 1.python的安装和配置 在Window下&#xff1a;在开始菜单中找到运行输入cmd或直接搜索cmd点击进入&#xff0c;输入python&#xff0c;如果出现下图中的>>>则证明Python安装成功。 检测Chrome的版本号安装Chromedriver 记录版本号&#xff1a; 87.0.42…

学习华为企业无线网络,有这篇文章就够了(一)

华为HCIA视频教程&#xff1a;超级实用&#xff0c;华为VRP系统文件详解 华为HCIA视频教程&#xff1a;不会传输层协议&#xff0c;HCIA都考不过 华为HCIA视频教程&#xff1a;网络工程师的基本功&#xff1a;网络地址转换NAT 华为HCIP视频教程&#xff1a;DHCP协议原理与配…

Django 6 后台与便签

1. 什么是后台管理 后台管理是网页管理员利用网页的后台程序管理和更新网站上网页的内容。各网站里网页内容更新就是通过网站管理员通过后台管理更新的。 2. 创建超级用户 1. python .\manage.py createsuperuser 2. 输入账号密码等信息 Username (leave blank to use syl…

SparkGraphX 基础解析(五)

1、Spark GraphX概述 1.1什么是Spark GraphX Spark GraphX是一个分布式图处理框架&#xff0c;它是基于Spark平台提供对图计算和图挖掘简洁易用的而丰富的接口&#xff0c;极大的方便了对分布式图处理的需求。 那么什么是图&#xff0c;都计算些什么&#xff1f;众所周知社交…

面试算法88:爬楼梯的最少成本

题目 一个数组cost的所有数字都是正数&#xff0c;它的第i个数字表示在一个楼梯的第i级台阶往上爬的成本&#xff0c;在支付了成本cost[i]之后可以从第i级台阶往上爬1级或2级。假设台阶至少有2级&#xff0c;既可以从第0级台阶出发&#xff0c;也可以从第1级台阶出发&#xff…

SpringBoot-搭建集成Mybatis的项目

本文介绍了如何在IntelliJ IDEA中使用SpringBoot和Mybatis构建Java Web应用程序。通过本文的学习&#xff0c;读者将了解如何使用IntelliJ IDEA快速搭建一个基于SpringBoot和Mybatis的Java Web应用程序&#xff0c;提高开发效率。IntelliJ IDEA是一款功能强大的Java集成开发环境…

训练过程中验证精度高于训练精度可能的原因

可能的原因&#xff1a; 1. 在数据集很大的时候&#xff0c;loss下降很明显。train loss是平均一个epoch内的所有loss&#xff0c;比如第一个epoch的loss是2.3,2.2,2.1...0.7,0.6 平均train loss是1.5&#xff0c; 而val的时候是用已经训练了一个epoch的model进行测试的&…

【NP】规约与问题复杂度

目录 多项式时间规约复杂度类 多项式时间规约 Polynomial-Time Reductions &#xff1a;如果问题 Y Y Y 的任意实例可以通过多项式次数的标准计算步骤&#xff0c;加上对解决问题 X X X 的黑盒的多项式次数调用来解决&#xff0c;那么称问题 Y Y Y 可以在多项式时间归约为问…

网络爬虫之金融数据前后端实现

基金监控项目实战 一 设计思想 爬虫 采集基金公司的数据 单线程爬虫&#xff0c;用requests进行处理 web开发 前端 负责页面的设计的设计 HTMLCSSJavaScriptecharts 后端 负责调用爬虫获取数据&#xff0c;传输给前端 Flask框架 流程思维导图&#xff1a; 二 前端设计 …

【AI】使用LoFTR进行图像匹配测试Demo

LoFTR图像匹配的源码解析我们在上篇文章中已经写了&#xff0c;对于怎么试用一下&#xff0c;我这边再啰嗦一下。 0.环境搭建 详细的搭建教程请点击链接查看&#xff0c;这里只对需要特殊注意的地方做阐述 1.创建的Python环境采用python3.8的环境&#xff0c;因为文章发布较早…

CMake入门教程【核心篇】添加库(add_library)

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「本文的内容」&#xff1a;CMake入门教程 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 1. 基本用法2.STATIC…

DevOps(3)

目录 11.描述root账户&#xff1f; 12.如何在发出命令时打开命令提示符&#xff1f; 14.Linux系统下交换分区的典型大小是多少&#xff1f; 15.什么是符号链接&#xff1f; 11.描述root账户&#xff1f; root账户就像一个系统管理员账户&#xff0c;允许你完全控制系统。 …

[DevOps-03] Build阶段-Maven安装配置

一、简要说明 下载安装JDK8下载安装Maven二、复制准备一台虚拟机 1、VM虚拟复制克隆一台机器 2、启动刚克隆的虚拟机,修改IP地址 刚刚克隆的虚拟机 ,IP地址和原虚拟的IP地址是一样的,需要修改克隆后的虚拟机IP地址,以免IP地址冲突。 # 编辑修改IP地址 $ vi /etc/sysconfig…

6. Mybatis 缓存

6. Mybatis 缓存 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率MyBatis系统中默认定义了两级缓存 一级缓存二级缓存 默认情况下&#xff0c;只有一级缓存&#xff08;SqlSession级别的缓存&#xff0c;也称为本地缓存&…

OpenGL如何基于glfw库 进行 点线面 已解决

GLFW是现在较流行、使用广泛的OpenGL的界面库&#xff0c;而glut库已经比较老了。GLEW是和管理OpenGL函数指针有关的库&#xff0c;因为OpenGL只是一个标准/规范&#xff0c;具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多&#xff0c;它大多数函数的位置…