一、问题描述
在 Ubuntu 20.04 系统中连接 HC-05 蓝牙串口模块时,Windows 系统可以正常连接,但 Ubuntu 系统中会出现蓝牙可以搜索到、PIN 码输入正确、设备可以配对成功,但是连接后立即断开的情况。
具体表现包括:
- 可以搜索到 HC-05;
- PIN 码
1234输入正确; - 配对成功;
bluetoothctl connect连接失败;rfcomm bind无法生成/dev/rfcomm0。
扫描设备时,可以看到 HC-05:
bash
Device 00:55:44:5D:3E:1B HC-05
输入 PIN 码
1234后,配对成功:
text
Pairing successful
查看设备信息:
bash
bluetoothctl info 00:55:44:5D:3E:1B
设备状态如下:
text
Name: HC-05
Paired: yes
Trusted: yes
Blocked: no
Connected: no
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)
这说明 HC-05 已经成功配对,并且提供蓝牙串口服务。
但是直接连接失败:
bash
connect 00:55:44:5D:3E:1B
报错如下:
text
Failed to connect: org.bluez.Error.Failed
继续尝试绑定蓝牙串口:
bash
sudo rfcomm bind /dev/rfcomm0 00:55:44:5D:3E:1B 1
报错如下:
text
RFCOMM TTY support not available
最终确认,该问题不是 PIN 错误,也不是 HC-05 配对失败,而是当前内核没有启用 RFCOMM TTY 支持,导致系统无法生成
/dev/rfcomm0。
二、原因分析
检查当前内核配置:
bash
sudo modprobe configs
zcat /proc/config.gz | grep -E "CONFIG_BT_RFCOMM|CONFIG_BT_RFCOMM_TTY"
输出结果:
text
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set
其中:
text
CONFIG_BT_RFCOMM=y
表示系统支持 RFCOMM 蓝牙通信协议。
text
# CONFIG_BT_RFCOMM_TTY is not set
表示系统不支持将 RFCOMM 蓝牙连接映射成 Linux TTY 串口设备。
也就是说,当前系统可以使用 RFCOMM 协议通信,但不能创建:
text
/dev/rfcomm0
因此,传统蓝牙串口绑定方式不可用:
bash
sudo rfcomm bind 0 00:55:44:5D:3E:1B 1
解决思路是绕过
/dev/rfcomm0,直接使用 Python 通过 RFCOMM Socket 与 HC-05 通信。
本文将该方法称为:
RFCOMM Socket 直连解析法
三、具体解决步骤
1. 进入 bluetoothctl
执行:
bash
bluetoothctl
依次输入:
text
power on
agent on
default-agent
scan on
扫描到 HC-05 后,会看到类似输出:
text
Device 00:55:44:5D:3E:1B HC-05
本文中的 HC-05 蓝牙地址为:
text
00:55:44:5D:3E:1B
实际使用时,需要将该地址替换成自己的 HC-05 地址。
2. 配对 HC-05
在
bluetoothctl中执行:
text
pair 00:55:44:5D:3E:1B
系统提示输入 PIN 码时,输入:
text
1234
配对成功后会显示:
text
Pairing successful
3. 将 HC-05 设置为信任设备
执行:
text
trust 00:55:44:5D:3E:1B
成功后会显示:
text
Changing 00:55:44:5D:3E:1B trust succeeded
退出
bluetoothctl:
text
quit
4. 确认 HC-05 状态
执行:
bash
bluetoothctl info 00:55:44:5D:3E:1B
确认状态中包含以下内容:
text
Paired: yes
Trusted: yes
Blocked: no
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)
其中:
text
UUID: Serial Port
表示 HC-05 提供蓝牙串口服务。
5. 检查系统 RFCOMM 支持状态
执行:
bash
sudo modprobe configs
zcat /proc/config.gz | grep -E "CONFIG_BT_RFCOMM|CONFIG_BT_RFCOMM_TTY"
当前系统输出为:
text
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set
这说明系统支持 RFCOMM 协议,但不能创建
/dev/rfcomm0。
6. 查询 HC-05 的 RFCOMM 通道
执行:
bash
sdptool browse 00:55:44:5D:3E:1B | grep -i -A 8 "Serial Port"
输出结果:
text
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
说明 HC-05 的 RFCOMM 通道是:
text
Channel: 1
后续 Python 程序中需要设置:
python
channel = 1
7. 清理蓝牙连接状态
执行:
bash
bluetoothctl
进入后执行:
text
scan off
disconnect 00:55:44:5D:3E:1B
quit
然后重启蓝牙服务:
bash
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
sudo hciconfig hci0 reset
检查是否还有残留连接:
bash
hcitool con
正常情况下输出:
text
Connections:
表示当前没有残留连接。
8. 创建 HC-05 数据接收和解析程序
新建 Python 文件:
bash
gedit hc05_parse.py
写入以下完整代码:
python
import socket
import time
import re
addr = "00:55:44:5D:3E:1B"
channel = 1
def parse_data(text):
"""
解析 HC-05 发来的数据。
示例数据:
hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#
"""
result = {}
# 如果数据前面存在乱码,则从第一个有效字段开始截取
match = re.search(r"(hear|spo2|temp|step|time):", text)
if match:
text = text[match.start():]
# 提取 key:value# 格式的数据
items = re.findall(r"([a-zA-Z_]+):([^#,]+)#", text)
for key, value in items:
result[key] = value
return result
while True:
sock = socket.socket(
socket.AF_BLUETOOTH,
socket.SOCK_STREAM,
socket.BTPROTO_RFCOMM
)
sock.settimeout(10)
try:
print("Connecting HC-05...")
sock.connect((addr, channel))
print("Connected")
while True:
data = sock.recv(1024)
if not data:
print("Disconnected")
break
text = data.decode("utf-8", errors="ignore").strip()
print("Raw:", text)
parsed = parse_data(text)
if parsed:
hear = parsed.get("hear")
spo2 = parsed.get("spo2")
temp = parsed.get("temp")
step = parsed.get("step")
time_value = parsed.get("time")
print("Parsed:")
print(" Heart:", hear)
print(" SpO2:", spo2)
print(" Temp:", temp)
print(" Step:", step)
print(" Time:", time_value)
print("-" * 30)
else:
print("No valid data parsed")
except Exception as e:
print("Error:", e)
print("Reconnect after 3 seconds...")
time.sleep(3)
finally:
sock.close()
保存并退出:
text
Ctrl + O
Enter
Ctrl + X
9. 运行程序
执行:
bash
python3 hc05_parse.py
成功连接后会显示:
text
Connecting HC-05...
Connected
接收到数据后会显示类似内容:
text
Raw: hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#
Parsed:
Heart: 0
SpO2: 0
Temp: 22.3
Step: 8
Time: 00:00:00
------------------------------
实际测试中收到的数据为:
text
Received: b'c.\x1c"hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#\r\n'
虽然数据前面存在无效字符,但程序会自动从
hear:、spo2:、temp:、step:或time:开始截取,因此可以正常解析后面的有效数据。
四、为什么 RFCOMM Socket 直连解析法可以使用
该方法可以使用的根本原因是:当前系统虽然不能生成
/dev/rfcomm0,但仍然支持 RFCOMM 协议。
系统内核配置为:
text
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set
其中:
text
CONFIG_BT_RFCOMM=y
表示 RFCOMM 蓝牙通信协议可用。
text
# CONFIG_BT_RFCOMM_TTY is not set
表示不能把 RFCOMM 映射成 Linux TTY 串口设备,也就是不能生成:
text
/dev/rfcomm0
传统方式依赖
/dev/rfcomm0,例如:
bash
sudo rfcomm bind 0 00:55:44:5D:3E:1B 1
因此会失败。
而 RFCOMM Socket 直连解析法不依赖/dev/rfcomm0,它直接通过 Python 创建蓝牙 RFCOMM Socket:
python
socket.socket(
socket.AF_BLUETOOTH,
socket.SOCK_STREAM,
socket.BTPROTO_RFCOMM
)
然后直接连接 HC-05:
python
sock.connect((addr, channel))
所以只要系统支持:
text
CONFIG_BT_RFCOMM=y
并且 HC-05 提供 Serial Port 服务,就可以正常通信。
五、解决中可能遇到的问题
1. bluetoothctl connect 失败
现象:
text
Failed to connect: org.bluez.Error.Failed
原因说明:
HC-05 是蓝牙串口模块,不一定需要通过bluetoothctl connect保持连接。只要已经完成配对和信任,Python 程序可以自己建立 RFCOMM 连接。
处理方法:
后续使用时不需要执行:
bash
bluetoothctl connect 00:55:44:5D:3E:1B
直接运行 Python 程序即可。
2. 无法生成 /dev/rfcomm0
现象:
text
RFCOMM TTY support not available
原因说明:
当前内核没有启用:
text
CONFIG_BT_RFCOMM_TTY
检查结果为:
text
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set
因此不能使用:
bash
sudo rfcomm bind 0 00:55:44:5D:3E:1B 1
处理方法:
使用 RFCOMM Socket 直连解析法,不依赖/dev/rfcomm0。
3. Python 连接时报 Device or resource busy
现象:
text
OSError: [Errno 16] Device or resource busy
原因说明:
蓝牙设备或 HC-05 当前可能处于占用状态。
处理方法:
bash
bluetoothctl
执行:
text
scan off
disconnect 00:55:44:5D:3E:1B
quit
然后重启蓝牙:
bash
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
sudo hciconfig hci0 reset
检查残留连接:
bash
hcitool con
确认只显示:
text
Connections:
然后重新运行:
bash
sudo python3 hc05_parse.py
4. 接收到的数据前面有乱码
现象:
text
b'c.\x1c"hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#\r\n'
原因说明:
蓝牙串口接收时可能会读到上一帧残留数据或非完整帧数据。
处理方法:
程序中从有效字段开始截取:
python
match = re.search(r"(hear|spo2|temp|step|time):", text)
if match:
text = text[match.start():]
这样可以自动丢弃前面的无效字符。
5. HC-05 已配对但无法收到数据
可以检查 HC-05 是否仍然处于正确状态:
bash
bluetoothctl info 00:55:44:5D:3E:1B
正常状态应包含:
text
Paired: yes
Trusted: yes
Blocked: no
Connected: no
UUID: Serial Port
然后确认通道:
bash
sdptool browse 00:55:44:5D:3E:1B | grep -i -A 8 "Serial Port"
如果显示:
text
Channel: 1
程序中就应设置:
python
channel = 1
六、总结
本次问题并不是 PIN 错误,也不是 HC-05 无法配对,而是当前内核没有启用 RFCOMM TTY 支持。
传统蓝牙串口方式需要:
text
/dev/rfcomm0
但当前系统不支持创建该设备。
内核配置显示:
text
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set
因此最终采用 RFCOMM Socket 直连解析法。
该方法的优点是:
- 不需要
/dev/rfcomm0 - 不需要重新编译内核
- 可以直接连接 HC-05
- 可以直接接收并解析蓝牙串口数据
- 适合 Jetson / Orin 这类未启用 RFCOMM TTY 的系统
最终运行结果证明,Ubuntu 20.04 / Jetson Orin 可以正常接收 HC-05 发来的数据:
text
hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#
解析后可以得到:
text
Heart: 0
SpO2: 0
Temp: 22.3
Step: 8
Time: 00:00:00
至此,HC-05 蓝牙串口通信问题解决。