Zephyr框架下NRF52840中心设备NUS通信配置问题求助
问题分析与修复方案
你使用Zephyr的peripheral_nus示例作为外设,能和手机NUS终端正常通信,但自制的中心设备连接外设后无法交换消息,核心问题在于中心设备的NUS客户端未完成GATT服务发现,且发送逻辑存在错误。以下是具体问题点和修复方案:
核心问题点
- 未执行NUS服务发现:中心作为NUS客户端,必须先定位外设的NUS服务(UUID 0xFFE0)及其TX/RX特征,否则无法找到通信的特征句柄,直接调用
bt_nus_send会失效。 bt_nus_send参数错误:第一个参数不能传NULL,需要传入绑定了NUS服务的客户端实例,而非空指针。- 重复注册回调:
main函数和connected回调中重复调用bt_nus_cb_register,属于冗余操作且可能引发冲突。 - 语法错误:
main函数存在多余的闭合花括号},会导致编译失败。 - 发送时机过早:连接建立后立即发送消息,此时GATT服务尚未完成发现,发送必然失败。
修复后的中心设备代码
#include <zephyr/types.h> #include <stddef.h> #include <errno.h> #include <zephyr/kernel.h> #include <zephyr/sys/printk.h> #include <zephyr/bluetooth/services/nus.h> #include <string.h> #include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/hci.h> #include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/uuid.h> #include <zephyr/bluetooth/gatt.h> #include <zephyr/sys/byteorder.h> #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) static void start_scan(void); static struct bt_conn *default_conn; static struct bt_nus_client nus_client; // 新增NUS客户端实例 static const bt_addr_le_t peripheral_addr = { .type = BT_ADDR_LE_RANDOM, .a.val = {0xC8, 0xF8, 0x6C, 0x27, 0xEB, 0x10} }; // NUS客户端回调函数 static void nus_notif_enabled(bool enabled, void *ctx) { ARG_UNUSED(ctx); printk("%s() - %s\n", __func__, (enabled ? "Enabled" : "Disabled")); } static void nus_received(struct bt_conn *conn, const void *data, uint16_t len, void *ctx) { char message[CONFIG_BT_L2CAP_TX_MTU + 1] = ""; ARG_UNUSED(conn); ARG_UNUSED(ctx); memcpy(message, data, MIN(sizeof(message) - 1, len)); printk("%s() - Len: %d, Message: %s\n", __func__, len, message); } static void nus_connected(struct bt_nus_client *client, uint8_t err) { if (err) { printk("NUS client connected failed (err %d)\n", err); return; } printk("NUS client connected successfully\n"); } static void nus_disconnected(struct bt_nus_client *client, uint8_t reason) { printk("NUS client disconnected (reason 0x%02x)\n", reason); } // NUS客户端回调结构体 static const struct bt_nus_client_cb nus_client_cb = { .notif_enabled = nus_notif_enabled, .received = nus_received, .connected = nus_connected, .disconnected = nus_disconnected, }; static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { char addr_str[BT_ADDR_LE_STR_LEN]; int err; if (default_conn) { return; } if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { return; } bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); printk("Device found: %s (RSSI %d)\n", addr_str, rssi); if (rssi < -50) { return; } if (bt_le_scan_stop()) { return; } err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn); if (err) { printk("Create conn to %s failed (%d)\n", addr_str, err); start_scan(); } } static void start_scan(void) { int err; err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found); if (err) { printk("Scanning failed to start (err %d)\n", err); return; } printk("Scanning successfully started\n"); } static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; int ret; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (err) { printk("Failed to connect to %s (%u)\n", addr, err); bt_conn_unref(default_conn); default_conn = NULL; start_scan(); return; } if (conn != default_conn) { return; } printk("Connected: %s\n", addr); // 绑定NUS客户端到当前连接,自动执行服务发现 ret = bt_nus_client_connect(conn, &nus_client, &nus_client_cb); if (ret) { printk("Failed to connect NUS client: %d\n", ret); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; if (conn != default_conn) { return; } bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); bt_conn_unref(default_conn); default_conn = NULL; start_scan(); } BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = connected, .disconnected = disconnected, }; int main(void) { int err; printk("Initialization begin\n"); err = bt_enable(NULL); if (err) { printk("Bluetooth init failed (err %d)\n", err); return 0; } printk("Bluetooth initialized\n"); start_scan(); // 初始化NUS客户端 err = bt_nus_client_init(&nus_client); if (err) { printk("Failed to init NUS client: %d\n", err); return err; } while (true) { k_sleep(K_SECONDS(1)); if (default_conn && nus_client.connected) { // 确保NUS服务已就绪 const char *message = "hello\n"; err = bt_nus_send(&nus_client, message, strlen(message)); if (err < 0 && err != -EAGAIN && err != -ENOTCONN) { printk("Failed to send message: %d\n", err); } else if (err >= 0) { printk("Message sent successfully\n"); } } } return 0; }
额外配置要求
在中心设备的prj.conf中必须添加以下配置:
CONFIG_BT=y CONFIG_BT_NUS_CLIENT=y CONFIG_BT_L2CAP_TX_MTU=255 CONFIG_BT_DEVICE_NAME="NUS_Central"
关键修复说明
- 新增NUS客户端实例:使用
struct bt_nus_client管理与外设的NUS连接,替代原有的通用回调注册逻辑。 - 自动服务发现:连接建立后调用
bt_nus_client_connect,该函数会自动发现外设的NUS服务和特征,无需手动执行GATT发现流程。 - 修正发送逻辑:发送消息时传入NUS客户端实例,同时判断
nus_client.connected确保NUS服务已完成初始化。 - 移除冗余代码:删除重复的回调注册操作,修复语法错误。
内容的提问来源于stack exchange,提问作者Josh Sinrud
相关产品推荐
相关产品推荐

