当前位置: 首页 > news >正文

Zephyr OS蓝牙广播(Advertising)功能实现

目录

概述

1 Advertising功能介绍

1.1 实现原理

 1.2 广播类型

 1.3 广播数据格式

1.4 优化建议

 1.5 常见问题和解决方法

2 Nordic 蓝牙广播(Advertising)功能实现

2.1 环境准备与SDK基础

2.2 广播功能实现

2.3 广播优化与最佳实践

3 实际应用案例

3.1 iBeacon实现

3.2 环境传感器广播

3.3 功耗测量优化

3.4 广播性能优化技巧

4 常见问题解决

4.1 广播不可见

4.2 数据更新失败

4.3 高功耗问题


概述

本文主要介绍Zephyr RTOS蓝牙广播(Advertising)功能实现,Zephyr RTOS为Nordic芯片提供了强大的蓝牙支持,使开发者能够高效实现BLE功能。下面我将详细介绍在Zephyr OS上实现蓝牙广播的完整流程。

1 Advertising功能介绍

蓝牙广播是低功耗蓝牙(BLE)中设备向外发送信息的主要方式,适用于信标、传感器数据广播、设备发现等场景。下面我将详细介绍蓝牙广播的实现原理和具体方法。

1.1 实现原理

蓝牙广播的核心机制是:

  1. 设备周期性地在三个广播信道(37, 38, 39)上发送广播包

  2. 广播包包含设备信息、服务标识和自定义数据

  3. 附近设备通过扫描接收这些广播信息

  4. 设备可以设置广播参数(间隔、类型、数据等)

 1.2 广播类型

广播类型描述适用场景
ADV_IND0可连接的非定向广播通用设备发现
ADV_DIRECT_IND1可连接的定向广播快速重连
ADV_SCAN_IND2可扫描的非定向广播广播数据
ADV_NONCONN_IND3不可连接的非定向广播信标设备
ADV_DIRECT_IND_LOW4低占空比的定向广播节能设备

 1.3 广播数据格式

1)合理组织AD结构

// 推荐的广播数据结构
[Flags][Service UUID][Device Name][Tx Power][Manufacturer Data]

2)控制数据长度

广播数据:最大31字节扫描响应数据:最大31字节优先放置重要信息在广播数据中

1.4 优化建议

1)功耗优化

  • 适当增加广播间隔(100ms-1s)

  • 使用不可连接广播类型(ADV_NONCONN_IND)

  • 在不需要时停止广播

2) 数据压缩

  • 使用紧凑的数据格式

  • 避免重复信息

  • 使用自定义二进制格式替代文本

 3)安全考虑

  • 避免广播敏感信息

  • 使用随机设备地址

  • 实现广播数据加密(如Eddystone-EID)

 1.5 常见问题和解决方法

1)广播数据被截断

  • 检查数据长度是否超过31字节

  • 优先放置重要数据在开头

  • 使用扫描响应数据补充信息

2) 设备无法被发现

  • 确认使用了正确的广播类型

  • 检查广播信道是否被干扰

  • 验证广播间隔设置是否合理

3) 功耗过高

  • 增加广播间隔

  • 减少广播数据量

  • 使用更节能的广播类型

 4)兼容性问题

  • 避免使用BLE 5.0特有功能与旧设备通信

  • 包含基本的BLE 4.0兼容数据

  • 提供多种广播数据格式

2 Nordic 蓝牙广播(Advertising)功能实现

2.1 环境准备与SDK基础

1) 开发环境

  • 硬件:nRF52系列开发板(如nRF52832/nRF52840)

  • 软件

    • nRF Connect SDK(最新版本)

    • Segger Embedded Studio 或 VSCode + nRF Connect插件

    • nRF Command Line Tools

2) SDK关键组件

  • SoftDevice:蓝牙协议栈

  • BLE Advertising Module:广播功能核心模块

  • BLE Services:GAP和GATT服务

2.2 广播功能实现

1)基础广播实现

#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/gap.h>/* 广播参数配置 */
static const struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME, // 可连接且包含设备名800,   // 最小广播间隔: 800*0.625ms=500ms1600,  // 最大广播间隔: 1600*0.625ms=1000msNULL); // 对等设备地址(定向广播使用)/* 广播数据结构 */
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, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};/* 扫描响应数据 */
static const struct bt_data sd[] = {BT_DATA(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_DIS_VAL)),
};void main(void)
{int err;/* 初始化蓝牙协议栈 */err = bt_enable(NULL);if (err) {printk("Bluetooth init failed (err %d)\n", err);return;}printk("Bluetooth initialized\n");/* 启动广播 */err = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));if (err) {printk("Advertising failed to start (err %d)\n", err);return;}printk("Advertising successfully started\n");/* 主循环 */while (1) {k_sleep(K_SECONDS(10));// 在此添加广播更新逻辑}
}

2)高级广播功能

- 2.1) 制造商特定数据广播

/* 制造商特定数据结构 */
#define MANUFACTURER_ID 0x0059 // Nordic的厂商IDstatic uint8_t mfg_data[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; // 自定义数据static struct bt_data custom_ad[] = {BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data)),
};/* 更新广播数据 */
void update_advertising_data(void)
{// 动态更新制造商数据mfg_data[0] = (k_uptime_get_32() >> 24) & 0xFF;mfg_data[1] = (k_uptime_get_32() >> 16) & 0xFF;// 停止当前广播bt_le_adv_stop();// 使用新数据重新启动广播bt_le_adv_start(adv_param, custom_ad, ARRAY_SIZE(custom_ad), NULL, 0);
}

-2.2) 扩展广播 (BLE 5.0+)

#if defined(CONFIG_BT_EXT_ADV)
/* 扩展广播参数 */
static const struct bt_le_adv_param ext_adv_param = {.id = 0,.sid = 0,.secondary_max_skip = 0,.options = BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME |BT_LE_ADV_OPT_CONNECTABLE,.interval_min = BT_GAP_ADV_FAST_INT_MIN_2, // 30ms.interval_max = BT_GAP_ADV_FAST_INT_MAX_2, // 50ms.peer = NULL,
};/* 配置扩展广播 */
void start_extended_advertising(void)
{struct bt_le_ext_adv *ext_adv;int err;/* 创建扩展广播实例 */err = bt_le_ext_adv_create(&ext_adv_param, NULL, &ext_adv);if (err) {printk("Failed to create extended advertising set (err %d)\n", err);return;}/* 设置广播数据 */err = bt_le_ext_adv_set_data(ext_adv, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));if (err) {printk("Failed to set advertising data (err %d)\n", err);return;}/* 启动扩展广播 */err = bt_le_ext_adv_start(ext_adv, BT_LE_EXT_ADV_START_DEFAULT);if (err) {printk("Failed to start extended advertising (err %d)\n", err);return;}printk("Extended advertising started\n");
}
#endif /* CONFIG_BT_EXT_ADV */

3. 动态广播间隔调整

/* 动态调整广播间隔 */
void adjust_advertising_interval(uint16_t min_interval, uint16_t max_interval)
{// 创建新的广播参数const struct bt_le_adv_param *new_param = BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME,min_interval,max_interval,NULL);// 停止当前广播bt_le_adv_stop();// 使用新参数启动广播bt_le_adv_start(new_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));printk("Advertising interval adjusted to %d-%d ms\n",min_interval * 5 / 8, max_interval * 5 / 8);
}/* 在低功耗模式下延长广播间隔 */
void enter_low_power_mode(void)
{// 设置长间隔:2000-4000 msadjust_advertising_interval(3200, 6400);
}/* 在活跃模式下缩短广播间隔 */
void enter_active_mode(void)
{// 设置短间隔:100-200 msadjust_advertising_interval(160, 320);
}

2.3 广播优化与最佳实践

1) 广播数据压缩技巧

/* 紧凑广播数据结构 */
static const struct bt_data compressed_ad[] = {// 标志位 (1字节)BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),// 短名称 (4字节)BT_DATA(BT_DATA_NAME_SHORTENED, "Zeph", 4),// 服务UUID (2字节)BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_UUID_16_ENCODE(BT_UUID_HRS_VAL)),// 制造商数据 (5字节: 厂商ID + 3字节自定义)BT_DATA(BT_DATA_MANUFACTURER_DATA, (uint8_t[]){0x59, 0x00, 0x01, 0x02, 0x03}, 5),// 发射功率 (2字节)BT_DATA_BYTES(BT_DATA_TX_POWER, 0xF4) // -12 dBm
};

2) 广播功耗优化

/* 优化广播参数 */
static const struct bt_le_adv_param low_power_adv_param = BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_LOW_POWER,1600,   // 1000ms3200,   // 2000msNULL);/* 降低发射功率 */
void reduce_tx_power(void)
{int err;// 设置-20dBm的发射功率err = bt_le_set_tx_power(BT_LE_TX_POWER_N4); // -20dBmif (err) {printk("Failed to set TX power (err %d)\n", err);} else {printk("TX power reduced to -20dBm\n");}
}/* 配置广播睡眠模式 */
void configure_advertising_scheduler(void)
{// 仅在白天活动 (示例)k_work_schedule(&adv_work, K_HOURS(6));  // 6AM开始广播k_work_schedule(&sleep_work, K_HOURS(18)); // 6PM停止广播
}static void start_adv_work(struct k_work *work)
{bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));printk("Advertising started\n");
}static void stop_adv_work(struct k_work *work)
{bt_le_adv_stop();printk("Advertising stopped\n");
}K_WORK_DELAYABLE_DEFINE(adv_work, start_adv_work);
K_WORK_DELAYABLE_DEFINE(sleep_work, stop_adv_work);

3 实际应用案例

3.1 iBeacon实现

#include <zephyr/sys/byteorder.h>/* iBeacon数据格式 */
void configure_ibeacon(void)
{const struct bt_data ibeacon_ad[] = {BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA,0x4c, 0x00, // Apple ID0x02, 0x15, // iBeacon类型// UUID0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2,0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0,// Major0x00, 0x01,// Minor0x00, 0x02,// Tx Power0xC5)};// 使用不可连接广播const struct bt_le_adv_param *ibeacon_param = BT_LE_ADV_PARAM(BT_LE_ADV_OPT_NONE, 160,   // 100ms320,   // 200msNULL);// 启动iBeacon广播bt_le_adv_start(ibeacon_param, ibeacon_ad, ARRAY_SIZE(ibeacon_ad), NULL, 0);printk("iBeacon advertising started\n");
}

3.2 环境传感器广播

/* 传感器数据结构 */
struct sensor_data {int16_t temperature; // 温度 (0.01°C)uint16_t humidity;   // 湿度 (0.01%)uint8_t battery;     // 电池电量 (0-100%)
};/* 更新传感器广播数据 */
void update_sensor_advertising(struct sensor_data *data)
{uint8_t mfg_data[7];// 厂商ID (Nordic)mfg_data[0] = 0x59;mfg_data[1] = 0x00;// 温度 (小端序)sys_put_le16(data->temperature, &mfg_data[2]);// 湿度 (小端序)sys_put_le16(data->humidity, &mfg_data[4]);// 电池电量mfg_data[6] = data->battery;// 更新广播数据const struct bt_data sensor_ad[] = {BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, sizeof(mfg_data))};// 停止并重新启动广播以更新数据bt_le_adv_stop();bt_le_adv_start(adv_param, sensor_ad, ARRAY_SIZE(sensor_ad), NULL, 0);printk("Sensor data updated: T=%.2fC, H=%.2f%%, Bat=%d%%\n",data->temperature / 100.0, data->humidity / 100.0, data->battery);
}

3.3 功耗测量优化

/* 功耗测量代码片段 */
void measure_power_consumption(void)
{uint32_t start_time = k_uptime_get_32();uint32_t start_cycles = k_cycle_get_32();// 执行广播操作bt_le_adv_start(/* 参数 */);k_sleep(K_MSEC(5000));bt_le_adv_stop();uint32_t duration_ms = k_uptime_get_32() - start_time;uint64_t total_cycles = k_cycle_get_32() - start_cycles;// 计算平均电流(需要硬件测量校准)float avg_current = (total_cycles * 1000.0) / (duration_ms * sys_clock_hw_cycles_per_sec());printk("Advertising power: %.2f mA\n", avg_current);
}

3.4 广播性能优化技巧

  1. 数据压缩:使用自定义二进制格式而非文本

  2. 广播间隔:根据应用场景动态调整间隔

    • 发现阶段:短间隔(100-200ms)

    • 稳定状态:长间隔(1-2秒)

  3. 广播信道:优先使用信道37(最少干扰)

  4. 数据分片:对大型数据使用扫描响应

  5. 广播时间窗口:仅在需要时广播

4 常见问题解决

4.1 广播不可见

// 在代码中添加验证
if (!bt_le_adv_is_enabled()) {printk("Advertising not enabled!\n");
}// 检查广播参数
if (adv_param->options & BT_LE_ADV_OPT_SCANNABLE) {printk("Broadcast is scannable\n");
}

4.2 数据更新失败

void safe_update_advertising(void)
{static struct k_mutex adv_mutex;k_mutex_lock(&adv_mutex, K_FOREVER);bt_le_adv_stop();// 更新数据bt_le_adv_start(/* 新参数 */);k_mutex_unlock(&adv_mutex);
}

4.3 高功耗问题

  • 动态调整广播间隔

  • 使用-20dBm到-12dBm的发射功率

  • 实现广播睡眠计划

// 1. 降低发射功率
bt_le_set_tx_power(BT_LE_TX_POWER_N8); // -8dBm// 2. 增加广播间隔
adjust_advertising_interval(3200, 6400); // 2-4秒// 3. 使用不可连接广播
const struct bt_le_adv_param *non_conn_param = BT_LE_ADV_PARAM(BT_LE_ADV_OPT_NONE, 1600, 3200, NULL);

相关文章:

  • 西安做网站建设哪家好佛山seo按效果付费
  • .net电影网站开发站长
  • 免费1级做爰片观看网站在线视频公众号推广费用一般多少
  • 天津做网站开发的齐三seo顾问
  • wordpress中文公司模板windows优化大师使用方法
  • 网站长尾词排名做不上去手机百度下载免费
  • 【Docker基础】Docker容器管理:docker unpause详解
  • 大模型本地部署,拥有属于自己的ChatGpt
  • 14.OCR字符识别
  • 【计算机网络】期末复习
  • STM32 环境监测与控制系统的设计与实现
  • 壁挂马桶品牌推荐:我的“瑞尔特瑞家HX5”沉浸式体验报告健康与洁净的硬核科技
  • 集成学习基础:Bagging 原理与应用
  • Linux环境下MariaDB如何实现负载均衡
  • 什么是RibbitMQ
  • 【e^ix图像展示】
  • 选择整数类型
  • 浸入式学语言助手(illa-helper)一款基于“可理解输入“理论的浏览器扩展插件,帮助在日常网页浏览中自然地学习语言。
  • [3D-Portfolio] docs | js集中式配置 | React组件 | 组件嵌套
  • 深度学习在智能机器人导航中的创新应用与未来趋势
  • 学习日记-spring-day36-6.24
  • NLP基础1_word-embedding
  • (简介)Llama 系列模型
  • 【ArcGIS】土地资源单项评价
  • WD5032是一款集成多个USB专用充电协议的高效、单片同步降压DC/DC转换器,32V,3.1A车充芯片,支持快速充电协议
  • 3D人物建模与WebGL渲染实战