ASRPRO系列语音模块(第十天)
👨💻个人主页:@开发者-削好皮的Pineapple!
👨💻 hello 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!
👨💻 本文由 削好皮的Pineapple! 原创
👨💻 收录于专栏:C语言到基于STM32 的智能矿探小车
文章目录
- 🎶一、语音模块编程环境搭建与配置
- 🎶二、语音模块与矿探小车控制系统的通信集成
- (一)GPIO引脚直连方案
- (二)串口通信方案(推荐用于矿探小车多指令控制)
- 结束语🥇
⭐前言⭐
- 本文聚焦矿探小车语音控制功能的实现,详细记录ASRPRO语音模块与STM32单片机的集成过程,包括编程环境搭建与通信方式调试,为小车智能化控制提供关键技术参考。
🎶一、语音模块编程环境搭建与配置
- 矿探小车采用ASRPRO系列语音模块实现语音交互,配套编程工具为天问BLOCK界面化编程软件,具体搭建步骤如下:
- 解压twenBlock.zip压缩包,双击安装包并按提示操作,安装路径需设置为纯英文目录,避免中文路径导致的兼容问题。
- 安装完成后需联网注册账号,勾选“记录密码”可简化后续登录流程。
- 模块程序开发流程:完成语音识别模型配置后,依次点击“生成模型”与“编译下载”,即可将程序烧录至ASRPRO模块。
🎶二、语音模块与矿探小车控制系统的通信集成
(一)GPIO引脚直连方案
- 适用于简单单指令控制,以“开灯”指令为例:
- 硬件连接:ASRPRO的PA0引脚(指令触发时输出高电平)与STM32的PC7引脚相连。
- STM32配置:将PC7引脚设置为浮空输入模式,用于检测ASRPRO输出的电平信号。
- 控制逻辑代码:
if(GPIO_READINPUTDATE(GPIOC,GPIO_PIN_7) == 1) {//执行矿探小车灯光开启操作car_light_on(); }
- 局限性:仅支持单一指令,扩展多指令需增加引脚数量,布线复杂度提升。
(二)串口通信方案(推荐用于矿探小车多指令控制)
- 利用ASRPRO的串口0实现与STM32的双向通信,支持多指令扩展:
- 硬件连接:
ASRPRO串口0 STM32串口(USART1/2/3) VCC VCC(3.3V/5V,需匹配模块电压) GND GND PB5(TX) RX(接收引脚) PB6(RX) TX(发送引脚) - 控制逻辑代码示例(支持小车前进、开灯等多指令):
if(recv == 'A') {//矿探小车前进控制car_move_forward(); } else if(recv == 'B') {//矿探小车灯光开启car_light_on(); } //可扩展后退('C')、转向('D'/'E')等指令
- 硬件连接:
- 优势:通过字符编码区分多指令,无需增加硬件引脚,适配矿探小车复杂运动控制需求。
#include "stm32f4xx.h"
#include "uart.h"
#include "car.h"
#include "led.h"
#include <stdio.h>// 全局变量定义
u8 recv; // USART2接收数据(命令指示)
u8 rdata; // USART3接收数据(MQ2传感器数据)
u8 asr_cmd; // 新增:ASRPRO接收的指令
u8 mq2_response[9]; // 存储MQ2模块响应数据帧
u16 smoke_concentration; // 存储烟雾浓度值(百分比)
volatile uint8_t mq2_response_index = 0; // 记录MQ2响应帧索引
static uint8_t is_sending = 0; // 发送状态标志,防止数据冲突
uint8_t request_smoke_data = 0; // 请求烟雾数据标志// 向MQ2模块发送请求数据帧(固定帧)
void send_mq2_request(void) {int i;u8 request_data[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};for (i = 0; i < 9; i++) {while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);USART_SendData(USART3, request_data[i]);}
}// 解析MQ2数据接收逻辑,包括帧格式和校验位验证
void parse_mq2_response(void) {u8 checksum = 0;u16 raw_value;int i;// 1. 验证帧头格式,MQ2响应帧头为FF 86if (mq2_response[0] != 0xFF || mq2_response[1] != 0x86) {smoke_concentration = 0; // 帧格式错误,返回0return;}// 2. 计算校验和,确保数据有效性for (i = 0; i < 8; i++) {checksum += mq2_response[i];}checksum = 0xFF - (checksum % 0xFF);if (checksum != mq2_response[8]) {smoke_concentration = 0; // 校验失败,返回0return;}// 3. 提取有效数据,浓度值在第2和3字节raw_value = (mq2_response[2] << 8) | mq2_response[3]; // 合并字节// 4. 根据公式进行实际浓度转换if (raw_value > 5000) {smoke_concentration = 100;} else {smoke_concentration = (raw_value * 100) / 5000;}
}// 修改字符串发送逻辑,确保数据完整发送
void send_smoke_concentration_to_bluetooth(void) {char buffer[20];int i;uint32_t timeout;if (is_sending) return; // 避免冲突,直接退出is_sending = 1;// 格式化字符串,确保格式正确snprintf(buffer, sizeof(buffer), "Smoke: %d%%\n", smoke_concentration);// 暂时关闭串口接收中断,防止冲突USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);// 发送字符串,添加超时机制for (i = 0; buffer[i] != '\0'; i++) {timeout = 0;// 等待发送缓冲区为空,超时值设置为500000while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) {if (timeout++ > 500000) { // 简单的超时处理is_sending = 0;// 恢复中断并退出USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);return;}}USART_SendData(USART2, buffer[i]);}// 发送完成,恢复中断USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);is_sending = 0;
}// 新增:ASRPRO通信串口初始化
void USART1_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;// 使能GPIOA和USART1时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);// 配置USART1 Tx (PA9)和Rx (PA10)引脚GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOA, &GPIO_InitStruct);// 将PA9和PA10复用为USART1功能GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);// 配置USART1参数USART_InitStruct.USART_BaudRate = 9600; // 与ASRPRO通信波特率USART_InitStruct.USART_WordLength = USART_WordLength_8b;USART_InitStruct.USART_StopBits = USART_StopBits_1;USART_InitStruct.USART_Parity = USART_Parity_No;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStruct);// 使能USART1接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 配置NVIC中断NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 优先级高于USART2和USART3NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStruct);// 使能USART1USART_Cmd(USART1, ENABLE);
}// 串口初始化函数(固定帧)
void uart_init(int bond) {// 原始代码不变,确保USART2和USART3配置正确GPIO_InitTypeDef GPIO_InitStruct;USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 | RCC_APB1Periph_USART3, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;// USART2 (PA2=TX, PA3=RX)GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;GPIO_Init(GPIOA, &GPIO_InitStruct);// USART3 (PB10=TX, PB11=RX)GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);USART_InitStruct.USART_BaudRate = bond;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(USART2, &USART_InitStruct);USART_Init(USART3, &USART_InitStruct);USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;NVIC_Init(&NVIC_InitStruct);USART_Cmd(USART2, ENABLE);USART_Cmd(USART3, ENABLE);// 初始化USART1用于ASRPRO通信USART1_Init();
}// 新增:ASRPRO通信中断处理
void USART3_IRQHandler(void) {if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET) {asr_cmd = USART_ReceiveData(USART3);// 解析ASRPRO发送的指令switch (asr_cmd) {case 'A':// 开灯led_ctrl(D1,ON);break;case 'F':// 小车前进car_up();break;case 'B':// 小车后退car_back();break;case 'L':// 小车左转car_left();break;case 'R':// 小车右转car_right();break;case 'S':// 小车停止car_stop();break;case 'G':// 请求烟雾浓度request_smoke_data = 1;break;default:// 未知指令break;}USART_ClearITPendingBit(USART3, USART_IT_RXNE);}
}// 中断处理函数(固定帧)
void USART2_IRQHandler(void) {if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) {recv = USART_ReceiveData(USART2);USART_ClearITPendingBit(USART2, USART_IT_RXNE);// 检测特定指令触发烟雾浓度请求if (recv == 'S' || recv == 's') { // 当接收到 'S' 或 's' 时请求数据request_smoke_data = 1;}}
}//void USART3_IRQHandler(void) {
// if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET) {
// rdata = USART_ReceiveData(USART3);
// mq2_response[mq2_response_index++] = rdata;
// // 接收到9字节后开始处理
// if (mq2_response_index == 9) {
// mq2_response_index = 0;
// parse_mq2_response();
// send_smoke_concentration_to_bluetooth(); // 发送浓度数据
// request_smoke_data = 0; // 重置请求标志
// }
// USART_ClearITPendingBit(USART3, USART_IT_RXNE);
// }
//}
#ifndef __UART_H__
#define __UART_H__
#include "stm32f4xx.h"void uart_init(int bond);
void USART1_Init(void); // 新增:ASRPRO通信串口初始化
void USART2_IRQHandler(void);
void USART3_IRQHandler(void);
void USART1_IRQHandler(void); // 新增:ASRPRO通信中断处理
void send_mq2_request(void);
void send_smoke_concentration_to_bluetooth(void);extern u8 recv; // USART2接收数据(命令)
extern u8 rdata; // USART3接收数据(MQ2传感器数据)
extern u8 asr_cmd; // 新增:ASRPRO接收的指令
extern uint8_t request_smoke_data; // 请求烟雾数据标志
#endif
#include "stm32f4xx.h"
#include "exit.h"
#include "car.h"
#include "delay.h"
#include "remote.h"
#include "uart.h"
#include "led.h"extern uint8_t request_smoke_data;int main(void) {// 系统初始化SystemInit();// 外设初始化car_init(); // 初始化小车控制remote_Init(); // 初始化遥控器delay_init(); // 初始化延时函数led_init(); // 初始化LEDuart_init(9600); // 初始化串口,波特率9600//car_up();// 系统启动提示// USART2_SendString("系统已启动,等待指令...\r\n");// USART1_IRQHandler();while(1) {// 当请求标志被设置时发送MQ2请求if (request_smoke_data) {send_mq2_request();// 等待一段时间以确保数据接收完成delay_ms(500);}// 其他可能的主循环任务// ...// 低功耗延时,减少CPU占用delay_ms(10);}
}
且记录且珍惜,又不想记录了。
结束语🥇
🔥 订阅专栏持续学习:C语言到基于STM32的智能矿探小车
💬 欢迎点赞、收藏、留言讨论,后续将分享语音模块与蓝牙模块的协同控制方案,进一步提升矿探小车的操作便捷性!