共计 3307 个字符,预计需要花费 9 分钟才能阅读完成。
背景与痛点
传统的小车遥控方式通常使用红外遥控或蓝牙模块,这些方式虽然成熟,但存在一些明显的局限性:

- 红外遥控需要对准接收器,且容易受到环境光线干扰
- 蓝牙遥控需要手机或专用遥控器,操作不够直观
- 都需要手持设备,无法实现真正的 ” 解放双手 ” 操作
相比之下,语音控制具有以下优势:
- 自然交互:符合人类最自然的沟通方式
- 解放双手:无需携带或操作额外设备
- 可扩展性强:通过语音指令可以轻松扩展更多功能
- 适用场景广:特别适合智能家居、残障辅助、教育机器人等领域
硬件选型
常见的语音识别方案主要有以下几种:
- 离线语音模块(如 LD3320、ASRPRO)
- 在线语音识别(如百度语音、阿里云语音)
- MCU+ 算法方案(如 STM32+ 神经网络)
我们选择 ASRPRO 的原因:
- 完全离线工作,不依赖网络
- 高识别率,支持中文指令
- 内置 DSP 处理器,识别速度快
- 提供图形化训练工具,降低开发门槛
- 成本适中,适合教育和小批量生产
系统架构
整体硬件连接如下:
- ASRPRO 语音识别模块
- 通过 UART 与 STM32 通信
- 3.3V 供电,注意电平匹配
-
麦克风输入接口
-
STM32F103C8T6 最小系统板
- 核心控制器
-
负责指令解析和电机控制
-
L298N 电机驱动模块
- 驱动两个直流电机
-
需要 12V 电源单独供电
-
电源系统
- 建议使用两路独立电源
- 一路 5V/3.3V 给控制部分
- 一路 12V 给电机驱动
通信协议采用简单的串口协议:
- 波特率:115200bps
- 数据位:8 位
- 停止位:1 位
- 无校验位
ASRPRO 识别到指令后,会通过串口发送预设的指令代码,如:
- “ 前进 ” → 发送 0x01
- “ 后退 ” → 发送 0x02
- “ 左转 ” → 发送 0x03
- “ 右转 ” → 发送 0x04
- “ 停止 ” → 发送 0x00
核心实现
ASRPRO 语音指令训练
使用 ASRPRO 配套的图形化工具进行语音训练:
- 创建新项目,选择中文模型
- 添加唤醒词(如 ” 小车小车 ”)
- 添加控制指令:
- “ 前进 ”
- “ 后退 ”
- “ 左转 ”
- “ 右转 ”
- “ 停止 ”
- 为每个指令分配对应的命令码
- 导出配置文件并烧录到模块
STM32 串口接收解析
使用 HAL 库实现串口接收:
// 串口初始化
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
// 开启接收中断
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}
// 中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART1)
{switch(rx_data)
{case 0x01: moveForward(); break;
case 0x02: moveBackward(); break;
case 0x03: turnLeft(); break;
case 0x04: turnRight(); break;
case 0x00: stop(); break;}
// 重新开启接收
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}
}
PWM 电机驱动控制
使用 TIMER 产生 PWM 波控制电机速度:
// PWM 初始化
TIM_HandleTypeDef htim2;
TIM_OC_InitTypeDef sConfigOC = {0};
void MX_TIM2_Init(void)
{
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71; // 72MHz/(71+1) = 1MHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999; // 1MHz/1000 = 1kHz PWM 频率
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim2);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比 0%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}
// 电机控制函数
void setMotorSpeed(uint8_t motor, uint16_t speed)
{if(speed > 1000) speed = 1000; // 限幅
switch(motor)
{
case MOTOR_LEFT:
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, speed);
break;
case MOTOR_RIGHT:
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, speed);
break;
}
}
避坑指南
语音识别误触发处理
- 环境降噪:
- 在麦克风周围添加海绵减震
-
软件端设置合适的识别阈值
-
指令确认机制:
- 重要指令要求二次确认
-
添加 ” 撤销 ” 指令
-
超时处理:
- 设置指令有效时间窗口
- 长时间无操作自动进入休眠
电机驱动电流保护
- 硬件保护:
- 电机电源并联大电容(1000uF 以上)
-
添加自恢复保险丝
-
软件保护:
- 限制 PWM 占空比变化率
- 监测电机电流(如有 ADC)
- 异常时自动切断输出
多任务调度注意事项
- 中断优先级:
- 串口中断优先级应高于定时器
-
避免在中断中进行复杂计算
-
任务划分:
- 语音识别处理放在主循环
- 电机控制放在定时中断
- 使用状态机管理小车行为
扩展思考:离线语音唤醒
要实现离线语音唤醒功能,可以考虑:
- 硬件层面:
- 选择支持唤醒词的语音模块(如 ASRPRO 的唤醒模式)
-
添加低功耗设计,唤醒时给主控供电
-
软件层面:
- 设置唤醒词识别专用线程
- 唤醒后激活其他功能模块
- 超时无操作自动休眠
示例代码:
void enterSleepMode(void)
{
// 关闭外设
HAL_UART_DeInit(&huart1);
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2);
// 配置唤醒源(如 EXTI)HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
// 进入停止模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();}
进一步优化方向
- 加入 PID 速度控制,实现精准移动
- 添加超声波或红外避障功能
- 开发手机 APP 进行参数配置
- 实现多小车协作控制
- 加入语音反馈功能(如 TTS 模块)
通过以上步骤,我们完成了一个完整的语音控制小车系统。这个项目不仅适用于教学演示,也可以作为智能家居控制的原型。希望这篇指南能帮助嵌入式开发新手快速入门语音交互开发。
正文完
