1. 项目概述
这个项目主要解决的是如何通过手机APP与HC-05蓝牙模块建立通信,实现STM32单片机数据的双向传输。作为一名嵌入式开发工程师,我经常需要在项目中实现无线通信功能,而蓝牙方案因其成本低、功耗适中、开发便捷等优势,成为许多物联网项目的首选。
HC-05作为经典的蓝牙2.0模块,虽然不支持BLE低功耗协议,但在需要稳定数据传输的场景下表现优异。它的典型工作距离在10米左右,传输速率可达2.1Mbps,完全能满足大多数嵌入式项目的需求。通过这个教程,你将学会如何从零开始构建一个完整的蓝牙通信系统。
2. 硬件准备与连接
2.1 所需硬件清单
- STM32开发板(推荐F103C8T6最小系统板)
- HC-05蓝牙模块(注意区分主从模式)
- USB转TTL模块(用于蓝牙模块配置)
- 杜邦线若干
- 安卓手机(用于测试APP)
2.2 硬件连接示意图
code复制STM32 USART1 <--> HC-05
PA9(TX) -> RXD
PA10(RX) -> TXD
3.3V -> VCC
GND -> GND
注意:HC-05的工作电压是3.3V,直接连接5V会烧毁模块。如果使用5V单片机,需要在RX线上添加电平转换电路。
2.3 蓝牙模块配置
在接入STM32前,建议先用USB转TTL工具对HC-05进行基础配置:
-
连接USB转TTL:
- TXD -> HC-05 RXD
- RXD -> HC-05 TXD
- GND -> GND
-
打开串口助手(波特率38400)
-
发送AT指令:
bash复制AT+NAME=MyBTModule # 设置模块名称 AT+PSWD=1234 # 设置配对密码 AT+UART=9600,0,0 # 设置通信波特率
3. STM32固件开发
3.1 开发环境搭建
推荐使用STM32CubeIDE进行开发:
- 安装STM32CubeMX
- 生成USART1初始化代码(异步模式)
- 配置参数:
- 波特率:9600
- 字长:8位
- 停止位:1
- 无校验
3.2 关键代码实现
c复制// 串口接收中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART1) {
// 处理接收到的数据
processBluetoothData(rxBuffer);
// 重新启动接收
HAL_UART_Receive_IT(&huart1, &rxBuffer, 1);
}
}
// 数据发送函数
void sendBTData(uint8_t *data, uint16_t len) {
HAL_UART_Transmit(&huart1, data, len, 100);
}
3.3 数据协议设计
建议定义简单的帧格式:
code复制[起始符][长度][数据][校验和]
0xAA Len Data SUM
示例校验和计算:
c复制uint8_t calcChecksum(uint8_t *data, uint8_t len) {
uint8_t sum = 0;
for(int i=0; i<len; i++) {
sum += data[i];
}
return (0xFF - sum);
}
4. 安卓APP开发
4.1 开发环境准备
- Android Studio 最新版
- 最低API Level 19(Android 4.4)
- 添加蓝牙权限:
xml复制<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
4.2 蓝牙核心功能实现
4.2.1 设备发现
java复制private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getName() != null && device.getName().equals("MyBTModule")) {
mDevice = device;
connectDevice();
}
}
}
};
4.2.2 数据接收线程
java复制private class ConnectedThread extends Thread {
private final InputStream mmInStream;
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String data = new String(buffer, 0, bytes);
runOnUiThread(() -> {
textView.append(data + "\n");
});
} catch (IOException e) {
break;
}
}
}
}
4.3 用户界面设计
关键组件:
- 设备列表ListView
- 连接状态指示灯
- 数据接收TextView
- 指令发送EditText + Button
布局示例:
xml复制<LinearLayout
android:orientation="vertical">
<Button
android:id="@+id/scanBtn"
android:text="扫描设备"/>
<TextView
android:id="@+id/statusText"
android:text="未连接"/>
<TextView
android:id="@+id/receivedData"
android:layout_height="200dp"/>
<EditText
android:id="@+id/commandInput"
android:hint="输入指令"/>
<Button
android:id="@+id/sendBtn"
android:text="发送"/>
</LinearLayout>
5. 通信测试与调试
5.1 测试流程
- 烧录STM32程序
- 上电后确认蓝牙模块LED闪烁频率(快闪表示可配对)
- 手机APP扫描并连接"MyBTModule"
- 测试数据收发:
- APP发送"AT+TEST"指令
- STM32应回复"TEST_OK"
5.2 常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法发现设备 | 蓝牙未开启/模块未进入配对模式 | 检查模块LED状态,长按KEY引脚进入AT模式 |
| 连接后立即断开 | 波特率不匹配 | 确认STM32与HC-05波特率一致 |
| 数据乱码 | 电平不兼容/接线错误 | 检查TX/RX交叉连接,确认电压匹配 |
| 发送无响应 | 未添加换行符 | 在APP发送指令末尾添加"\r\n" |
5.3 性能优化建议
- 增加数据缓冲队列,避免高频发送导致丢失
- 实现心跳包机制,检测连接状态
- 使用二进制协议替代字符串,提高传输效率
- 添加数据重传机制,确保关键指令可靠送达
6. 项目扩展方向
在实际项目中,这个基础框架可以进一步扩展:
- 多模块组网:配置多个HC-05组成星型网络
- 数据加密:在应用层实现AES加密传输
- OTA升级:通过蓝牙实现固件无线更新
- 低功耗优化:调整模块工作模式延长续航
我最近在一个智能家居项目中应用了这套方案,实现了通过手机APP控制多个STM32节点的功能。实测在室内环境下,穿墙后仍能保持稳定通信,平均延迟在100ms以内,完全满足控制类应用的需求。
