1. 项目概述
最近在做一个智能家居的小demo,用STM32 CubeIDE开发环境搭配蓝牙模块实现了手机APP控制LED灯的功能。这个方案成本低、响应快,特别适合智能开关、遥控灯具等场景。下面就把整个实现过程拆解一下,包括硬件选型、环境搭建、代码编写和调试技巧。
市面上常见的蓝牙模块有HC-05、HC-06、JDY-31等,我最终选择了JDY-31蓝牙4.2模块。相比经典蓝牙模块,它的功耗更低(工作电流8mA),支持AT指令配置,而且价格只要十几块钱。最关键的是它支持主从一体模式,既可以作为主机连接手机,也能作为从机被其他设备发现。
2. 硬件准备与连接
2.1 所需材料清单
- STM32F103C8T6最小系统板(蓝色药丸板)
- JDY-31蓝牙模块(注意要买3.3V版本)
- LED灯及220Ω限流电阻
- USB转TTL模块(用于蓝牙初始配置)
- 杜邦线若干
2.2 电路连接示意图
蓝牙模块与STM32的连接非常简单:
code复制JDY-31 STM32
VCC → 3.3V
GND → GND
TXD → PA3(USART2_RX)
RXD → PA2(USART2_TX)
LED灯接在PB12引脚,记得串联限流电阻。初次使用蓝牙模块时,建议先用USB转TTL连接电脑,用串口助手发送AT指令测试模块是否正常。
注意:蓝牙模块的TXD要接MCU的RX,RXD接TX,这个交叉连接新手容易搞反。如果发现无法通信,首先检查这个接线。
3. 开发环境配置
3.1 STM32CubeIDE设置
- 新建工程时选择STM32F103C8Tx系列
- 在Pinout视图启用USART2:
- Mode选择Asynchronous
- 波特率保持默认9600(后续可改)
- 配置PB12为GPIO_Output
- 在Project Manager勾选"Generate peripheral initialization as a pair of .c/.h files"
3.2 关键代码实现
在main.c中添加以下核心逻辑:
c复制// 在USER CODE BEGIN PV区域定义变量
uint8_t rxData[1];
uint8_t ledState = 0;
// 在main()的while循环前启用串口接收中断
HAL_UART_Receive_IT(&huart2, rxData, 1);
// 在USER CODE BEGIN 4区域添加回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(rxData[0] == '1') {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
ledState = 1;
}
else if(rxData[0] == '0') {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
ledState = 0;
}
HAL_UART_Transmit(&huart2, &ledState, 1, 100); // 回传状态
HAL_UART_Receive_IT(&huart2, rxData, 1); // 重新启用接收
}
这段代码实现了:
- 通过中断方式接收蓝牙数据
- 收到'1'点亮LED,收到'0'熄灭LED
- 每次操作后通过蓝牙回传当前状态
4. 手机端APP配置
4.1 Android应用选择
推荐使用"蓝牙串口助手"类APP,我测试过以下几款:
- Serial Bluetooth Terminal:开源免费,支持自定义按钮
- BLE调试助手:界面简洁,响应速度快
- Arduino Bluetooth Controller:预设了LED控制界面
4.2 通信协议设计
为了确保可靠性,建议定义简单的通信协议:
- 手机发送:
- 开灯:0xA1
- 关灯:0xA0
- 查询状态:0xB1
- 设备回复:
- 当前状态:0xC1(开)或0xC0(关)
实际测试发现,直接用ASCII字符(如'1'/'0')更简单,兼容性更好。如果后续要扩展多路控制,再考虑用二进制协议。
5. 调试与优化技巧
5.1 常见问题排查
-
蓝牙无法连接:
- 检查模块是否进入配对模式(快闪)
- 确认手机没有连接过该模块的旧版本(删除已配对设备)
- 测量模块供电电压是否稳定(3.3V±0.2V)
-
数据收发异常:
- 用逻辑分析仪抓取USART信号
- 确认双方波特率一致(建议先用9600bps)
- 在TX线上加10K上拉电阻增强信号
-
LED无反应:
- 用万用表测量PB12引脚电压
- 检查LED极性是否接反
- 在代码中添加调试输出
5.2 功耗优化方案
如果考虑电池供电,可以:
- 配置蓝牙模块为低功耗模式(AT+SLEEP=1)
- 将STM32设置为STOP模式,通过蓝牙唤醒
- 在HAL_UART_RxCpltCallback中处理完立即进入低功耗
实测电流:
- 常亮模式:12mA
- 低功耗模式:0.8mA(LED灭+蓝牙睡眠)
6. 功能扩展思路
6.1 多路PWM调光
修改代码支持PWM调光:
c复制// 在TIM3初始化后添加
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
// 在回调函数中处理
if(rxData[0] >= '0' && rxData[0] <= '9') {
uint16_t duty = (rxData[0] - '0') * 10;
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
}
6.2 状态同步功能
增加EEPROM存储状态,上电时恢复上次设置:
c复制// 在初始化时读取
HAL_I2C_Mem_Read(&hi2c1, 0xA0, 0x00, I2C_MEMADD_SIZE_8BIT, &ledState, 1, 100);
// 在状态改变时写入
HAL_I2C_Mem_Write(&hi2c1, 0xA0, 0x00, I2C_MEMADD_SIZE_8BIT, &ledState, 1, 100);
6.3 加入OTA升级
通过蓝牙传输固件实现无线升级:
- 将Flash分为两个区(bootloader+app)
- 手机端发送HEX文件分包
- bootloader校验并写入新固件
这个方案我实际测试时发现需要至少留出64KB Flash空间,适合STM32F103C8T6(64KB Flash)以上的型号。