Rv1126b与手机(SPP蓝牙串口APP)蓝牙通信流程

本文将详细介绍在 RV1126B 开发板上,使用 BlueZ 5.77 协议栈,通过 SPP(Serial Port Profile)与手机蓝牙串口 APP 进行通信的完整流程。

SPP 是经典蓝牙(BR/EDR)中一种非常实用的协议,它能在蓝牙设备间建立一个"虚拟串口",让数据传输变得像操作物理串口一样简单。这使得它非常适合嵌入式设备与手机等上位机进行数据交换。


1. 核心概念与准备工作

1.1 核心概念

1.1.1 在开始之前,需要先了解几个关键概念:

  • BlueZ :Linux 官方的开源蓝牙协议栈,RV1126B 上的蓝牙功能完全依赖它。bluez5_utils 是 Buildroot 中 BlueZ 5.x 版本的软件包名。

  • SPP (Serial Port Profile):蓝牙串口协议,它定义了设备间如何模拟串口进行通信。

  • RFCOMM:这是 SPP 使用的核心传输协议,它在 L2CAP 之上提供了一个简单的、基于通道的数据流,用于模拟 RS-232 串口。

  • SDP (Service Discovery Protocol):服务发现协议。服务端(RV1126B)通过 SDP 对外广播自己支持哪些服务(比如 SPP),客户端(手机)通过 SDP 来发现这些服务并获取连接所需的信息(如 RFCOMM 通道号)。

  • SPP(Serial Port Profile) 是经典蓝牙(BR/EDR)的"串口模拟"协议,由两部分拼成:

    组成 承载 作用
    RFCOMM L2CAP,PSM = 0x0003 建立带流控的可靠数据通道
    SDP L2CAP,PSM = 0x0001 登记"我在哪个 RFCOMM channel 提供串口服务",供对端查询

    关键标识:

    名称
    SPP 服务 UUID 00001101-0000-1000-8000-00805F9B34FB(短 UUID 0x1101
    RFCOMM PSM 0x0003
    SDP PSM 0x0001
    Public Browse Root 0x1002

    两个必须先纠正的认知:

    1. SPP 属于经典蓝牙,不是 BLE。 nRF Connect 这类 BLE 工具连不上 SPP,必须用支持 BR/EDR 串口的 APP。
    2. RFCOMM 上没有真正的波特率。 空口速率由 BR/EDR 物理层和 L2CAP/RFCOMM 参数决定;RPN 里协商的 9600/115200 只是给内核 TTY 层看的"礼貌参数",让 termios 表现得像真串口。数据乱码永远不是波特率问题,而是编码/分包问题。

    还有一个 BlueZ 5 的关键事实bluetoothd 不提供任何 SPP 的 D-Bus 接口org.bluez.Serial 早已移除)。它只负责 SDP 记录管理和配对鉴权,SPP 通道本身必须你自己在应用层实现

1.2 环境准备

确保你的 RV1126B 系统已包含 BlueZ 工具集,主要包括 bluetoothd(后台服务)和 bluetoothctl(管理工具)。你可以使用以下命令检查:

bash 复制代码
hciconfig -a   # 查看蓝牙设备状态
bluetoothctl -v # 查看 BlueZ 版本

如果命令未找到,需要在 Buildroot 中确认 bluez5_utils 包已被选中并编译。


2. 服务端配置:让 RV1126B 成为 SPP 服务端

要让 RV1126B 作为服务端被手机连接,需要完成两个核心步骤:注册 SPP 服务启动 RFCOMM 监听

2.1 使用 sdptool 注册 SPP 服务

首先,需要使用 sdptool 命令向本地的 SDP 数据库中添加一个 SPP 服务记录。这一步是告诉手机:"我支持 SPP 串口服务,请通过这个通道来找我"。

bash 复制代码
# 注册 SPP 服务,使用默认的 RFCOMM 通道 1
sdptool add SP

# 或者可以指定一个通道,例如通道 3
sdptool add --channel=3 SP

关键点sdptool add SP 必须在手机尝试连接 之前 执行。如果连接后执行,手机已经完成服务查询,将无法发现该服务。

可能遇到的问题与解决

  • 如果提示 Failed to connect to SDP server,通常是因为 bluetoothd 未以兼容模式运行。你需要先停止现有服务,然后手动启动:

    bash 复制代码
    killall bluetoothd
    /usr/libexec/bluetooth/bluetoothd -C -n -d &

    这里的 -C 参数用于启用对旧版命令行工具的兼容性。

2.2 使用 rfcomm 监听连接

服务注册成功后,就可以使用 rfcomm 命令来监听来自手机的连接请求了。

bash 复制代码
# 监听 /dev/rfcomm0 设备,使用通道 1(需与 sdptool 注册的通道一致)
rfcomm listen /dev/rfcomm0 1

执行后,终端会显示 Waiting for connection on channel 1,此时 RV1126B 已准备好接受连接。

数据交互

当手机连接成功后,/dev/rfcomm0 这个虚拟串口设备就会被创建。之后,你可以像操作普通串口一样对它进行读写。

  • 读取手机发来的数据:cat /dev/rfcomm0
  • 向手机发送数据:echo "Hello from RV1126B" > /dev/rfcomm0

3. 进阶:编写 C 语言服务端程序

虽然命令行工具可以快速测试,但在实际项目中,通常需要编写一个程序来实现更复杂的逻辑。以下是一个使用 C 语言实现的 RFCOMM 服务端框架。

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>

int main(int argc, char **argv) {
    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
    char buf[1024] = { 0 };
    int s, client, bytes_read;
    socklen_t opt = sizeof(rem_addr);

    // 1. 创建 RFCOMM socket
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

    // 2. 绑定 socket 到本地蓝牙地址和通道 1
    loc_addr.rc_family = AF_BLUETOOTH;
    bacpy(&loc_addr.rc_bdaddr, BDADDR_ANY);
    loc_addr.rc_channel = (uint8_t) 1;
    bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));

    // 3. 监听连接
    listen(s, 1);

    // 4. 接受来自手机 APP 的客户端连接
    client = accept(s, (struct sockaddr *)&rem_addr, &opt);

    // 5. 数据收发循环
    while (1) {
        memset(buf, 0, sizeof(buf));
        bytes_read = read(client, buf, sizeof(buf));
        if (bytes_read > 0) {
            printf("Received: %s\n", buf);
            // 回复手机
            char reply[] = "ACK from RV1126B\n";
            write(client, reply, sizeof(reply));
        } else {
            break;
        }
    }

    close(client);
    close(s);
    return 0;
}

编译与运行

在 RV1126B 上使用交叉编译工具链编译:

bash 复制代码
aarch64-buildroot-linux-gnu-gcc -o bt_server bt_server.c -lbluetooth

然后运行:

bash 复制代码
./bt_server

注意 :此代码示例未包含 SDP 服务注册。在实际部署时,仍需在程序启动前或程序内部通过 system("sdptool add SP") 等方式完成注册。


4. 手机端连接与数据通信

  1. 打开手机蓝牙,并搜索附近设备。
  2. 找到并配对 名为 BlueZ 5.77(或你自定义的名称)的设备。
  3. 打开手机上的 SPP 蓝牙串口 APP(如 "Serial Bluetooth Terminal")。
  4. 在 APP 中扫描并连接到已配对的 BlueZ 5.77 设备。
  5. 连接建立后,APP 界面会类似一个串口终端。此时即可在 APP 中输入文字并发送,RV1126B 的服务端程序(或 rfcomm 命令行)会收到数据并显示。

5. 常见问题与故障排查

问题现象 可能原因与解决方案
hciconfigsdptool 命令找不到 Buildroot 中未包含或未正确安装 bluez5-utils 包。请检查 Buildroot 配置并重新编译。
sdptool add SP 失败 bluetoothd 服务未以兼容模式运行。尝试使用 bluetoothd -C -n -d & 重启服务。
手机能配对,但无法连接 SPP 服务 1. SDP 服务未注册 :确保 sdptool add SP 在手机连接之前 已执行。 2. RFCOMM 未监听 :确保 rfcomm listen 或你的服务端程序正在运行。 3. 通道不匹配 :检查 sdptool 注册的通道与 rfcomm 监听的通道是否一致。
连接后立即断开 服务端程序可能在 accept() 后立即退出。确保服务端程序在 accept() 之后进入一个持续运行的循环。
数据传输失败或乱码 检查服务端和手机 APP 的串口参数(如波特率)是否匹配。虽然 SPP 通常会自动协商,但某些 APP 可能需要手动设置。

6. 总结

通过以上步骤,你可以在 RV1126B 上成功建立一个基于 SPP 的蓝牙串口服务,并与手机 APP 进行通信。

整个流程的核心在于:

  1. 注册服务 :使用 sdptool 让手机能够发现 RV1126B 的 SPP 服务。
  2. 建立监听 :使用 rfcomm 或编写 C 程序,在指定通道上等待连接。
  3. 数据交互 :连接建立后,通过虚拟串口 /dev/rfcomm0 或 socket 进行双向数据传输。
相关推荐
虚无的纽扣1 小时前
【Linux】进程第二课:进程优先级和环境变量
linux·运维·服务器
maosheng11461 小时前
【无标题】linux中企业容易考的的小知识点1(rhcsa)
linux·运维·服务器
牢姐与蒯1 小时前
Linux进程(九).自定义shell——深度理解命令行和shell
linux·运维·服务器
天道jimmy1 小时前
VulnHub 系列:View2aKill,1
linux·运维·服务器
mengge.cloud2 小时前
0909华为云网络类服务实践小白实验教程
linux·运维·服务器·网络·华为云·php
小诗懂技术2 小时前
从零手写一个 C 语言 HTTP 商品查询服务器:全链路技术实践
linux·服务器·网络
Escalating_xu2 小时前
【Linux mmap 文件映射】从虚拟地址到页缓存:读写文件、匿名映射与极简 malloc
linux·缓存
Zixhy2 小时前
Boost 库实现异步高并发服务器
linux·服务器·c++
阿明62 小时前
基础编辑工具使用【Linux】
linux·运维·服务器