zephyr架构下Bluetooth advertising接口
目录
概述
1 函数接口
2 主要函数介绍
2.1 bt_le_adv_start函数
2.1.1 函数功能介绍
2.1.2 典型使用示例
2.1.3 广播间隔
2.1.4 注意事项
2.2 bt_le_adv_stop 函数
2.2.1 函数功能
2.2.2 使用方法介绍
2.2.3 实际应用示例
2.2.4 关键注意事项
2.2.5 常见问题解决
2.2.6 应用总结
2.3 bt_enable
2.3.1 函数功能
2.3.2 典型使用模式
2.3.3 关键处理流程
2.3.4 注意事项
2.3.5 初始化失败常见原因
2.3.6 实际应用示例
2.3.7 应用总结
2.4 bt_le_adv_update_data函数
2.4.1 函数功能
2.4.2 典型使用场景
2.4.3 关键特性
2.4.4 实现原理
2.4.5 注意事项
2.4.6 错误处理最佳实践
2.4.7 典型应用案例
2.4.8 应用总结
概述
本文主要介绍zephyr架构下Bluetooth advertising一些接口函数的功能和使用方法,这些函数是bluetooth的最重要的一些接口,掌握这些函数的用法是进行蓝牙功能开发的基础。
1 函数接口
基于zephyr OS架构下实现Bluetooth advertising功能其使用的函数接口有如下这些
函数名称 | 功能 | 说明 |
bt_le_adv_start | 实现广播功能 | BLE模块被使能后,启用该函数进行广播,可通过设置不同的参数,实现不同的广播方式 |
bt_enable | 使能BLE | 使能BLE的功能,该函数 |
bt_le_adv_stop | 停止广播 | 关闭广播功能,下次要重新广播时,需要调用bt_le_adv_start |
bt_le_adv_update_data | 更新广播数据 |
2 主要函数介绍
2.1 bt_le_adv_start函数
2.1.1 函数功能介绍
bt_le_adv_start
是蓝牙低功耗 (BLE) 协议栈中的一个关键 API 函数,用于启动设备的广播(Advertising)功能。这个函数允许 BLE 设备(Peripheral 角色)向周围设备广播自己的存在,并携带相关信息。bt_le_adv_start
是 BLE 设备广播功能的核心 API,合理配置广播参数和数据可以优化设备发现性、连接速度和功耗表现。开发者需要根据具体应用场景(如 Beacon、可连接外设等)选择合适的广播模式和数据结构。
1)功能概述
作用:启动 BLE 设备的广播功能
适用角色:Peripheral(外设)或 Broadcaster(广播者)
广播模式:可配置为可连接广播、不可连接广播、可扫描广播等
广播数据:可携带设备名称、服务 UUID、厂商数据等
2)函数原型:
int bt_le_adv_start(const struct bt_le_adv_param *param,const struct bt_data *ad,size_t ad_len,const struct bt_data *sd,size_t sd_len);
3)参数说明
参数 | 类型 | 说明 |
---|---|---|
param | bt_le_adv_param* | 广播参数配置(广播类型、间隔等) |
ad | bt_data* | 广播数据(Advertising Data) |
ad_len | size_t | 广播数据项数量 |
sd | bt_data* | 扫描响应数据(Scan Response Data) |
sd_len | size_t | 扫描响应数据项数量 |
4)广播参数配置(bt_le_adv_param)
struct bt_le_adv_param {uint8_t id; // 广播集 IDuint32_t options; // 广播选项(如 BT_LE_ADV_OPT_CONNECTABLE)uint16_t interval_min; // 最小广播间隔(单位:0.625ms)uint16_t interval_max; // 最大广播间隔(单位:0.625ms)uint8_t peer[6]; // 定向广播的目标地址(可选)
};
常用广播选项(options)
BT_LE_ADV_OPT_CONNECTABLE
- 可连接广播
BT_LE_ADV_OPT_USE_NAME
- 在广播中包含设备名称
BT_LE_ADV_OPT_SCANNABLE
- 允许扫描响应
BT_LE_ADV_OPT_ONE_TIME
- 仅广播一次
5)广播数据类型(bt_data)
struct bt_data {uint8_t type; // 数据类型(如 BT_DATA_NAME_COMPLETE)uint8_t data_len;const uint8_t *data;
};
2.1.2 典型使用示例
1)1. 基本可连接广播
static const struct bt_data ad[] = {BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};static const struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME,BT_GAP_ADV_FAST_INT_MIN_1,BT_GAP_ADV_FAST_INT_MAX_1,NULL
);bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), NULL, 0);
2)不可连接广播(Beacon 模式)
static const uint8_t beacon_data[] = {0x01, 0x02, 0x03, 0x04, // 厂商特定数据
};static const struct bt_data ad[] = {BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NONCONN_IND),BT_DATA(BT_DATA_MANUFACTURER_DATA, beacon_data, sizeof(beacon_data)),
};bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad), NULL, 0);
2.1.3 广播间隔
BLE 广播间隔以 0.625ms 为单位:
-
快速广播:20ms - 60ms(
BT_GAP_ADV_FAST_INT_MIN_1
= 32 = 20ms) -
慢速广播:100ms - 150ms(
BT_GAP_ADV_SLOW_INT_MIN
= 160 = 100ms)
返回值
-
0
:广播启动成功 -
负值:错误码(如
-EINVAL
参数错误,-ENOMEM
内存不足)
2.1.4 注意事项
广播数据总长度不能超过 31 字节
扫描响应数据也受 31 字节限制
广播间隔影响功耗和可发现性
某些广播模式(如定向广播)有额外限制
2.2 bt_le_adv_stop 函数
2.2.1 函数功能
bt_le_adv_stop
是蓝牙低功耗 (BLE) 协议栈中的一个关键 API 函数,用于停止正在进行的广播。它通常与 bt_le_adv_start
配对使用,用于控制 BLE 设备的广播生命周期。
1)核心功能
停止广播:立即终止当前正在进行的 BLE 广播
释放资源:释放与广播相关的协议栈资源
配合广播控制:通常用于动态广播管理场景
2)函数原型(基于 Zephyr BLE 协议栈)
int bt_le_adv_stop(void);
参数
-
无参数:直接停止当前活跃的广播
返回值
返回值 | 说明 |
---|---|
0 | 停止广播成功 |
-EALREADY | 当前没有活跃的广播 |
其他负值 | 其他错误(如协议栈错误) |
2.2.2 使用方法介绍
1) 基本启停控制
// 启动广播
bt_le_adv_start(...);// 一段时间后停止广播
bt_le_adv_stop();
2)条件性停止广播
if (need_to_stop_advertising) {int err = bt_le_adv_stop();if (err) {printk("Stop failed (err %d)\n", err);}
}
3) 广播模式切换
// 先停止当前广播
bt_le_adv_stop();// 更换参数后重新启动
bt_le_adv_start(new_params, ...);
2.2.3 实际应用示例
场景:温度传感器按需广播
void start_temp_advertising(void) {bt_le_adv_start(..., temp_ad_data, ...);
}void stop_advertising_when_connected(void) {// 当连接建立时自动停止广播// 或手动调用:bt_le_adv_stop();
}void on_button_press(void) {// 按钮按下时重新广播bt_le_adv_stop(); // 先确保停止start_temp_advertising();
}
2.2.4 关键注意事项
无广播时的调用
如果没有活跃的广播,调用会返回-EALREADY
(非致命错误)线程安全性
建议在协议栈线程(如 Zephyr 的 Bluetooth 线程)上下文中调用与连接的交互
如果设备已通过广播建立连接,广播会自动停止,此时调用会返回-EALREADY
低功耗场景
停止广播会显著降低功耗(广播是功耗主要来源之一)广播集支持
在支持多广播集的协议栈中(如 Zephyr 2.7+),可能需要指定广播集 ID
2.2.5 常见问题解决
Q1:停止广播后为什么设备仍可被扫描到?
A1:可能是其他广播实例仍在运行,或广播停止有延迟(检查返回值)
Q2:如何确保广播完全停止?
A2:
do {err = bt_le_adv_stop();
} while (err == 0); // 直到返回-EALREADY
Q3:停止广播会影响已建立的连接吗?
A3:不会,只影响广播行为,不影响现有连接
2.2.6 应用总结
bt_le_adv_stop
是 BLE 设备广播管理的核心控制点,合理使用可以实现:
精确的广播生命周期控制
动态广播策略切换
有效的功耗管理
在需要频繁切换广播模式或优化功耗的场景中,正确使用该API至关重要。
2.3 bt_enable
2.3.1 函数功能
bt_enable
是蓝牙协议栈中的核心初始化函数,用于启用和初始化蓝牙控制器及协议栈。它是任何蓝牙应用程序的第一个关键调用,为后续所有蓝牙操作建立基础环境。
函数原型(基于Zephyr等常见协议栈)
int bt_enable(bt_ready_cb_t cb);
参数说明
参数 | 类型 | 说明 |
---|---|---|
cb | bt_ready_cb_t | 蓝牙初始化完成后的回调函数(可设为NULL) |
回调函数类型定义:
typedef void (*bt_ready_cb_t)(int err);
核心功能
硬件初始化
初始化蓝牙射频控制器(Radio)
配置底层硬件(如时钟、电源等)
协议栈加载
加载HCI层、L2CAP、ATT/GATT等协议栈组件
初始化安全管理器(SM)
默认配置应用
设置默认蓝牙MAC地址
应用编译时配置的默认参数
状态切换
将蓝牙控制器从OFF状态切换到READY状态
返回值
返回值 | 说明 |
---|---|
0 | 初始化流程成功启动(注意:实际结果通过回调返回) |
-EALREADY | 蓝牙协议栈已启用 |
-ENOMEM | 内存不足 |
-EIO | 硬件初始化失败 |
2.3.2 典型使用模式
1) 同步初始化(无回调)
int err = bt_enable(NULL);
if (err) {printk("Bluetooth init failed (err %d)\n", err);return;
}
// 继续其他蓝牙操作
2)异步初始化(带回调)
void bt_ready(int err) {if (err) {printk("Bluetooth init failed (err %d)\n", err);return;}printk("Bluetooth initialized\n");// 在这里启动广播/扫描等操作
}void main(void) {int err = bt_enable(bt_ready);if (err) {printk("Bluetooth enable failed (err %d)\n", err);}
}
2.3.3 关键处理流程
2.3.4 注意事项
单次调用限制
多数实现要求全局只调用一次
重复调用需先调用
bt_disable()
回调上下文
回调函数通常在蓝牙线程执行
避免在回调中进行阻塞操作
依赖关系
必须在所有其他蓝牙API前调用
通常应在系统初始化完成后调用
调试支持
可通过
CONFIG_BT_DEBUG
等选项启用调试日志
2.3.5 初始化失败常见原因
硬件问题
蓝牙芯片未正确供电
射频电路故障
配置冲突
与其他无线服务(如WiFi)共用资源
错误的时钟配置
资源不足
内存池大小不足(检查
CONFIG_BT_*_TX_COUNT
等配置)中断冲突
2.3.6 实际应用示例
1) 简单外设初始化
void main(void)
{bt_enable(NULL); // 同步初始化bt_le_adv_start(...); // 立即开始广播
}
2)带错误恢复的初始化
void bt_retry_init(int err)
{if (err) {k_sleep(K_SECONDS(1));bt_enable(bt_retry_init); // 重试初始化}
}void main(void)
{bt_enable(bt_retry_init);
}
2.3.7 应用总结
bt_enable
是蓝牙开发的第一个关键调用,其核心价值在于:
-
建立蓝牙操作的基础环境
-
提供同步/异步两种初始化模式
-
协调硬件和协议栈的启动
正确使用该API需要注意:
-
调用时机(早于其他蓝牙操作)
-
错误处理机制
-
特定协议栈的特殊要求
在复杂应用中,建议使用异步回调模式,以便在初始化完成后自动执行后续蓝牙操作流程。
2.4 bt_le_adv_update_data函数
2.4.1 函数功能
bt_le_adv_update_data
是蓝牙低功耗 (BLE) 协议栈中的一个关键 API 函数,用于动态更新正在进行的广播数据或扫描响应数据,而无需停止并重新启动广播。
核心功能
动态更新广播数据:修改广播包(Advertising Data)或扫描响应包(Scan Response Data)内容
无需重启广播:保持广播持续进行,避免广播中断导致的设备不可见期
实时数据刷新:适用于需要频繁更新广播信息的场景(如传感器数据变化)
函数原型(基于Zephyr等常见协议栈)
int bt_le_adv_update_data(const struct bt_data *ad, size_t ad_len,const struct bt_data *sd,size_t sd_len);
参数说明
参数 | 类型 | 说明 |
---|---|---|
ad | bt_data* | 新的广播数据数组 |
ad_len | size_t | 广播数据项数量 |
sd | bt_data* | 新的扫描响应数据数组 |
sd_len | size_t | 扫描响应数据项数量 |
返回值
返回值 | 说明 |
---|---|
0 | 数据更新成功 |
-EINVAL | 参数无效(如数据长度超限) |
-ENOMEM | 内存不足 |
-EAGAIN | 协议栈繁忙,需重试 |
-ENOTCONN | 当前未进行广播 |
2.4.2 典型使用场景
1) 传感器数据实时更新
// 初始广播
bt_le_adv_start(..., initial_ad, ...);// 当温度变化时更新数据
void update_temp_data(float new_temp)
{uint8_t temp_encoded = (uint8_t)(new_temp * 2);struct bt_data new_ad[] = {BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL),BT_DATA(BT_DATA_MANUFACTURER_DATA, &temp_encoded, 1)};bt_le_adv_update_data(new_ad, ARRAY_SIZE(new_ad), NULL, 0);
}
2) 动态切换广播模式
// 从普通广播切换到信标模式
struct bt_data beacon_ad[] =
{BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NONCONN_IND),BT_DATA(BT_DATA_MANUFACTURER_DATA, beacon_payload, sizeof(beacon_payload))
};bt_le_adv_update_data(beacon_ad, ARRAY_SIZE(beacon_ad), NULL, 0);
2.4.3 关键特性
原子性更新
1)数据更新在单个广播间隔内完 ;
2)接收端不会看到部分更新的数据
广播连续
1)保持现有广播间隔不变;
2)避免传统"停止-修改-重启"方式导致的 ~300ms 广播中断
数据限制
1)仍需遵守31字节的广播数据长度限制;
2)数据类型需符合蓝牙规范(不能动态修改AD Type)
2.4.4 实现原理
2.4.5 注意事项
广播必须处于活跃状态
1)需在bt_le_adv_start之后调用
2)已连接的设备会自动停止广播
数据一致性
1)更新期间应避免修改原始数据缓冲区
2)建议使用静态或全局数据数组
性能考量
1)频繁更新(如每秒多次)可能影响射频稳定性
2)建议合并更新(如每200ms批量更新一次)
厂商限制
1)某些低端蓝牙芯片可能不支持实时更新
2)需要检查协议栈实现是否支持该功能
2.4.6 错误处理最佳实践
int err = bt_le_adv_update_data(new_ad, ad_len, NULL, 0);
if (err == -ENOTCONN)
{// 广播未激活,重新启动bt_le_adv_start(...);
}
else if (err){printk("Update failed (err %d), retrying...\n", err);k_sleep(K_MSEC(100));// 重试逻辑}
2.4.7 典型应用案例
电子价签系统
不建立连接,通过广播更新价格信息
每15分钟更新一次广播数据
运动传感器
实时广播心率/步数变化
保持低功耗的同时更新数据
智能信标
动态调整广播内容(如店铺促销信息)
基于位置切换广播UUID
2.4.8 应用总结
bt_le_adv_update_data
提供了高效的广播数据动态更新机制,特别适合:
需要保持持续广播可见性的场景
实时数据传输但无需建立连接的用例
低功耗设备的数据更新需求
正确使用该API可以避免传统重启广播方式带来的连接中断风险,同时保证数据更新的实时性和可靠性。开发者应注意目标平台的协议栈实现差异,并进行充分的错误场景测试。