会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 从零开始手把手教你写一个根据nRF54L15的BLE工程!

从零开始手把手教你写一个根据nRF54L15的BLE工程

时间:2025-05-21 14:08:10 来源:锐评时讯 作者:生活 阅读:514次

最近收到了Nordic最新的旗舰级BLE芯片 n。RF。54L15的开发板,大约研讨了一下,今日教咱们怎样在上面把BLE跑起来。

前语:开发板概览。

1、翻开包装之后里边是用防静电袋包装的开发板和。NFC。天线。,nRF54L15DK的代号是PCA10156,可是nRF54L15的开发板比照nRF52832的开发板来看,nRF54L15的开发板没有再选用Arduion。接口。将IO引出。开发板上用到的。元器件。也少了许多,看下来只用到五颗主芯片。


开发板的JLINK芯片用的是Nordic的nRF5340,JLINK的。USB。口换成了Typc-C口。


电源芯片。用上了Nordic自己的。PMIC。nPM1300。


终究来看一下nRF54L15部分,这儿外挂了一个MXIC 64Mbit的flash,nRF54L15最小体系的元器件也少了许多。


在网上能够找到nRF54L15的材料:

介绍:https://www.nordicsemi.com/Products/nRF54L15。

规格书:https://docs-be.nordicsemi.com/bundle/ps_nrf54L15/att。ac。h/pdf/nRF54L15_nRF54L10_nRF54L05_Datasheet_v0.7.pdf。

硬件规划:https://www.nordicsemi.com/-/media/Software-and-other-downlo。ad。s/Reference-Layouts/nRF54L15/nRF54L15-QFAA-Reference-Layout-0_7.zip。

2、环境建立。

依据我原厂的朋友的说法,新的nRF54L15需求用到NRF Connect。 SD。K去开发,

这儿环境建立能够参阅官方的文档:Installing the nRF Connect SDK (nordicsemi.com)。

最新的文档现已引荐运用nrfu。ti。l来下载SDK了,可是我个人仍是更喜爱用west的办法。

这儿能够参阅我国区原厂FAE的博客:开发你的第一个nRF Connect SDK(NCS)/Zephyr应用程序 - iini - 博客园 (cnblogs.com)。


依照博客中的办法安装好Choco和相关的东西之后,直接履行下面两条指令即可:

west init -m https://github.com/nrfconnect/sdk-nrf --mr v2.9.0。

west update。

nRF54系列的SDK要运用NCS 2.7.0及以上的版别,下载SDK的时分需求留意。

NRF CONNECT SDK现在的编译环境也换成了VS Code + Nordic插件的办法,这儿的编译环境建立也能够参阅上面我国区原厂FAE的博客。


一、在nRF54L15D上运转你的第一个程序。

1、建立好环境之后,首要咱们从SDK中Copy一个Hello World的工程。


2、编译在NRF54L15DK上运转,这儿需求留意NCS2.7.x及以上的版别在编译的时分需求挑选SysBuild。



3、程序编译之后下载到nRF54L15DK中,翻开串口咱们能够看到串口打印如下:

别离是NCS和Zephyr的版别,以及Hello World!和Boards的类型。


4、咱们翻开这个工程的main.c,能够看到这个工程十分简略,便是调用了printf来打印Hello World!和CONFIG_BOARD_TARGET这个宏。


二、增加LOG模块。

上面的Hello World运用了printf来打印,在咱们的程序里边能够调用LOG模块来打印调试日志,这样便利咱们后续在产品量产的时分封闭LOG模块。

1、这儿咱们先在hello_world/prj.conf中下面这些的宏,敞开LOG。

仿制代码。

#Config logger。

CONFIG_LOG=y。

CONFIG_USE_SEGGER_RTT=n。

CONFIG_LOG_BACKEND_RTT=n。

CONFIG_LOG_BACKEND_。UART。=y。

CONFIG_LOG_DEFAULT_LEVEL=3。

仿制代码。

2、在main.c中参加下面这些头文件,调用LOG的库,并注册LOG模组。

仿制代码。

//Add Log Library file。

#include。

#include。

//Register LOG Module。

#define LOG_MODULE_NAME ble_hello_world。

LOG_MODULE_REGISTER(LOG_MODULE_NAME);

仿制代码。

3、这儿咱们提早写一个bluetooth_init的函数,并在bluetooth_init中参加一些LOG信息。

仿制代码。

int bluetooth_init(void)。

{。

int err_code;

LOG_INF("Initiallzing BLE");

err_code = 0;

return err_code;

}。

仿制代码。

4、、在main函数中调用函数 bluetooth_init。

仿制代码。

int main(void)。

{。

int err_code;

err_code = bluetooth_init();

if(err_code){。

LOG_ERR("Bluetooth_init returnrd %d", err_code)。

}。

printf("Hello World! %sn", CONFIG_BOARD_TARGET);

}。

仿制代码。

5、咱们来编译并下载程序到nRF54L15DK中会看到程序进入了bluetooth_init 并在串口打印了LOG:


三、使能协议栈。

1、接下来,咱们需求参加BLE相关的头文件。

//Add BLE Library file。

#include。

#include。

#include。

#include。

2、prj.conf中参加这些宏,敞开BLE相关的宏。

仿制代码。

#Config BLE。

CONFIG_BT=y。

CONFIG_BT_PERIPHERAL=y。

CONFIG_BT_DEVICE_NAME="BLE_Hello_World"。

CONFIG_BT_DEVICE_APPEARANCE=0。

CONFIG_BT_LL_SOFTDEVICE=y。

CONFIG_BT_MAX_CONN=1。

CONFIG_ASSERT=y。

仿制代码。

3、在 bluetooth_init中调用bt_enable,这是一个库函数,这个函数的界说的bluetooth.h中,由于bt_enable只担任调度BLE协议栈的发动,而在履行其他函数之前需求保证协议栈完结了发动,所以咱们要做一个简略判别。

仿制代码。

int bluetooth_init(void)。

{。

int err_code;

err_code = bt_enable(bt_ready_callback);

if(err_code)。

{。

LOG_ERR("BLE Enable returned %d",err_code);

return err_code;

}。

LOG_INF("Initiallzing BLE");

return err_code;

}。

仿制代码。

3、咱们去看一下这个函数的用法,这儿看到bt_enable需求一个回调函数。

仿制代码。

/**。

* brief Enable Bluetooth。

*。

* Enable Bluetooth. Must be the cal。led。before any calls that。

* require communication with the local Bluetooth hardware.。

*。

* When kconfig{CONFIG_BT_SETTINGS} is enabled, the application must load the。

* Bluetooth settings af。te。r this A。PI。call successfully completes before。

* Bluetooth APIs。 can。be used. Lo。adi。ng the settings before calling this function。

* is insufficient. Bluetooth settings can be loaded with settings_load() or。

* settings_load_。sub。tree() with argument "bt". The latter selectively loads only。

* Bluetooth settings and is。 recom。mended if settings_load() has been called。

* earlier.。

*。

* pa。ram。cb Callback to notify completion or NULL to perform the。

* enabling synchronously. The callback is called from the system workqueue.。

*。

* return Zero on success or (negative) error code otherwise.。

*/。

int bt_enable(bt_ready_cb_t cb);

仿制代码。

咱们再去看bt_ready_cb_t这个参数的界说,从这个注释中能够得知这个回调的作用是告诉BLE已使能。

仿制代码。

/**。

* typedef bt_ready_cb_t。

* brief Callback for notifying that Bluetooth has been enabled.。

*。

* param err zero on success or (negative) error code otherwise.。

*/。

typedef void (*bt_ready_cb_t)(int err);

仿制代码。

所以为了保证BLE协议栈现已完结了使能,咱们需求自己写一个回调函数。

仿制代码。

/*BLE Enable Callback function*/。

void bt_ready_callback(int err_code)。

{。

if(err_code)。

{。

LOG_ERR("BLE Enable callback returned %d",err_code);

}。

}。

仿制代码。

4、这儿咱们在bluetooth_init中增加一个。信号。量,等候bt_ready_cb_t告诉协议栈已使能,这儿咱们调用K_SEM_DEFINE初始化一个信号量,并将其计数设为 1、边界设为 1,然后在bluetooth_init中调用k_sem_take()获取这个信号量,由于咱们将计数设置为了1,所以程序会一直在bt_enable()这儿等候协议栈使能完结,当然能够将K_FOREVER设置为一个时间,超时之后程序会继续往下履行。

仿制代码。

static K_SEM_DEFINE(ble_init_ok, 1, 1);

int bluetooth_init(void)。

{。

int err_code;

LOG_INF("Initiallzing BLE");

err_code = bt_enable(bt_ready_callback);

if(err_code)。

{。

LOG_ERR("BLE Enable returned %d",err_code);

return err_code;

}。

k_sem_take(&ble_init_ok, K_FOREVER);return err_code;

}。

仿制代码。

由于这儿咱们要保证BLE协议栈使能完结,所以咱们能够在bt_ready_callback()中开释这个信号量,这样咱们能够经过信号量的同步得知BLE协议栈现已被使能。

仿制代码。

/*BLE Enable Callback function*/。

void bt_ready_callback(int err_code)。

{。

if(err_code)。

{。

LOG_ERR("BLE Enable callback returned %d",err_code);

}。

k_sem_give(&ble_init_ok);

}。

仿制代码。

5、终究咱们编译看一下有什么作用,这儿能够看到BLE协议栈现已被使能,并打印了版别信息等LOG。


四、敞开播送。

使能BLE协议栈之后,咱们接下来要做的便是敞开一个BLE播送。

1、咱们来设置播送包的内容,咱们能够在播送包中参加UUID,这儿咱们能够写一个宏来界说UUID的号码。

/** brief UUID of the Hello World Service. **/。

#define BT_UUID_HOWD_VAL。

BT_UUID_128_ENCODE(0x6e400001, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24。dc。ca9e)。

#define BT_UUID_HOWD_SERVICE BT_UUID_DECLARE_128(BT_UUID_HOWD_VAL)。

2、咱们写一个宏来设置播送称号,这个宏终究调用的是在prj.conf中CONFIG_BT_DEVICE_NAME的值,这儿我的界说是CONFIG_BT_DEVICE_NAME="BLE_Hello_World"。

/*Config BLE Device Name*/。

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME。

#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)。

3、终究咱们把上面的UUID和称号放在播送包数据中,这儿我把UUID放在了Scan response里边。

仿制代码。

/*Config BLE Advertising Data*/。

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),

};

/*Config BLE Scan repsponse Data*/。

static const struct bt_data srd[] = {。

BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_HOWD_VAL),

};

仿制代码。

4、完结播送数据界说之后,咱们就能够在bluetooth_init()中调用bt_le_adv_start()来敞开播送了。

仿制代码。

int bluetooth_init(void)。

{。

int err_code;

LOG_INF("Initiallzing BLE");

bt_conn_cb_register();

err_code = bt_enable(bt_ready_callback);

if(err_code)。

{。

LOG_ERR("BLE Enable returned %d",err_code);

return err_code;

}。

k_sem_take(&ble_init_ok, K_FOREVER);

err_code = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), srd,

ARRAY_SIZE(srd));

if (err_code) {。

LOG_ERR("Advertising failed to start (err_code %d)", err_code);

return 0;

}。

return err_code;

}。

仿制代码。

这儿咱们能够去看一下bt_le_adv_start()这个函数的用法,这是一个库函数,能够在bluetooth.h中找到声明,能够看到这个函数一共有5个入参,别离是。

1)const struct bt_le_adv_param *param,是包含播送周期、播送类型等参数。

2)const struct bt_data *ad, size_t ad_len,别离是播送包数据和播送包的长度。

3)const struct bt_data *sd, size_t sd_len,别离是扫描呼应包数据和扫描呼应包的长度。

1/**。

2* brief Start advertising。

3*。

4* Set advertisement data, scan response data, advertisement paramete。rs。

5* and start advertising.。

6*。

7* When the advertisement parameter peer address has been set the advertising。

8* will be directed to the peer. In this case advertisement data and scan。

9* response data parameters are ignored. If the mode is high duty cycle。

10* the timeout will be ref BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT.。

11*。

12* This function cannot be used with ref BT_LE_ADV_OPT_EXT_ADV in the p param.options.。

13* For extended advertising, the bt_le_ext_adv_* functions must be used.。

14*。

15* param param Advertising parameters.。

16* param ad Data to be used in advertisement packets.。

17* param ad_len Number of elements in ad。

18* param sd Data to be used in scan response packets.。

19* param sd_len Number of elements in sd。

20*。

21* return Zero on success or (negative) error code otherwise.。

22* return -ENOMEM No free connection objects av。ai。lable for connectable。

23* advertiser.。

24* return -ECONNREFUSED When connectable advertising is requested and there。

25* is already。 maxim。um number of connections established。

26* in the controller.。

27* This error code is only guaranteed when using Zephyr。

28* controller, for other controllers code returned in。

29* this case may be -EIO.。

30*/。

31intbt_le_adv_start(conststructbt_le_adv_param *param,

32conststructbt_data *ad, size_t ad_len,

33 conststructbt_data *sd, size_t sd_len);

在上面的代码中,播送参数也调用了一个现成的宏,这个宏在bluetooth.h中能够找到,在这个宏里边能够看到参数主义是界说了播送类型为可衔接播送,快速播送的最小周期和最大周期。此外播送包中还界说了一下flag等,感兴趣的读者能够自行去看下面这几个宏。

BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)。

#define BT_LE_ADV_CONN BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE,

BT_GAP_ADV_FAST_INT_MIN_2,

BT_GAP_ADV_FAST_INT_MAX_2, NULL)。

仿制代码。

#define BT_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */。

#define BT_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */。

/**。

* brief Advertise as connectable.。

*。

* Advertise as connectable. If not connectable then the type of。

* advertising is determined by providing scan response data.。

* The advertiser address is determined by the type of advertising。

* and/or enabling privacy kconfig{CONFIG_BT_PRIVACY}.。

*/。

BT_LE_ADV_OPT_CONNECTABLE = BIT(0),

仿制代码。

此外bluetooth.h中除了BT_LE_ADV_CONN BT_LE_ADV_PARAM之外,还有其他好多个播送参数,感兴趣的读者能够去看看其他的宏别离界说了一些什么。

5、终究咱们编译工程来看一下有什么作用,咱们能够运用nRF Connect app去检查一下播送数据。



6、操练:假如你了解nRF5 SDK,你会发现在NCS上界说个播送参数和播送数据会比nRF5 SDK上要简略,不需求去写参数很多的指针变量,乃至能够直接用现成界说好的宏,许多参数乃至能够直接在prj.conf中界说即可,这大大减少了代码开发的工作量。这儿感兴趣的读者能够去自行修正Appearance,这个参数能够经过下面这个宏来界说,修正这个宏的值然后在nRF Connect app的播送设备的图标会呈现改变,SIG界说了一些规范详细的值,例如心率设备、HID设备等,详细去SIG这个网站查询:https://www.bluetooth.com/specifications/assigned-numbers。

CONFIG_BT_DEVICE_APPEARANCE=0。

五、BLE的衔接回调。

在nRF5 SDK中BLE初始化的时分会注册一个回调函数ble_evt_handler来处理BLE衔接、断开衔接、更新PHY、Timeout等时分的中止事情。

仿制代码。

/*nRF5 SDK中的BLE中止事情*/。

/**brief Function for handling BLE events.。

*。

* param[in] p_ble_evt Bluetooth stack event.。

* param[in] p_context Unused.。

*/。

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)。

{。

uint32_t err_code;

switch (p_ble_evt->header.evt_id)。

{。

case BLE_GAP_EVT_CONNECTED:。

NRF_LOG_INFO("Connected");

err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);

APP_ERROR_CHECK(err_code);

m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);

APP_ERROR_CHECK(err_code);

break;

case BLE_GAP_EVT_DISCONNECTED:。

NRF_LOG_INFO("Disconnected");

// LED indication will be changed when advertising starts.。

m_conn_handle = BLE_CONN_HANDLE_INVALID;

break;

case BLE_GAP_EVT_PHY_UPDATE_REQUEST:。

{。

NRF_LOG_DEBUG("PHY update request.");

ble_gap_phys_t const phys =。

{。

.rx_phys = BLE_GAP_PHY_AUTO,

.tx_phys = BLE_GAP_PHY_AUTO,

};

err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);

APP_ERROR_CHECK(err_code);

} break;

case BLE_GAP_EVT_SEC_PARAMS_REQUEST:。

// Pairing not supported。

err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);

APP_ERROR_CHECK(err_code);

break;

case BLE_GATTS_EVT_SYS_ATTR_MISSING:。

// No system attributes have been stored.。

err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);

APP_ERROR_CHECK(err_code);

break;

case BLE_GATTC_EVT_TIMEOUT:。

// Disconnect on GATT Client timeout event.。

err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,

BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);

APP_ERROR_CHECK(err_code);

break;

case BLE_GATTS_EVT_TIMEOUT:。

// Disconnect on GATT Server timeout event.。

err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,

BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);

APP_ERROR_CHECK(err_code);

break;

default:。

// No implementation needed.。

break;

}。

}。

仿制代码。

在NCS中,咱们也能够这样来做,这个章节咱们将演示如安在衔接和断开衔接的时分,打印LOG和点亮平息DK的LED1。

1、首要咱们在bluetooth_init()参加一个回调注册函数bt_conn_cb_register(),这个函数在conn.h,咱们来看一下这个函数的声明,能够看到这个函数的首要作用便是注册一个callback用来在衔接状态下监控相关事情。

仿制代码。

/** brief Register connection callbacks.。

*。

* Register callbacks to monitor the state of connections.。

*。

* param cb Callback struct. Must point to memory that remains valid.。

*。

* retval 0 Success.。

* retval -EEXIST if p cb was already registered.。

*/。

int bt_conn_cb_register(struct bt_conn_cb *cb);

仿制代码。

从注释中咱们能够看到这个函数需求输入 struct bt_conn_cb *cb 这个结构体作为入参,这个结构体的声明也在conn.h中,咱们去看一下这个结构体的注释,能够看到这个结构体中给出的相关BLE回调函数是和nRF5 SDK中给出的case是类似的,感兴趣的读者能够自行检查注释来进一步做比照。

仿制代码。

/** brief Connection callback structure.。

*。

* This structure is used for tracking the state of a connection.。

* It is registered with the help of the bt_conn_cb_register() API.。

* It's permissible to register multiple instances of this ref bt_conn_cb。

* type, in case different modules of an application are interested in。

* tracking the connection state. If a callback is not of interest for。

* an instance, it may be set to NULL and will as a consequence not be。

* used for that instance.。

*/。

struct bt_conn_cb {。

/** brief A new connection has been established.。

*。

* This callback notifies the application of a new connection.。

* In case the err parameter is non-zero it means that the。

* connection establishment failed.。

*。

* note If the connection was established from an advertising set then。

* the advertising set cannot be restarted directly from this。

* callback. Instead use the connected callback of the。

* advertising set.。

*。

* param conn New connection object.。

* param err HCI error. Zero for success, non-zero otherwise.。

*。

* p err can mean either of the following:。

* - ref BT_HCI_ERR_UNKNOWN_CONN_ID Creating the connection started by。

* ref bt_conn_le_create was canceled either by the user through。

* ref bt_conn_disconnect or by the timeout in the host through。

* ref bt_conn_le_create_param timeout parameter, which defaults to。

* kconfig{CONFIG_BT_CREATE_CONN_TIMEOUT} seconds.。

* - p BT_HCI_ERR_ADV_TIMEOUT High duty cycle directed connectable。

* advertiser started by ref bt_le_adv_start failed to be connected。

* within the timeout.。

*/。

void (*connected)(struct bt_conn *conn, uint8_t err);

/** brief A connection has been disconnected.。

*。

* This callback notifies the application that a connection。

* has been disconnected.。

*。

* When this callback is called the stack still has one reference to。

* the connection object. If the application in this callback tries to。

* start either a connectable advertiser or create a new connection。

* this might fail because there are no free connection objects。

* available.。

* To avoid this issue it is recommended to either start connectable。

* advertise or create a new connection using ref k_work_submit or。

* increase kconfig{CONFIG_BT_MAX_CONN}.。

*。

* param conn Connection object.。

* param reason BT_HCI_ERR_* reason for the disconnection.。

*/。

void (*disconnected)(struct bt_conn *conn, uint8_t reason);

/** brief A connection object has been returned to the pool.。

*。

* This callback notifies the application that it might be able to。

* allocate a connection object. No guarantee, first come, first serve.。

*。

* Use this to e.g. re-start connectable advertising or scanning.。

*。

* Treat this callback as an ISR, as it originates from。

* ref bt_conn_unref which is used by the BT stack. Making。

* Bluetooth API calls in this context is error-prone and strongly。

* discouraged.。

*/。

void (*recycled)(void);

/** brief LE connection parameter update request.。

*。

* This callback notifies the application that a remote device。

* is requesting to update the connection parameters. The。

* application accepts the parameters by returning true, or。

* rejects them by returning false. Before accepting, the。

* application may also adjust the parameters to better suit。

* its needs.。

*。

* It is recommended for an application to have just one of these。

* callbacks for。 sim。plicity. However, if an application registers。

* multiple it needs to manage the potentially different。

* requirements for each callback. Each callback gets the。

* parameters as returned by previous callbacks, i.e. they are not。

* necessarily the same ones as the remote originally sent.。

*。

* If the application does not have this callback then the default。

* is to accept the parameters.。

*。

* param conn Connection object.。

* param param Proposed connection parameters.。

*。

* return true to accept the parameters, or false to reject them.。

*/。

bool (*le_param_req)(struct bt_conn *conn,

struct bt_le_conn_param *param);

/** brief The parameters for an LE connection have been updated.。

*。

* This callback notifies the application that the connection。

* parameters for an LE connection have been updated.。

*。

* param conn Connection object.。

* param interval Connection interval.。

* param latency Connection latency.。

* param timeout Connection supervision timeout.。

*/。

void (*le_param_updated)(struct bt_conn *conn, uint16_t interval,

uint16_t latency, uint16_t timeout);

#if defined(CONFIG_BT_SMP)。

/** brief Remote Identity Address has been resolved.。

*。

* This callback notifies the application that a remote。

* Identity Address has been resolved。

*。

* param conn Connection object.。

* param rpa Resolvable Private Address.。

* param identity Identity Address.。

*/。

void (*identity_resolved)(struct bt_conn *conn,

const bt_addr_le_t *rpa,

const bt_addr_le_t *identity);

#endif /* CONFIG_BT_SMP */。

#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CLASSIC)。

/** brief The security level of a connection has changed.。

*。

* This callback notifies the application that the security of a。

* connection has changed.。

*。

* The security level of the connection can either have been increased。

* or remain unchanged. An increased security level means that the。

* pairing procedure has been performed or the bond information from。

* a previous connection has been applied. If the security level。

* remains unchanged this means that the encryption key has been。

* refreshed for the connection.。

*。

* param conn Connection object.。

* param level New security level of the connection.。

* param err Security error. Zero for success, non-zero otherwise.。

*/。

void (*security_changed)(struct bt_conn *conn, bt_security_t level,

enum bt_security_err err);

#endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CLASSIC) */。

#if defined(CONFIG_BT_REMOTE_INFO)。

/** brief Remote information procedures has completed.。

*。

* This callback notifies the application that the remote information。

* has been retrieved from the remote peer.。

*。

* param conn Connection object.。

* param remote_info Connection information of remote device.。

*/。

void (*remote_info_available)(struct bt_conn *conn,

struct bt_conn_remote_info *remote_info);

#endif /* defined(CONFIG_BT_REMOTE_INFO) */。

#if defined(CONFIG_BT_USER_PHY_UPDATE)。

/** brief The PHY of the connection has changed.。

*。

* This callback notifies the application that the PHY of the。

* connection has changed.。

*。

* param conn Connection object.。

* param info Connection LE PHY information.。

*/。

void (*le_phy_updated)(struct bt_conn *conn,

struct bt_conn_le_phy_info *param);

#endif /* defined(CONFIG_BT_USER_PHY_UPDATE) */。

#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)。

/** brief The data length parameters of the connection has changed.。

*。

* This callback notifies the application that the maximum Link Layer。

* payload length or transmission time has changed.。

*。

* param conn Connection object.。

* param info Connection data length information.。

*/。

void (*le_data_len_updated)(struct bt_conn *conn,

struct bt_conn_le_data_len_info *info);

#endif /* defined(CONFIG_BT_USER_DATA_LEN_UPDATE) */。

#if defined(CONFIG_BT_DF_CONNECTION_CTE_RX)。

/** brief Callback for IQ samples report collected when sampling。

* CTE received by data channel PDU.。

*。

* param conn The connection object.。

* param iq_report Report data for collected IQ samples.。

*/。

void (*cte_report_cb)(struct bt_conn *conn,

const struct bt_df_conn_iq_samples_report *iq_report);

#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */。

#if defined(CONFIG_BT_TRANSMIT_POWER_CONTROL)。

/** brief LE Read Remote Transmit Power Level procedure has completed or LE。

* Transmit Power Reporting event.。

*。

* This callback notifies the application that either the remote transmit power level。

* has been read from the peer or transmit power level has changed for the local or。

* remote controller when transmit power reporting is enabled for the respective side。

* using ref bt_conn_le_set_tx_power_report_enable.。

*。

* param conn Connection object.。

* param report Transmit power report.。

*/。

void (*tx_power_report)(struct bt_conn *conn,

const struct bt_conn_le_tx_power_report *report);

#endif /* CONFIG_BT_TRANSMIT_POWER_CONTROL */。

#if defined(CONFIG_BT_PATH_LOSS_MONITORING)。

/** brief LE Path Loss Threshold event.。

*。

* This callback notifies the application that there has been a path loss threshold。

* c。ros。sing or reporting the initial path loss threshold zone after using。

* ref bt_conn_le_set_path_loss_mon_enable.。

*。

* param conn Connection object.。

* param report Path loss threshold report.。

*/。

void (*path_loss_threshold_report)(struct bt_conn *conn,

const struct bt_conn_le_path_loss_threshold_report *report);

#endif /* CONFIG_BT_PATH_LOSS_MONITORING */。

#if defined(CONFIG_BT_SUBRATING)。

/** brief LE Subrate Changed event.。

*。

* This callback notifies the application that the subrating parameters。

* of the connection may have changed.。

* The connection subrating parameters will be unchanged。

* if status is not BT_HCI_ERR_SUCCESS.。

*。

* param conn Connection object.。

* param params New subrating parameters.。

*/。

void (*subrate_changed)(struct bt_conn *conn,

const struct bt_conn_le_subrate_changed *params);

#endif /* CONFIG_BT_SUBRATING */。

#if defined(CONFIG_BT_CHANNEL_SOUNDING)。

/** brief LE CS Read Remote Supported Capabilities Complete event.。

*。

* This callback notifies the application that the remote channel。

* sounding capabilities have been received from the peer.。

*。

* param conn Connection object.。

* param remote_cs_capabilities Remote Channel Sounding Capabilities.。

*/。

void (*le_cs_remote_capabilities_available)(struct bt_conn *conn,

struct bt_conn_le_cs_capabilities *params);

/** brief LE CS Read Remote FAE Table Complete event.。

*。

* This callback notifies the application that the remote mode-0。

* FAE Table has been received from the peer.。

*。

* param conn Connection object.。

* param params FAE Table.。

*/。

void (*le_cs_remote_fae_table_available)(struct bt_conn *conn,

struct bt_conn_le_cs_fae_table *params);

/** brief LE CS Config created.。

*。

* This callback notifies the application that a Channel Sounding。

* Configuration procedure has completed and a new CS config is created。

*。

* param conn Connection object.。

* param config CS configuration.。

*/。

void (*le_cs_config_created)(struct bt_conn *conn, struct bt_conn_le_cs_config *config);

/** brief LE CS Config removed.。

*。

* This callback notifies the application that a Channel Sounding。

* Configuration procedure has completed and a CS config is removed。

*。

* param conn Connection object.。

* param config_id ID of the CS configuration that was removed.。

*/。

void (*le_cs_config_removed)(struct bt_conn *conn, uint8_t config_id);

/** brief Subevent Results from a CS procedure are available.。

*。

* This callback notifies the user that CS subevent results are。

* available for the given connection object.。

*。

* param conn Connection objects.。

* param result Subevent results。

*/。

void (*le_cs_subevent_data_available)(struct bt_conn *conn,

struct bt_conn_le_cs_subevent_result *result);

/** brief LE CS Security Enabled.。

*。

* This callback notifies the application that a Channel Sounding。

* Security Enable procedure has completed。

*。

* param conn Connection object.。

*/。

void (*le_cs_security_enabled)(struct bt_conn *conn);

/** brief LE CS Procedure Enabled.。

*。

* This callback notifies the application that a Channel Sounding。

* Procedure Enable procedure has completed。

*。

* param conn Connection object.。

* param params CS Procedure Enable parameters。

*/。

void (*le_cs_procedure_enabled)(。

struct bt_conn *conn, struct bt_conn_le_cs_procedure_enable_complete *params);

#endif。

/** internal Internally used field for list handling */。

sys_snode_t _node;

};

仿制代码。

2、这儿咱们仍是来演示怎么运用CONNECT和DISCONNECT这两个回调来在BLE断开和衔接的时分处理相关使命。首要咱们来写一个结构体ble_connection_callback ,这个结构体里边包含两个函数ble_on_connected和ble_on_connected。

struct bt_conn_cb ble_connection_callback = {。

.connected = ble_on_connected,

.disconnected = ble_on_disconnected,

};

这儿咱们需求调用bt_conn_get_dst这个函数来获取对端设备的MAC地址,并调用bt_addr_le_to_str将获取到的地址转成字符串用于打印。

仿制代码。

/** brief Get destination (peer) address of a connection.。

*。

* param conn Connection object.。

*。

* return Destination address.。

*/。

const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn);

/** brief Converts binary LE Bluetooth address to string.。

*。

* param addr Address of buffer containing binary LE Bluetooth address.。

* param str Address of user buffer with enough room to store。

* formatted string containing binary LE address.。

* param len Length of data to be copied to user string buffer. Refer to。

* BT_ADDR_LE_STR_LEN about recommended value.。

*。

* return Number of successfully formatted bytes from binary address.。

*/。

static inline int bt_addr_le_to_str(const bt_addr_le_t *addr, char *str,

size_t len)。

仿制代码。

在衔接和断开反常的时分咱们还能够调用bt_hci_err_to_str来获取相关的错误代码。

仿制代码。

/** Converts a HCI error to string.。

*。

* The error codes are described in the Bluetooth Core specification,

* Vol 1, Part F, Section 2.。

*。

* The HCI documentation found in Vol 4, Part E,

* describes when the different error codes are used.。

*。

* See also the defined BT_HCI_ERR_* macros.。

*。

* return The string representation of the HCI error code.。

* If kconfig{CONFIG_BT_HCI_ERR_TO_STR} is not enabled,

* this just returns the empty string。

*/。

#if defined(CONFIG_BT_HCI_ERR_TO_STR)。

const char *bt_hci_err_to_str(uint8_t hci_err);

#else。

static inline const char *bt_hci_err_to_str(uint8_t hci_err)。

仿制代码。

终究调用dk_set_led_on和dk_set_led_off来点亮和平息nRF54L15 DK的LED1。

3、接下来咱们来写ble_on_connected和ble_on_connected这两个回调函数。

仿制代码。

static void ble_on_connected(struct bt_conn *conn, uint8_t err)。

{。

char addr[BT_ADDR_LE_STR_LEN];

/*Print err code when the connection is error*/。

if (err) {。

LOG_ERR("Connection failed, err 0x%02x %s", err, bt_hci_err_to_str(err));

return;

}。

/*Print the MAC address of Central Deevice*/。

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

LOG_INF("Connected %s", addr);

/*Count the coennection*/。

current_conn = bt_conn_ref(conn);

dk_set_led_on(DK_LED1)。

);

}。

仿制代码。

仿制代码。

static void ble_on_disconnected(struct bt_conn *conn, uint8_t reason)。

{。

char addr[BT_ADDR_LE_STR_LEN];

/*Get the MAC address of central and print it when the connection is disconnected*/。

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

LOG_INF("Disconnected: %s, reason 0x%02x %s", addr, reason, bt_hci_err_to_str(reason));

/*Decrement a connection's reference count and off LED1 of DK*/。

if (current_conn) {。

bt_conn_unref(current_conn);

current_conn = NULL;

dk_set_led_off(DK_LED1);

}。

}。

仿制代码。

这儿咱们引入了一个全局变量current_conn用于计数已衔接的设备数量,所以需求做一个声明。

static struct bt_conn *current_conn;

此外咱们调用了LED1这个外设用来指示BLE的衔接状况,所以咱们还需求在main中初始化LED1这个外设,这儿咱们需求参加一些头文件并在prj.conf中使能相关的宏,终究在main中调用configure_gpio。

//Add LED and Button drivers Library file。

#include。

# Enable DK LED and Buttons library。

CONFIG_DK_LIBRARY=y。

CONFIG_GPIO=y。

仿制代码。

static void configure_gpio(void)。

{。

int err_code;

err_code = dk_leds_init();

if (err_code) {。

LOG_ERR("Cannot init LEDs (err: %d)", err_code);

}。

}。

仿制代码。

4、完结上述过程之后,咱们将ble_connection_callback这个函数注册到bluetooth_init中。

仿制代码。

int bluetooth_init(struct bt_conn_cb *ble_cb)。

{。

int err_code;

LOG_INF("Initiallzing BLE");

if (ble_cb == NULL)。

{。

return -NRFX_ERROR_NULL;

}。

bt_conn_cb_register(ble_cb);

err_code = bt_enable(bt_ready_callback);

if(err_code)。

{。

LOG_ERR("BLE Enable returned %d",err_code);

return err_code;

}。

k_sem_take(&ble_init_ok, K_FOREVER);

err_code = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), srd,

ARRAY_SIZE(srd));

if (err_code) {。

LOG_ERR("Advertising failed to start (err_code %d)", err_code);

return 0;

}。

return err_code;

}。

仿制代码。

仿制代码。

int main(void)。

{。

int err_code;

configure_gpio();

err_code = bluetooth_init(&ble_connection_callback);

if(err_code)。

{。

LOG_ERR("Bluetooth_init returnrd %d", err_code);

}。

printf("Hello World! %sn", CONFIG_BOARD_TARGET);

}。

仿制代码。

5、终究咱们编译下载工程到nRF54L15的DK中,运用nRF Connect APP衔接能够看到衔接和断开之后别离打印了。手机。端的MAC地址。


一起DK的LED1在衔接之后常亮。


六、增加一个Service。

1、从上面的图片中能够看到,APP衔接nRF54L15 DK之后只要一些通用的Service,这一步咱们来演示怎么增加一个自界说的Service,在nRF5 SDK中咱们需求在service_init中初始化给相关的指针写入值,但在NCS中咱们能够直接调用BT_GATT_SERVICE_DEFINE来完结。

仿制代码。

/**。

* brief Statically define and register a service.。

*。

* Helper macro to statically define and register a service.。

*。

* param _name Service name.。

*/。

#define BT_GATT_SERVICE_DEFINE(_name, ...)。

const struct bt_gatt_attr attr_##_name[] = { __VA_ARGS__ };

const STRUCT_SECTION_ITERABLE(bt_gatt_service_static, _name) =。

BT_GATT_SERVICE(attr_##_name)。

#define _BT_GATT_ATTRS_ARRAY_DEFINE(n, _instances, _attrs_def)。

static struct bt_gatt_attr attrs_##n[] = _attrs_def(_instances[n])。

#define _BT_GATT_SERVICE_ARRAY_ITEM(_n, _) BT_GATT_SERVICE(attrs_##_n)。

仿制代码。

2、这儿我直接用了NUS服务的UUID,当然你能够自己界说一个UUID看一下有什么作用。

仿制代码。

/** brief UUID of the NUS Service. **/。

#define BT_UUID_HOWD_VAL。

BT_UUID_128_ENCODE(0x6e400001, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)。

#define BT_UUID_HOWD_SERVICE BT_UUID_DECLARE_128(BT_UUID_HOWD_VAL)。

#define SERVICE_NAME nus_svc。

BT_GATT_SERVICE_DEFINE(SERVICE_NAME,

BT_GATT_PRIMARY_SERVICE(BT_UUID_HOWD_SERVICE)。

);

仿制代码。

3、终究编译一下工程下载的nRF54L15DK,并运用nRF Connect APP衔接中能够看到多了一个NUS服务。


七、增加特征值并界说其特点。

1、完结上述过程之后,BLE多了一个Service,可是这个Service中没有Characteristic(特征值),这儿咱们还能够在BT_GATT_SERVICE_DEFINE中调用BT_GATT_CHARACTERISTIC,将特征值放在Service下面,这个结构就像APP上Service下面有特征值那样,十分直观。这儿咱们去看一下BT_GATT_CHARACTERISTIC,会发现它一共有6个入参。

1)_uuid是特征值的UUID。

2)_props是特征值的特点,比方:read,write,Notify,indicate等。

3)_perm是特点的拜访权限,比方:一般、加密、配对等。

4)_read、_write是别离是读取和写入的回调函数。

5)_user_data是留给用户自界说的一些数据,一般不必。

仿制代码。

/**。

* brief Characteristic and Value Declaration Macro.。

*。

* Helper macro to declare a characteristic attribute along with its。

* attribute value.。

*。

* param _uuid Characteristic attribute uuid.。

* param _props Characteristic attribute properties,

* a bitmap of ``BT_GATT_CHRC_*`` macros.。

* param _perm Characteristic Attribute access permissions,

* a bitmap of ref bt_gatt_perm values.。

* param _read Characteristic Attribute read callback。

* (ref bt_gatt_attr_read_func_t).。

* param _write Characteristic Attribute write callback。

* (ref bt_gatt_attr_write_func_t).。

* param _user_data Characteristic Attribute user data.。

*/。

#define BT_GATT_CHARACTERISTIC(_uuid, _props, _perm, _read, _write, _user_data)。

BT_GATT_ATTRIBUTE(BT_UUID_GATT_CHRC, BT_GATT_PERM_READ,

bt_gatt_attr_read_chrc, NULL,

((struct bt_gatt_chrc[]) {。

BT_GATT_CHRC_INIT(_uuid, 0U, _props),

})),

BT_GATT_ATTRIBUTE(_uuid, _perm, _read, _write, _user_data)。

仿制代码。

2、这儿由于咱们这个特征值的特点是Read,所以咱们需求在写一个回调,在里边将Button的键值经过GATT接口发送出去,这需求用到一个库函数bt_gatt_attr_read,这个函数的声明在gatt.h中,能够看到这个函数的作用是将本地数据经过Read特点上传。

仿制代码。

/** brief Generic Read Attribute value helper.。

*。

* Read attribute value from local database storing the result into buffer.。

*。

* param conn Connection object.。

* param attr Attribute to read.。

* param buf Buffer to store the value.。

* param buf_len Buffer length.。

* param offset Start offset.。

* param value Attribute value.。

* param value_len Length of the attribute value.。

*。

* return number of bytes read in case of success or negative values in。

* case of error.。

*/。

ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,

void *buf, uint16_t buf_len, uint16_t offset,

const void *value, uint16_t value_len);

仿制代码。

3、咱们来尝试加一个Read特点的特征值,读取按键DK上按下的Button的键值,从BT_GATT_CHARACTERISTIC的注释中能够看到,要运用这个宏需求写一个回调函数,首要来声明以下这个回调函数,并将bt_gatt_attr_read的入参作为回调函数的入参。

ssize_t read_button_characteristic_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,

void *buf, uint16_t len, uint16_t offset);

这个函数的实践功用是在Read这个特征值的时分,将键值上传给GATT,所以咱们来界说一个全局变量来获取button的键值。

static uint8_t button_value = 0;

然后将button_value经过bt_gatt_attr_read上传给GATT。

仿制代码。

ssize_t read_button_characteristic_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,

void *buf, uint16_t len, uint16_t offset)。

{。

return bt_gatt_attr_read(conn, attr, buf, len, offset, &button_value, sizeof(button_value));

}。

仿制代码。

4、将这个回调放入BT_GATT_CHARACTERISTIC中,并写入这个Read特征值的特点等相关装备。

这儿的特征值的UUID我用了NUS服务TX的特征值;

BT_GATT_CHRC_READ表明特征值的特点是Read。

BT_GATT_PERM_READ表明特征值的拜访权限为一般读取。

读取的回调运用咱们写好的read_button_characteristic_cb这个函数。

由于这个特征值仅仅Read特点,所以不需求Write的回调,也不需求用户自界说数据,所以终究两个入参填写为NULL。

仿制代码。

#define BT_UUID_NUS_TX_VAL。

BT_UUID_128_ENCODE(0x6e400003, 0xb5a3, 0xf393, 0xe0a9, 0xe50e24dcca9e)。

#define BT_UUID_NUS_TX BT_UUID_DECLARE_128(BT_UUID_NUS_TX_VAL)。

BT_GATT_SERVICE_DEFINE(SERVICE_NAME,

BT_GATT_PRIMARY_SERVICE(BT_UUID_NUS_SERVICE),

BT_GATT_CHARACTERISTIC(BT_UUID_NUS_TX,

BT_GATT_CHRC_READ,

BT_GATT_PERM_READ,

read_button_characteristic_cb, NULL, NULL),

);

仿制代码。

GATT的特点和权限除了上述两个参数之外,还有其他类型,感兴趣的读者详细能够去gatt.h中检查相关注释阐明。

5、至此咱们现已完结了BLE数据上传部分的代码编写,接下来咱们来读取Button的键值,并将这个值给到全局变量button_value即可。这儿咱们写一个函数来传递button的键值。

void set_button_value(uint8_t btn_value)。

{。

button_value = btn_value;

}。

咱们还需求经过GPIO外设来读取键值,和点亮LED相同,需求先将DK的Button初始化,这儿要调用dk_buttons_init来完结,它是一个库函数,函数声明在dk_buttons_and_leds.h中。

仿制代码。

/** brief Initialize the library to read the button state.。

*。

* param button_handler Callback handler for button state changes.。

*。

* retval 0 If the operation was successful.。

* Otherwise, a (negative) error code is returned.。

*/。

int dk_buttons_init(button_handler_t button_handler);

/**。

* typedef button_handler_t。

* brief Callback that is executed when a button state change is detected.。

*。

* param button_state Bitmask of button states.。

* param has_changed Bitmask that shows which buttons have changed.。

*/。

typedef void (*button_handler_t)(uint32_t button_state, uint32_t has_changed);

仿制代码。

从注释能够看到这个函数需求一个button的回调函数,用于处理button时分的中止。咱们来写这个回调,在里边处理不同按键按下之后,界说不同的键值,并经过LOG打印键值,终究调用set_button_value将键值传递给全局变量button_value。

仿制代码。

void button_handler(uint32_t button_state, uint32_t has_changed)。

{。

int button_pressed = 0;

if (has_changed & button_state) {。

if (DK_BTN1_MSK & has_changed) {。

button_pressed = 1;

}。

if (DK_BTN2_MSK & has_changed) {。

button_pressed = 2;

}。

if (DK_BTN3_MSK & has_changed) {。

button_pressed = 3;

}。

if (DK_BTN4_MSK & has_changed) {。

button_pressed = 4;

}。

LOG_INF("Button %d pressed", button_pressed);

set_button_value(button_pressed);

}。

}。

仿制代码。

终究在GPIO初始化里边调用dk_buttons_init并写入回调函数button_handler即可。

仿制代码。

static void configure_gpio(void)。

{。

int err_code;

err_code = dk_buttons_init(button_handler);

if (err_code) {。

LOG_ERR("Cannot init buttons (err: %d)", err_code);

}。

err_code = dk_leds_init();

if (err_code) {。

LOG_ERR("Cannot init LEDs (err: %d)", err_code);

}。

}。

仿制代码。

6、终究编译工程,并运用nRF Connect APP衔接nRF54L15DK的播送,能够看到NUS Service下多了一个Read特点,当咱们按下DK上的Button的时分,能够读取到对应的键值。




继续未完........。

上一篇:nRF Connect SDK(NCS)/Zephyr固件晋级详解 – 要点叙述。MCU。boot和。蓝牙。空中晋级。

审阅修改 黄宇。

内容来源:https://sonybravia.xyz/app-1/m99 online casino,http://chatbotjud.saude.mg.gov.br/app-1/jogo-pc-torrent

(责任编辑:社会)

    系统发生错误

    系统发生错误

    您可以选择 [ 重试 ] [ 返回 ] 或者 [ 回到首页 ]

    [ 错误信息 ]

    页面发生异常错误,系统设置开启调试模式后,刷新本页查看具体错误!