第一次接触HC-05蓝牙模块时,我把它想象成一个"无线串口助手"。这个火柴盒大小的蓝色模块,本质上是个自带蓝牙协议的串口透传设备,能帮我们把有线串口通信无线化。市面上常见的HC-05有6个引脚:VCC(3.3V-5V供电)、GND、TXD(发送)、RXD(接收)、STATE(状态指示)和EN(使能脚)。实际使用时,我们主要关注前四个引脚。
连接硬件时有个容易踩坑的地方:TXD和RXD需要交叉连接。也就是说,模块的TXD要接USB转TTL的RXD,模块的RXD接USB转TTL的TXD。去年帮学弟调试时,他就因为直连导致通信失败,折腾了半天才发现这个细节。供电方面,虽然模块标称支持3.3V-5V,但实测5V供电更稳定,特别是在长距离通信时。
模块上有颗LED指示灯,它的闪烁状态会告诉我们当前的工作模式:
要让HC-05进入AT指令模式,就像给手机刷机需要先进入recovery模式一样,需要特定操作组合。根据我的实测经验,成功率最高的步骤如下:
这里有个常见问题:有时发送AT指令后没有任何反应。我遇到过三种可能原因:
HC-05的AT指令就像它的控制密码,通过不同指令组合可以定制化模块行为。下面这些指令是我在多个项目中验证过的实用配置:
基础查询指令:
bash复制AT+NAME? # 查询当前模块名称(默认HC-05)
AT+PSWD? # 查询配对密码(默认1234)
AT+UART? # 查询波特率参数(默认38400,0,0)
参数配置指令:
bash复制AT+NAME=MyDrone # 设置设备名为"MyDrone"
AT+PSWD=6688 # 修改配对密码为6688
AT+UART=9600,0,0 # 设置通信波特率为9600(与STM32通信时常用)
高级设置指令:
bash复制AT+ROLE=1 # 设置为主模式(0从模式,1主模式,2回环)
AT+CMODE=1 # 任意蓝牙地址连接模式
AT+INIT # 初始化SPP协议(主模式需执行)
实际配置时,我建议按这个顺序操作:
特别注意:波特率设置需要两次生效。第一次设置后,模块会以新波特率通信,但断电后会恢复默认值。需要再发送AT+RESET保存设置,或者重新上电后再次用38400波特率进入AT模式确认设置。
以STM32F103C8T6(蓝莓派开发板)为例,与HC-05的连接非常简单:
在代码层面,需要先初始化USART外设。下面这个初始化函数我一直在用,稳定可靠:
c复制void USART3_Init(u32 baudrate) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
// 配置TX引脚(PB10)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置RX引脚(PB11)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// USART参数配置
USART_InitStruct.USART_BaudRate = baudrate;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStruct);
// 使能接收中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
NVIC_EnableIRQ(USART3_IRQn);
// 启动串口
USART_Cmd(USART3, ENABLE);
}
关键点说明:
当硬件和基础通信都准备好后,就可以实现手机通过蓝牙控制设备的完整链路了。这里以控制直流电机为例,展示典型实现方案。
中断服务函数处理接收数据:
c复制void USART3_IRQHandler(void) {
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
uint8_t ch = USART_ReceiveData(USART3);
switch(ch) {
case 'A': // 前进指令
Motor_Forward();
break;
case 'B': // 后退指令
Motor_Backward();
break;
case 'S': // 停止指令
Motor_Stop();
break;
default:
break;
}
}
}
手机端配置(以安卓蓝牙调试助手为例):
调试时常见问题排查:
完成基础功能后,我通常会做这些优化使项目更可靠:
通信协议优化:
示例协议帧:
code复制[0xAA][CMD][DATA][CHECKSUM][0x55]
电源管理改进:
安全增强措施:
c复制#define MAX_CMD_RATE 10 // 每秒最大指令数
void USART3_IRQHandler(void) {
static uint32_t last_time = 0;
static uint8_t cmd_count = 0;
uint32_t current = HAL_GetTick();
if(current - last_time > 1000) {
cmd_count = 0;
last_time = current;
}
if(cmd_count++ > MAX_CMD_RATE) {
return; // 超出频率限制
}
// ...原有处理逻辑
}
这些优化虽然增加了开发难度,但能让项目在实际环境中稳定运行。记得第一次做智能小车时,就因为没有防抖处理,导致电机在信号干扰下突然启动,差点撞到实验设备。