基于STM32F103C8T6与HC-05的蓝牙串口透传:从零构建手机APP无线控制LED系统
1. 项目背景与硬件准备
第一次接触STM32和蓝牙模块时,我被这个组合的潜力惊艳到了。想象一下,用手机就能控制家里的灯光,这种物联网的初级应用其实离我们并不遥远。这次我们要用STM32F103C8T6(俗称"蓝莓板")和HC-05蓝牙模块搭建一个无线LED控制系统,整个过程就像搭积木一样有趣。
你需要准备的硬件清单很简单:
- STM32F103C8T6最小系统板(某宝20元左右)
- HC-05蓝牙模块(建议买带底板版本,约15元)
- LED灯(普通5mm直径即可)
- 220欧姆限流电阻
- 杜邦线若干(建议公对公、母对母各准备10根)
- USB转TTL模块(用于调试,CH340芯片版本最便宜)
特别提醒新手:HC-05模块有JDY-31、HC-06等变种,建议选择经典HC-05,因为它的资料最全。我刚开始贪便宜买了不知名型号,结果AT指令不兼容,调试了整整两天。
2. 硬件连接详解
2.1 电路原理分析
这个项目的核心是串口通信。STM32通过USART与HC-05对话,就像两个人用对讲机交流。当手机APP发送"led on"时,蓝牙模块会把这句话原样传给STM32,单片机收到后就让PC13引脚输出低电平,点亮LED。
接线时要注意电压匹配:HC-05的工作电压是3.3V,而STM32的IO口也是3.3V电平,所以可以直接连接。如果用5V供电的Arduino,就需要电平转换电路了。
2.2 具体接线步骤
按照这个顺序连接最不容易出错:
- 先接电源:STM32的3.3V → HC-05的VCC,GND对GND
- 串口交叉连接:HC-05的TXD接STM32的PA10(RX),HC-05的RXD接STM32的PA9(TX)
- LED电路:PC13引脚 → 220Ω电阻 → LED正极 → LED负极 → GND
实测中发现个坑:如果先用USB给STM32供电,再接蓝牙模块,有时会出现通信失败。正确的上电顺序应该是先接好所有线路,最后再通电。
3. HC-05蓝牙模块配置
3.1 AT指令实战
要让蓝牙模块听话,得先进入它的"配置模式":
- 按住模块上的小按钮不放
- 同时给模块上电
- 看到指示灯变成慢闪(约2秒一次)后松开按钮
这时候用USB转TTL连接电脑,打开串口调试助手(推荐使用XCOM V2.2),关键设置:
- 波特率:38400(配置模式固定值)
- 数据位:8
- 停止位:1
- 校验位:无
发送"AT"应该会收到"OK"回复。我整理了最实用的几条AT指令:
| 指令 | 功能说明 | 示例 |
|---|---|---|
| AT+NAME? | 查询当前设备名 | 返回:+NAME:HC-05 |
| AT+NAME=MyLED | 修改设备名为MyLED | 成功后返回OK |
| AT+UART? | 查询通信波特率 | 返回:+UART:9600,0,0 |
| AT+UART=115200,0,0 | 修改波特率为115200 | 需重启生效 |
| AT+PSWD=1234 | 设置配对密码为1234 | 防止别人乱连 |
3.2 常见问题排查
遇到过最头疼的问题是发送AT指令没反应,通常有三个原因:
- 串口线接反了(TXD-RX要交叉)
- 波特率不对(必须38400)
- 模块没进入AT模式(指示灯必须是慢闪)
建议新手先用手机蓝牙搜索模块,如果能发现设备,说明基础功能正常,可以继续调试。
4. STM32程序设计
4.1 开发环境搭建
我用的是Keil MDK+STM32CubeMX组合拳:
- 安装STM32CubeMX后,选择STM32F103C8T6芯片
- 配置USART1为异步模式,波特率9600(与HC-05匹配)
- 启用PC13为GPIO_Output
- 生成代码后用Keil打开工程
关键代码片段解析:
// 串口中断回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1){ if(RxBuffer[0] == 'o'){ // 收到'on'开头的指令 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); HAL_UART_Transmit(&huart1, "LED ON\r\n", 8, 100); } else if(RxBuffer[0] == 'f'){ // 收到'off'指令 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, "LED OFF\r\n", 9, 100); } HAL_UART_Receive_IT(&huart1, RxBuffer, 1); // 重新启用接收 } }4.2 通信协议设计
为了让控制更可靠,我设计了个简单协议:
- 指令以'#'开头,'$'结尾
- 中间为命令内容,如"#on$"表示开灯
对应的代码处理逻辑:
if(RxBuffer[0] == '#'){ command_flag = 1; cmd_index = 0; } else if(RxBuffer[0] == '$' && command_flag){ command_flag = 0; process_command(received_cmd); // 处理存储的命令 } else if(command_flag){ received_cmd[cmd_index++] = RxBuffer[0]; }5. 手机APP配置与调试
5.1 蓝牙调试APP选择
试过十几款APP后,我推荐这两款:
- 蓝牙串口助手(安卓):界面简洁,支持指令保存
- Serial Bluetooth Terminal:开源免费,可自定义界面
安装后先配对设备(默认密码一般是1234或0000),然后选择SPP协议连接。成功连接后HC-05的指示灯会从快闪变为双闪。
5.2 调试技巧分享
遇到数据收发不正常时,可以:
- 先用USB转TTL连接电脑,用串口助手看原始数据
- 在STM32程序里添加调试输出,比如:
printf("Received: %s\r\n", RxBuffer);- 检查手机APP的发送格式,是否添加了换行符(建议统一用\r\n)
有个容易忽略的细节:部分手机会在后台休眠时断开蓝牙连接,需要在APP设置里保持常连接。
6. 项目优化与扩展
完成基础功能后,可以尝试这些升级:
- 多LED控制:用不同指令控制多个GPIO口
- 状态反馈:STM32将LED状态回传给手机
- PWM调光:通过发送数值调节LED亮度
- 定时功能:实现手机端预约开关
进阶版代码结构示例:
typedef struct { uint8_t cmd; uint8_t pin; uint8_t value; } BLUETOOTH_CMD; void parse_command(char* str) { BLUETOOTH_CMD bt_cmd; sscanf(str, "%c%d%d", &bt_cmd.cmd, &bt_cmd.pin, &bt_cmd.value); switch(bt_cmd.cmd){ case 'S': // Set pin HAL_GPIO_WritePin(get_port(bt_cmd.pin), get_pin(bt_cmd.pin), bt_cmd.value ? GPIO_PIN_SET : GPIO_PIN_RESET); break; case 'P': // PWM control set_pwm_duty(bt_cmd.pin, bt_cmd.value); break; } }最后提醒大家,下载程序时要断开蓝牙模块的TX线,否则可能干扰烧录。这个项目虽然简单,但涵盖了嵌入式开发的完整流程,非常适合作为物联网开发的入门练习。
