目录
[1 函数接口](#1 函数接口)
[2 主要函数介绍](#2 主要函数介绍)
[2.1 bt_le_adv_start函数](#2.1 bt_le_adv_start函数)
[2.1.1 函数功能介绍](#2.1.1 函数功能介绍)
[2.1.2 典型使用示例](#2.1.2 典型使用示例)
[2.1.3 广播间隔](#2.1.3 广播间隔)
[2.1.4 注意事项](#2.1.4 注意事项)
[2.2 bt_le_adv_stop 函数](#2.2 bt_le_adv_stop 函数)
[2.2.1 函数功能](#2.2.1 函数功能)
[2.2.2 使用方法介绍](#2.2.2 使用方法介绍)
[2.2.3 实际应用示例](#2.2.3 实际应用示例)
[2.2.4 关键注意事项](#2.2.4 关键注意事项)
[2.2.5 常见问题解决](#2.2.5 常见问题解决)
[2.2.6 应用总结](#2.2.6 应用总结)
[2.3 bt_enable](#2.3 bt_enable)
[2.3.1 函数功能](#2.3.1 函数功能)
[2.3.2 典型使用模式](#2.3.2 典型使用模式)
[2.3.3 关键处理流程](#2.3.3 关键处理流程)
[2.3.4 注意事项](#2.3.4 注意事项)
[2.3.5 初始化失败常见原因](#2.3.5 初始化失败常见原因)
[2.3.6 实际应用示例](#2.3.6 实际应用示例)
[2.3.7 应用总结](#2.3.7 应用总结)
[2.4 bt_le_adv_update_data函数](#2.4 bt_le_adv_update_data函数)
[2.4.1 函数功能](#2.4.1 函数功能)
[2.4.2 典型使用场景](#2.4.2 典型使用场景)
[2.4.3 关键特性](#2.4.3 关键特性)
[2.4.4 实现原理](#2.4.4 实现原理)
[2.4.5 注意事项](#2.4.5 注意事项)
[2.4.6 错误处理最佳实践](#2.4.6 错误处理最佳实践)
[2.4.7 典型应用案例](#2.4.7 典型应用案例)
[2.4.8 应用总结](#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)函数原型:
            
            
              cpp
              
              
            
          
          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)
            
            
              cpp
              
              
            
          
          struct bt_le_adv_param {
    uint8_t  id;        // 广播集 ID
    uint32_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)
            
            
              cpp
              
              
            
          
          struct bt_data {
    uint8_t type;  // 数据类型(如 BT_DATA_NAME_COMPLETE)
    uint8_t data_len;
    const uint8_t *data;
};
        2.1.2 典型使用示例
1)1. 基本可连接广播
            
            
              cpp
              
              
            
          
          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 模式)
            
            
              cpp
              
              
            
          
          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 协议栈)
            
            
              cpp
              
              
            
          
          int bt_le_adv_stop(void);
        参数
- 无参数:直接停止当前活跃的广播
 
返回值
| 返回值 | 说明 | 
|---|---|
0 | 
停止广播成功 | 
-EALREADY | 
当前没有活跃的广播 | 
| 其他负值 | 其他错误(如协议栈错误) | 
2.2.2 使用方法介绍
1)基本启停控制
            
            
              cpp
              
              
            
          
          // 启动广播
bt_le_adv_start(...);
// 一段时间后停止广播
bt_le_adv_stop();
        2)条件性停止广播
            
            
              cpp
              
              
            
          
          if (need_to_stop_advertising) {
    int err = bt_le_adv_stop();
    if (err) {
        printk("Stop failed (err %d)\n", err);
    }
}
        3)广播模式切换
            
            
              cpp
              
              
            
          
          // 先停止当前广播
bt_le_adv_stop();
// 更换参数后重新启动
bt_le_adv_start(new_params, ...);
        2.2.3 实际应用示例
场景:温度传感器按需广播
            
            
              cpp
              
              
            
          
          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:
            
            
              cpp
              
              
            
          
          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等常见协议栈)
            
            
              cpp
              
              
            
          
          int bt_enable(bt_ready_cb_t cb);
        参数说明
| 参数 | 类型 | 说明 | 
|---|---|---|
cb | 
bt_ready_cb_t | 
蓝牙初始化完成后的回调函数(可设为NULL) | 
回调函数类型定义:
            
            
              cpp
              
              
            
          
          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) 同步初始化(无回调)
            
            
              cpp
              
              
            
          
          int err = bt_enable(NULL);
if (err) {
    printk("Bluetooth init failed (err %d)\n", err);
    return;
}
// 继续其他蓝牙操作
        2)异步初始化(带回调)
            
            
              cpp
              
              
            
          
          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) 简单外设初始化
            
            
              cpp
              
              
            
          
          void main(void) 
{
    bt_enable(NULL); // 同步初始化
    bt_le_adv_start(...); // 立即开始广播
}
        2)带错误恢复的初始化
            
            
              cpp
              
              
            
          
          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等常见协议栈)
            
            
              cpp
              
              
            
          
          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) 传感器数据实时更新
            
            
              cpp
              
              
            
          
          // 初始广播
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) 动态切换广播模式
            
            
              cpp
              
              
            
          
          // 从普通广播切换到信标模式
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 错误处理最佳实践
            
            
              cpp
              
              
            
          
          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可以避免传统重启广播方式带来的连接中断风险,同时保证数据更新的实时性和可靠性。开发者应注意目标平台的协议栈实现差异,并进行充分的错误场景测试。