zephyr设置BLE广播数据实例

目录

实例1:静态开启广播数据

新建一个hello world的工程模板。

  1. 在prj.conf中开启蓝牙
c 复制代码
CONFIG_BT=y

这个宏,默认会开启广播支持 ( BT_BROADCASTER) ,使用softDevice控制器 ( BT_LL_CHOICE= BT_LL_SOFTDEVICE),发射功率为0dBm( BT_CTLR_TX_PWR = BT_CTLR_TX_PWR_0)。

  1. 设置设备名称
    添加以下行prj.conf:
c 复制代码
 CONFIG_BT_DEVICE_NAME="Nordic_Beacon"
  1. 设置广播数据
c 复制代码
/* STEP 4.1.1 - Declare the advertising packet */
static const struct bt_data ad[] = {
	/* STEP 4.1.2 - Set the advertising flags */
	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
	/* STEP 4.1.3 - Set the advertising packet data  */
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),

};
  1. 设置扫描响应数据
c 复制代码
/* STEP 4.2.2 - Declare the URL data to include in the scan response */
static unsigned char url_data[] = {
	0x17, '/', '/', 'b', 'a', 'i', 'd', 'u', '.',
	'c', 'o', 'm'};

/* STEP 4.2.1 - Declare the scan response packet */
static const struct bt_data sd[] = {
	/* 4.2.3 Include the URL data in the scan response packet*/
	BT_DATA(BT_DATA_URI, url_data, sizeof(url_data)),
};
  1. 使能蓝牙协议栈
c 复制代码
	err = bt_enable(NULL);
	if (err)
	{
		LOG_ERR("Bluetooth init failed (err %d)\n", err);
		return -1;
	}
  1. 开启蓝牙广播
c 复制代码
	err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
	if (err)
	{
		LOG_ERR("Advertising failed to start (err %d)\n", err);
		return -1;
	}

运行和测试

开启广播就是这么简单就行。
完整的代码

实例2:动态更改广播数据

这个实例将重点关注广播参数、制造商特定数据以及动态更新广播数据。

广播参数的控制,广播参数放在bt_le_adv_param变量里面。由于此变量需要初始化内容太多,因此使用宏 BT_LE_ADV_PARAM()来帮助初始化

c 复制代码
options:用于配置广告选项的特定宏。例如,选择在哪个频道(37、38、39)上投放广告。有 19 个选项可用,可在此处找到。
最小广告间隔:(N * 0.625 毫秒):小于或等于最大广告间隔。N 的允许范围是 32 到 16384,相当于 20 毫秒到 10.24 秒。API 具有用于广告间隔的预定义值。
最大广告间隔:(N * 0.625 毫秒):大于或等于最小广告间隔。N 的允许范围是 32 到 16384,相当于 20 毫秒到 10.24 秒。API 具有用于广告间隔的预定义值。
对等地址:如果使用定向广告则包含。否则,设置为 NULL。

代码实现如下

  1. 使用自带的LED和BUTTON库,在prj.conf加入如下。
c 复制代码
# Button and LED library
CONFIG_DK_LIBRARY=y

2.在main.c加入头文件

c 复制代码
#include <dk_buttons_and_leds.h>

3.定义广播参数

c 复制代码
static struct bt_le_adv_param *adv_param =
	BT_LE_ADV_PARAM(BT_LE_ADV_OPT_NONE,
	800,
	801,
	NULL);

4.定义自定义数据

c 复制代码
#define COMPANY_ID_CODE            0x0059

5.定义动态数据存放的变量,这里定义个结构体,方便管理

c 复制代码
typedef struct adv_mfg_data {
	uint16_t company_code;	    /* Company Identifier Code. */
	uint16_t number_press;      /* Number of times Button 1 is pressed*/
} adv_mfg_data_type;

初始化

c 复制代码
static adv_mfg_data_type adv_mfg_data = {COMPANY_ID_CODE,0x00};

6.将自定义数据包含到广播包里面

c 复制代码
static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
	BT_DATA(BT_DATA_MANUFACTURER_DATA, (unsigned char *)&adv_mfg_data, sizeof(adv_mfg_data)), // 添加自定义数据
};

7.添加按钮初始化代码,和注册按钮回调函数

c 复制代码
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	if (has_changed & button_state & USER_BUTTON) {
	adv_mfg_data.number_press += 1;
	bt_le_adv_update_data(ad, ARRAY_SIZE(ad),
			      sd, ARRAY_SIZE(sd)); //这里是动态更新广播数据的地方
	}
}

static int init_button(void)
{
	int err;

	err = dk_buttons_init(button_changed);
	if (err) {
		printk("Cannot init buttons (err: %d)\n", err);
	}

	return err;
}

8.在main函数调用按钮初始化

c 复制代码
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	if (has_changed & button_state & USER_BUTTON) {
	adv_mfg_data.number_press += 1;
	bt_le_adv_update_data(ad, ARRAY_SIZE(ad),
			      sd, ARRAY_SIZE(sd));
	}
}

在第7步,函数是动态更新广播数据

编译和测试

可以点击数据,选择显示数据的格式

完整代码

开启蓝牙后,建议将栈的空间加大到2048

c 复制代码
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
CONFIG_MAIN_STACK_SIZE=2048

实例3:创建可连接的广播

  1. 配置蓝牙BLE的角色,配置为外设角色
c 复制代码
CONFIG_BT_PERIPHERAL=y
  1. 修改蓝牙名称,这样可以方便区分
c 复制代码
CONFIG_BT_DEVICE_NAME="Nordic_Peripheral"

3.修改广播的内容,主要是修改flag的内容,

c 复制代码
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),
};

扫描响应包添加UUID,比如添加一个LBS的UUID

c 复制代码
#include <zephyr/bluetooth/uuid.h>

static const struct bt_data sd[] = {
	// BT_DATA(BT_DATA_URI, url_data, sizeof(url_data)),
	BT_DATA_BYTES(BT_DATA_UUID128_ALL,BT_UUID_128_ENCODE(0x00001523, 0x1212, 0xefde, 0x1523, 0x785feabcd123)),
};

4.设置随机静态地址。

c 复制代码
#include <zephyr/bluetooth/addr.h>

    bt_addr_le_t addr;
    err = bt_addr_le_from_str("FF:EE:DD:CC:BB:AA", "random", &addr);
    if (err) {
        printk("Invalid BT address (err %d)\n", err);
    }

    err = bt_id_create(&addr, NULL);
    if (err < 0) {
        printk("Creating new ID failed (err %d)\n", err);
    }

修改广播参数为可连接

c 复制代码
static struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM((BT_LE_ADV_OPT_CONNECTABLE|BT_LE_ADV_OPT_USE_IDENTITY), 
                800, /*Min Advertising Interval 500ms (800*0.625ms) */
                801, /*Max Advertising Interval 500.625ms (801*0.625ms)*/
                NULL); /* Set to NULL for undirected advertising*/

完整代码

相关推荐
小智学长 | 嵌入式4 小时前
SOC-ESP32S3部分:26-物联网MQTT连云
单片机·物联网·esp32
lixzest5 小时前
Keil调试模式下,排查程序崩溃简述
stm32·单片机
极术社区6 小时前
【Mini-F5265-OB开发板试用测评】显示RTC日历时钟
单片机·嵌入式硬件·实时音视频
小智学长 | 嵌入式7 小时前
SOC-ESP32S3部分:31-ESP-LCD控制器库
单片机·物联网·esp32
广药门徒13 小时前
最小硬件系统概念及其组成
单片机·嵌入式硬件
啵啵学习16 小时前
Linux 里 su 和 sudo 命令这两个有什么不一样?
linux·运维·服务器·单片机·ubuntu·centos·嵌入式
可乐鸡翅好好吃18 小时前
通过BUG(prvIdleTask、pxTasksWaitingTerminatio不断跳转问题)了解空闲函数(prvIdleTask)和TCB
c语言·stm32·单片机·嵌入式硬件·bug·keil
才鲸嵌入式19 小时前
01 Ubuntu20.04下编译QEMU8.2.4,交叉编译32位ARM程序,运行ARM程序的方法
linux·c语言·单片机·嵌入式·arm·qemu·虚拟机
广药门徒21 小时前
我认为STM32输入只分为模拟输入 与 数字输入
stm32·单片机·嵌入式硬件
天月风沙1 天前
PX4 | 无人机关闭磁力计罗盘飞行(yaw estimate error报错解决方法)
单片机·嵌入式硬件·mcu·无人机