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

Zephyr 中的 bt_le_per_adv_set_data 函数的介绍和应用方法

目录

概述

1 函数接口介绍

1.1 函数原型

1.2 功能详解

2 使用方法

2.1 创建流程

2.1.1 创建扩展广播实例

2.1.2 设置周期性广播数据

2.1.3 配置周期性广播参数

2.1.4 启动广播

2.2 主流程函数

2.3 关键配置 (prj.conf)

3 高级用法

3.1 大数据分片传输

3.2 动态数据更新

3.3 多广播集数据同步

4 应用场景

4.1 LE Audio 广播

4.2 电子货架标签系统

4.3 工业传感器网络

5 性能优化技巧

5.1 数据压缩:

5.2 增量更新:

5.3 自适应间隔:

6 常见问题和解决方案


概述

bt_le_per_adv_set_data() 是 Zephyr RTOS 蓝牙协议栈中用于设置周期性广播数据的关键函数。它允许设备配置周期性广播的数据内容,这是蓝牙 5.0 及以上版本支持的高级特性。该函数是实现高效周期性广播系统的核心,通过合理设计数据结构和更新机制,可以构建从低功耗传感器网络到高质量音频广播等各种应用。

1 函数接口介绍

1.1 函数原型

int bt_le_per_adv_set_data(struct bt_le_ext_adv *adv, const uint8_t *data, uint8_t len);

参数说明

参数类型说明
advstruct bt_le_ext_adv*指向已创建的扩展广播实例的指针
dataconst uint8_t*周期性广播数据缓冲区
lenuint8_t数据长度(最大 252 字节)

返回值

返回值说明
0设置成功
-EINVAL无效参数
-ENOMEM内存不足
-EIO底层 HCI 错误

1.2 功能详解

1) 配置周期性广播内容

  • 定义周期性广播中传输的实际数据内容

  • 数据格式遵循标准蓝牙 AD 结构(长度-类型-值)

2) 与主广播分离

  • 周期性广播数据独立于主扩展广播数据

  • 允许传输更大、更频繁更新的数据集

3)  数据格式要求

  • 必须符合蓝牙 SIG 定义的 AD 数据结构

  • 典型结构:

    // 示例数据格式
    uint8_t per_adv_data[] = {0x02, BT_DATA_FLAGS, BT_LE_AD_NO_BREDR,           // 广播标志0x0A, BT_DATA_MANUFACTURER_DATA, 0xCD, 0x01, ...  // 厂商自定义数据0x10, BT_DATA_SVC_DATA16, 0xAA, 0xFE, ...         // 服务数据
    };

2 使用方法

2.1 创建流程

2.1.1 创建扩展广播实例

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/gap.h>static struct bt_le_ext_adv *adv;// 创建扩展广播实例
int create_adv_instance(void)
{struct bt_le_adv_param adv_params = {.id = BT_ID_DEFAULT,.sid = 1,.secondary_max_skip = 0,.options = BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_PERIODIC,.interval_min = BT_GAP_ADV_SLOW_INT_MIN,.interval_max = BT_GAP_ADV_SLOW_INT_MAX,};return bt_le_ext_adv_create(&adv_params, NULL, &adv);
}

2.1.2 设置周期性广播数据

// 设置周期性广播数据
int set_periodic_data(void)
{// 示例:温度传感器数据uint8_t temp_data[] = {0x02, BT_DATA_FLAGS, BT_LE_AD_NO_BREDR,          // 广播标志0x03, BT_DATA_TEMP_SERVICE, 0xAA, 0xBB,          // 温度服务标识0x05, BT_DATA_SENSOR_VALUE, 0x00, 0x00, 0x00, 0x00 // 4字节温度值};// 更新温度值(小端格式)float temperature = 23.5f;memcpy(&temp_data[8], &temperature, sizeof(float));return bt_le_per_adv_set_data(adv, temp_data, sizeof(temp_data));
}

2.1.3 配置周期性广播参数

// 配置周期性广播参数
int config_periodic_adv(void)
{struct bt_le_per_adv_param per_adv_params = {.interval_min = BT_GAP_PER_ADV_SLOW_INT_MIN, // 1.28秒.interval_max = BT_GAP_PER_ADV_SLOW_INT_MIN, // 固定间隔.options = BT_LE_PER_ADV_OPT_USE_TX_POWER,  // 包含发射功率};return bt_le_per_adv_set_param(adv, &per_adv_params);
}

2.1.4 启动广播

// 启动广播
int start_advertising(void)
{int err;// 启动扩展广播struct bt_le_ext_adv_start_param ext_adv_params = {0};if ((err = bt_le_ext_adv_start(adv, &ext_adv_params))) {return err;}// 启动周期性广播return bt_le_per_adv_start(adv);
}

2.2 主流程函数

void main(void)
{bt_enable(NULL); // 初始化蓝牙create_adv_instance();set_periodic_data();config_periodic_adv();start_advertising();while (1) {k_sleep(K_SECONDS(30));update_sensor_data(); // 定期更新广播数据}
}// 更新传感器数据
void update_sensor_data(void)
{// 1. 停止周期性广播bt_le_per_adv_stop(adv);// 2. 更新数据set_periodic_data();// 3. 重新启动bt_le_per_adv_start(adv);
}

2.3 关键配置 (prj.conf)

# 基础蓝牙配置
CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y# 扩展广播和周期性广播
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y# 增加缓冲区大小
CONFIG_BT_BUF_ACL_TX_SIZE=255
CONFIG_BT_BUF_ACL_RX_SIZE=255# 支持的最大广播集
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2

3 高级用法

3.1 大数据分片传输

#define CHUNK_SIZE 200
uint8_t large_data[1000]; // >252字节的数据void send_large_data(void)
{for (int i = 0; i < sizeof(large_data); i += CHUNK_SIZE) {uint8_t chunk_len = MIN(CHUNK_SIZE, sizeof(large_data) - i);uint8_t adv_data[2 + CHUNK_SIZE] = {0x01, BT_DATA_SEQ_DATA, // 自定义分片标识(i / CHUNK_SIZE) & 0xFF // 分片序号};memcpy(&adv_data[2], &large_data[i], chunk_len);bt_le_per_adv_set_data(adv, adv_data, chunk_len + 2);k_sleep(K_MSEC(50)); // 等待传输完成}
}

3.2 动态数据更新

// 无中断更新数据
void update_data_seamlessly(void)
{// 1. 准备新数据uint8_t new_data[200] = {...};// 2. 设置新数据bt_le_per_adv_set_data(adv, new_data, sizeof(new_data));// 注意:无需停止/重启广播,数据会自动更新
}

3.3 多广播集数据同步

struct bt_le_ext_adv *adv1, *adv2;void sync_adv_data(void)
{uint8_t shared_data[] = {...};// 为多个广播集设置相同数据bt_le_per_adv_set_data(adv1, shared_data, sizeof(shared_data));bt_le_per_adv_set_data(adv2, shared_data, sizeof(shared_data)));
}

4 应用场景

4.1 LE Audio 广播

// 配置LE音频广播数据
int setup_le_audio_broadcast(void)
{uint8_t audio_data[] = {// 基础音频配置0x06, BT_DATA_LE_AUDIO_BROADCAST, 0x01, 0x00, // 广播ID0x02,       // 音频编码: LC30x02, 0x01, // 采样率48kHz// 附加信息0x05, BT_DATA_LE_AUDIO_METADATA,0x01, 0x02, 0x03, 0x04};return bt_le_per_adv_set_data(adv, audio_data, sizeof(audio_data));
}

4.2 电子货架标签系统

void update_esl_data(uint16_t product_id, uint32_t price)
{uint8_t esl_data[] = {0x01, 0x12, // 自定义ESL标识(product_id >> 8) & 0xFF, product_id & 0xFF,(price >> 24) & 0xFF, (price >> 16) & 0xFF,(price >> 8) & 0xFF, price & 0xFF};bt_le_per_adv_set_data(adv, esl_data, sizeof(esl_data));
}

4.3 工业传感器网络

void broadcast_sensor_readings(float temp, float humidity, uint32_t pressure)
{uint8_t sensor_data[15] = {0x02, BT_DATA_MANUFACTURER_DATA, 0xCD, 0x01, // 厂商ID};// 小端格式打包数据memcpy(&sensor_data[4], &temp, 4);memcpy(&sensor_data[8], &humidity, 4);memcpy(&sensor_data[12], &pressure, 4);bt_le_per_adv_set_data(adv, sensor_data, sizeof(sensor_data));
}

5 性能优化技巧

5.1 数据压缩

// 使用紧凑数据格式
uint8_t compressed_data[10] = {0x01, 0xAB, // 数据类型标识(int8_t)(temp * 2),   // 1字节温度 (-128~127°C, 0.5°C精度)(uint8_t)humidity,    // 1字节湿度 (0-100%)(pressure >> 16) & 0xFF, (pressure >> 8) & 0xFF, pressure & 0xFF // 3字节压力
};

5.2 增量更新

// 仅发送变化的数据
if (fabs(temp - last_temp) > 0.1f) {update_temp_in_adv_data(temp);bt_le_per_adv_set_data(adv, current_data, data_len);last_temp = temp;
}

5.3 自适应间隔

// 根据数据变化率调整广播间隔
void adjust_broadcast_interval(float change_rate)
{uint32_t new_interval = MAX(BT_GAP_PER_ADV_FAST_INT_MIN,MIN(BT_GAP_PER_ADV_SLOW_INT_MAX,1000 / change_rate // 基于变化率计算));struct bt_le_per_adv_param params = {.interval_min = new_interval,.interval_max = new_interval};bt_le_per_adv_set_param(adv, &params);
}

6 常见问题和解决方案

1) 数据设置失败 (错误 -22/EINVAL)

  • 检查数据长度:确保不超过 252 字节

  • 验证数据结构:确认 AD 结构格式正确(长度值匹配后续数据)

  • 确认广播实例状态:必须在启动周期性广播前设置数

2) 接收端无法解析数据

  • 包含必要标识:确保数据中包含广播标志 (0x01)

  • 添加设备名称:包含完整或简称设备名

  • 使用标准数据类型:优先使用 SIG 定义的 AD 类型

3) 数据更新延迟

  • 减少广播间隔:使用更短的间隔参数

  • 优化更新流程

    // 高效更新流程
    void efficient_update(uint8_t *new_data, uint8_t len)
    {// 无需停止广播即可更新数据bt_le_per_adv_set_data(adv, new_data, len);// 强制刷新(某些控制器需要)bt_le_per_adv_stop(adv);k_sleep(K_MSEC(5));bt_le_per_adv_start(adv);
    }
http://www.dtcms.com/a/337710.html

相关文章:

  • [机器学习]09-基于四种近邻算法的鸢尾花数据集分类
  • 具身智能赋能轮椅机器人的认知革命与人机共生新范式
  • 【软考架构】第4章 信息安全的抗攻击技术
  • 从「行走」到「思考」:机器人进化之路与感知—决策链路的工程化实践
  • 微电网管控系统中python多线程缓存与SQLite多数据库文件连接池实践总结(含源码)
  • 安川YASKAWA焊接机器人保护气智能节气阀
  • 蓝牙 GFSK RX Core 架构解析
  • Linux下的软件编程——IPC机制
  • 重复(Repeat)和迭代(Iteration)区别、递归(Recursion)
  • 超级云平台:重构数字生态的“超级连接器“
  • 想找出版社出书?这样选就对了!
  • 哈工深无人机目标导航新基准!UAV-ON:开放世界空中智能体目标导向导航基准测试
  • 【论文阅读】-《GeoDA: a geometric framework for black-box adversarial attacks》
  • 基于Flink CDC实现联系人与标签数据实时同步至ES的实践
  • 后台管理系统-6-vue3之mockjs模拟和axios请求数据
  • python UV虚拟环境项目搭建
  • 和芯星通携手思博伦通信,测试验证系列导航定位芯片/模块符合GB/T 45086.1标准
  • 学习stm32 感应开关盖垃圾桶
  • 用 Python 实现一个“小型 ReAct 智能体”:思维链 + 工具调用 + 环境交互
  • 软件测试覆盖率:真相与实践
  • unity实现背包拖拽排序
  • 1个月征服Java:零基础直达企业级开发——Java面向对象补充知识
  • 汽车近光灯难达标?OAS 软件精准解困
  • 【牛客刷题】正六边形阴影面积计算
  • 深入理解列式存储与向量化引擎
  • 无人机行业“黑话”
  • 10CL016YF484C8G Altera FPGA Cyclone
  • Qt第十讲-使用快捷键
  • Mybatis执行sql流程(一)
  • TP6用word文档导入数学公式