You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux系统下使用C程序实现与BLE设备的交互?

基于BlueZ的BLE C代码交互指南(心率监测仪场景)

BlueZ是Linux官方默认的蓝牙协议栈,你可以通过bluetoothctl正常读取心率数据,说明系统BlueZ服务运行状态正常。C代码实现设备交互当前有两种可选实现路径:

  • 用BlueZ的DBus API(现在官方推荐的方式,不需要链接BlueZ内部私有库,兼容所有5.40以上版本的BlueZ)
  • 用旧版hci、gattlib类第三方库(不推荐,新版本BlueZ已经弃用绝大多数hci相关接口,兼容性极差)

前置依赖确认

  • 编译依赖:提前安装libdbus-1-dev、glib2.0-dev包,示例代码采用GDBus(GLib封装的DBus绑定)实现
  • 已知参数:提前通过bluetoothctl获取目标设备MAC地址,心率服务标准UUID为0000180d-0000-1000-8000-00805f9b34fb,心率测量特征值标准UUID为00002a37-0000-1000-8000-00805f9b34fb,绝大多数合规心率监测设备都采用蓝牙联盟规定的通用UUID
  • 运行要求:BlueZ版本≥5.40,bluetoothd系统服务正常启动

核心操作流程

流程和你用bluetoothctl操作的逻辑完全对应:

  1. 扫描设备(你已经实现该功能,扫描完成后可以拿到目标设备的DBus对象路径,格式一般为/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX,其中XX为MAC地址的十六进制值,冒号替换为下划线)
  2. 发起设备连接,等待BlueZ自动完成GATT服务发现
  3. 遍历GATT特征列表,匹配到心率测量对应的特征对象
  4. 开启特征值通知,订阅属性变更信号,设备上报心率时会触发回调
  5. 按协议解析特征值拿到心率数据

关键代码片段示例

设备连接代码

// 入参conn为已初始化的GDBusConnection对象,obj_path为目标设备的DBus对象路径
GError *error = NULL;
g_dbus_connection_call_sync(
    conn,
    "org.bluez",
    obj_path,
    "org.bluez.Device1",
    "Connect",
    NULL,
    NULL,
    G_DBUS_CALL_FLAGS_NONE,
    -1,
    NULL,
    &error
);
if (error != NULL) {
    g_printerr("连接失败: %s\n", error->message);
    g_error_free(error);
    return 1;
}

开启特征通知代码

// 入参char_path为心率测量特征的DBus对象路径
g_dbus_connection_call_sync(
    conn,
    "org.bluez",
    char_path,
    "org.bluez.GattCharacteristic1",
    "StartNotify",
    NULL,
    NULL,
    G_DBUS_CALL_FLAGS_NONE,
    -1,
    NULL,
    &error
);
// 订阅特征值变更信号
g_dbus_connection_signal_subscribe(
    conn,
    "org.bluez",
    "org.freedesktop.DBus.Properties",
    "PropertiesChanged",
    char_path,
    NULL,
    G_DBUS_SIGNAL_FLAGS_NONE,
    on_heart_rate_update, // 自定义回调函数,处理收到的心率数据
    NULL,
    NULL
);

心率数据回调函数

static void on_heart_rate_update(GDBusConnection *connection,
                                 const gchar *sender_name,
                                 const gchar *object_path,
                                 const gchar *interface_name,
                                 const gchar *signal_name,
                                 GVariant *parameters,
                                 gpointer user_data) {
    const gchar *iface;
    GVariant *props;
    g_variant_get(parameters, "(&s@a{sv}as)", &iface, &props, NULL);
    if (g_strcmp0(iface, "org.bluez.GattCharacteristic1") != 0) {
        g_variant_unref(props);
        return;
    }
    GVariant *value = g_variant_lookup_value(props, "Value", G_VARIANT_TYPE_BYTESTRING);
    if (value != NULL) {
        gsize len;
        const guint8 *data = g_variant_get_data(value, &len);
        if (len >= 2) {
            guint8 flags = data[0];
            // 标志位第0位为1时心率是16位值,否则为8位值
            guint16 heart_rate = (flags & 0x01) ? GUINT16_FROM_LE(*(guint16*)(data+1)) : data[1];
            g_print("当前心率: %d bpm\n", heart_rate);
        }
        g_variant_unref(value);
    }
    g_variant_unref(props);
}

BlueZ API参考入口

所有接口定义的官方文档都在你本地系统的BlueZ安装目录下,路径为/usr/share/doc/bluez/api/:

  • device-api.txt:设备连接、配对、属性查询相关的接口定义
  • gatt-api.txt:GATT服务、特征、描述符的读写、通知相关的接口定义
    所有方法、参数、信号的规则都有明确说明。

注意事项

  • 程序运行需要root权限,或者给编译后的二进制文件加cap_net_raw,cap_net_admin capabilities权限
  • 连接设备前确保没有其他进程(比如bluetoothctl)占用目标设备
  • 如果需要主动读取特征值,调用org.bluez.GattCharacteristic1.ReadValue方法,参数传入空字典即可

内容的提问来源于stack exchange,提问作者Maneesh N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 11:36:04