You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zephyr框架下NRF52840中心设备NUS通信配置问题求助

问题分析与修复方案

你使用Zephyr的peripheral_nus示例作为外设,能和手机NUS终端正常通信,但自制的中心设备连接外设后无法交换消息,核心问题在于中心设备的NUS客户端未完成GATT服务发现,且发送逻辑存在错误。以下是具体问题点和修复方案:

核心问题点

  1. 未执行NUS服务发现:中心作为NUS客户端,必须先定位外设的NUS服务(UUID 0xFFE0)及其TX/RX特征,否则无法找到通信的特征句柄,直接调用bt_nus_send会失效。
  2. bt_nus_send参数错误:第一个参数不能传NULL,需要传入绑定了NUS服务的客户端实例,而非空指针。
  3. 重复注册回调:main函数和connected回调中重复调用bt_nus_cb_register,属于冗余操作且可能引发冲突。
  4. 语法错误:main函数存在多余的闭合花括号},会导致编译失败。
  5. 发送时机过早:连接建立后立即发送消息,此时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"

关键修复说明

  1. 新增NUS客户端实例:使用struct bt_nus_client管理与外设的NUS连接,替代原有的通用回调注册逻辑。
  2. 自动服务发现:连接建立后调用bt_nus_client_connect,该函数会自动发现外设的NUS服务和特征,无需手动执行GATT发现流程。
  3. 修正发送逻辑:发送消息时传入NUS客户端实例,同时判断nus_client.connected确保NUS服务已完成初始化。
  4. 移除冗余代码:删除重复的回调注册操作,修复语法错误。

内容的提问来源于stack exchange,提问作者Josh Sinrud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:07:02