嵌入式Linux下蓝牙BLE驱动开发:实现物联网设备的无线数据交互
在物联网浪潮中,蓝牙低功耗(BLE)凭借其极低的功耗和便捷的连接方式,成为传感器、穿戴设备、智能家居的首选无线协议。在嵌入式Linux平台上,BlueZ是官方蓝牙协议栈,它提供了从HCI层到GATT层的完整API。本文以树莓派4B为例,展示如何用C语言开发一个BLE外设驱动,实现物联网设备的无线数据交互。
BlueZ协议栈概览
BlueZ是Linux内核的蓝牙子系统,包含核心驱动、L2CAP、SMP、ATT/GATT等协议层。用户空间通过D-Bus接口或Socket与内核交互。对于BLE开发,最常用的工具是bluetoothctl(交互式控制)和gatttool(GATT操作)。但若要集成到产品中,则需要直接调用BlueZ的D-Bus API或使用libbluetooth库。
开发环境准备
在树莓派上安装依赖:
sudo apt install bluez bluez-tools libbluetooth-dev
确认蓝牙适配器正常工作:
hciconfig -a
# 若hci0未开启,执行
sudo hciconfig hci0 up
编写BLE外设(Peripheral)
以下代码创建一个BLE GATT服务器,广播一个自定义服务,包含一个可读写的特征值。使用BlueZ的D-Bus API(通过GLib)。
#include <glib.h>
#include <gio/gio.h>
GDBusProxy *adapter, *advertising, *application;
const char *service_uuid = "0000180f-0000-1000-8000-00805f9b34fb";
const char *char_uuid = "00002a19-0000-1000-8000-00805f9b34fb";
static void on_characteristic_read(GDBusProxy *proxy, GVariant *value) {
// 返回电池电量(示例固定值80%)
guchar level = 80;
GVariant *new_val = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &level, 1, 1);
g_dbus_proxy_call_sync(proxy, "WriteValue", g_variant_new_tuple(NULL, 0), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
}
int main() {
GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
// 获取适配器对象
adapter = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
"org.bluez", "/org/bluez/hci0", "org.bluez.Adapter1", NULL, NULL);
// 设置可发现
g_dbus_proxy_call_sync(adapter, "SetDiscoveryFilter", g_variant_new("(a{sv})", NULL), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
// 创建GATT应用...
// 实际代码较长,此处省略详细注册过程
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
return 0;
}
实际开发中,推荐使用libsimple-bluez或gattlib等封装库简化D-Bus调用。对于快速原型,也可用Python的bluepy或pygatt。
编写BLE中央设备(Central)
扫描并连接外设,读取特征值:
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int scan_and_connect() {
int dev_id = hci_get_route(NULL);
int sock = hci_open_dev(dev_id);
if (sock < 0) return -1;
inquiry_info *info = malloc(255 * sizeof(inquiry_info));
int num = hci_inquiry(dev_id, 8, 255, NULL, &info, IREQ_CACHE_FLUSH);
for (int i = 0; i < num; i++) {
char addr[18];
ba2str(&info[i].bdaddr, addr);
printf("Found device: %s\n", addr);
}
free(info);
close(sock);
return 0;
}
实际应用要点
权限:运行BLE程序需要cap_net_admin或root权限,建议通过setcap cap_net_admin+eip ./app授权。
UUID:自定义服务/特征需使用128位UUID,标准服务使用16位UUID。
MTU:BLE 4.2及以上支持MTU扩展,协商更大的MTU可提升吞吐量。
连接间隔:根据功耗和实时性需求调整连接间隔(7.5ms~4s)。
白名单:生产环境中使用白名单过滤连接,防止非法设备接入。
写在最后
在嵌入式Linux上开发BLE驱动,本质是调用BlueZ提供的D-Bus接口或Socket API,实现GATT服务器的注册与客户端的数据交互。掌握hci_*、g_dbus_proxy_call等核心函数后,即可将传感器数据通过BLE广播出去,或被手机App读取。当你的物联网设备需要“低功耗、短距离、免配对”的无线链路时,BLE + BlueZ是最成熟的开源选择。从树莓派到工业ARM板,这套方案可以无缝迁移。





