目录
概述
在 nRF Connect SDK(基于 Zephyr RTOS)中,获取蓝牙设备的 MAC 地址(Bluetooth Address) 可以通过以下几种方式实现:
1. 获取设备的默认蓝牙地址
1.1 读取 NRF_FICR->DEVICEADDR
该方法仅适合于如下这些类型的芯片:
nRF52/nRF53 系列
Nordic 芯片的 Factory Information Configuration Registers (FICR) 存储了默认的蓝牙地址(Public 或 Random Static):
#include <hal/nrf_ficr.h>
void print_default_ble_address(void) {
uint32_t addr_low = NRF_FICR->DEVICEADDR[0]; // 低 4 字节
uint32_t addr_high = NRF_FICR->DEVICEADDR[1]; // 高 2 字节
uint8_t ble_addr[6] = {
(addr_low >> 0) & 0xFF, // 字节 0
(addr_low >> 8) & 0xFF, // 字节 1
(addr_low >> 16) & 0xFF, // 字节 2
(addr_low >> 24) & 0xFF, // 字节 3
(addr_high >> 0) & 0xFF, // 字节 4
(addr_high >> 8) & 0xFF, // 字节 5
};
printk("Factory BLE Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
ble_addr[5], ble_addr[4], ble_addr[3], // 高位在前
ble_addr[2], ble_addr[1], ble_addr[0]);
}
⚠️ 注意:
某些芯片(如 nRF52840)的 FICR 地址是 只读 的。
如果未烧录地址,可能返回
FF:FF:FF:FF:FF:FF
或随机值。
1.2 使用 bt_id_get()
获取当前使用的地址
#include <bluetooth/bluetooth.h>
void print_current_ble_address(void) {
bt_addr_le_t addrs[CONFIG_BT_ID_MAX];
size_t count = CONFIG_BT_ID_MAX;
// 获取所有已注册的蓝牙地址
bt_id_get(addrs, &count);
for (size_t i = 0; i < count; i++) {
printk("BLE Address %d: %02X:%02X:%02X:%02X:%02X:%02X (type: %s)\n",
i,
addrs[i].a.val[5], addrs[i].a.val[4], addrs[i].a.val[3],
addrs[i].a.val[2], addrs[i].a.val[1], addrs[i].a.val[0],
addrs[i].type == BT_ADDR_LE_PUBLIC ? "Public" : "Random");
}
}
输出示例:
BLE Address 0: AA:BB:CC:DD:EE:FF (type: Random)
2 获取对端设备的蓝牙地址
2.1 在连接建立后获取对端地址
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
static void connected(struct bt_conn *conn, uint8_t err) {
if (err) {
printk("Connection failed (err %u)\n", err);
return;
}
// 获取对端设备的蓝牙地址
const bt_addr_le_t *addr = bt_conn_get_dst(conn);
printk("Connected to: %02X:%02X:%02X:%02X:%02X:%02X (type: %s)\n",
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type == BT_ADDR_LE_PUBLIC ? "Public" : "Random");
}
static struct bt_conn_cb conn_callbacks = {
.connected = connected,
};
void main(void) {
bt_conn_cb_register(&conn_callbacks);
}
2.2 在扫描时获取广播设备的地址
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
static void scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type,
struct net_buf_simple *buf) {
printk("Device found: %02X:%02X:%02X:%02X:%02X:%02X (RSSI: %d)\n",
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0], rssi);
}
void start_scan(void) {
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_PASSIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
};
bt_le_scan_start(&scan_param, scan_cb);
}
3. 使用 Shell 命令获取地址
如果启用了 Bluetooth Shell,可以直接通过终端命令获取地址:
# 查看本机地址
bt id-show
# 扫描周围设备
bt scan on
输出示例:
[bt] [ID] 0: AA:BB:CC:DD:EE:FF (random static)
4 总结
4.1 获取ADD方法
方法 | 适用场景 | 代码示例 |
---|---|---|
NRF_FICR->DEVICEADDR | 读取芯片出厂地址 | NRF_FICR->DEVICEADDR[0/1] |
bt_id_get() | 获取当前使用的地址 | bt_id_get(addrs, &count) |
bt_conn_get_dst() | 获取对端设备地址 | bt_conn_get_dst(conn) |
扫描回调 scan_cb | 获取广播设备地址 | bt_le_scan_start() |
Shell 命令 | 快速调试 | bt id-show |
4.2 注意事项
-
Public vs Random 地址:
-
Public 地址需向 IEEE 申请,通常由芯片厂商预烧录。
-
Random Static 地址最高 2 位应为
11
(如0xCF:...
)。
-
-
隐私模式(Privacy):
-
如果启用了
CONFIG_BT_PRIVACY=y
,设备会使用 Resolvable Private Address (RPA),此时bt_id_get()
可能返回临时地址。
-
如果需要进一步处理地址(如转换为字符串),可以使用 bt_addr_le_to_str()
:
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
printk("Address: %s\n", addr_str);