1. Zephyr BLE 初探:搭建开发环境与第一个蓝牙示例
说实话,很多初学者在 Zephyr 上栽的第一个跟头,不是代码写不对,而是环境搭不起来。我当年第一次搞 Zephyr 时,光 west 工具就折腾了大半天。所以这一章,咱们先把地基打牢。
1.1 为什么选 Zephyr 做 BLE 开发?
市面上能做 BLE 的 RTOS 不少,FreeRTOS、RT-Thread、NimBLE 原生栈……但我个人习惯用 Zephyr,原因有三:
- 原生蓝牙栈:Zephyr 内置了 BlueZ 和 NimBLE 双栈,不用额外移植。
- 跨平台硬件:同一套代码,换个板子改个 dts 文件就能跑。
- 生态成熟:Nordic、NXP、ST 都在推,社区活跃度很高。
你想想看,如果每个项目都要从头移植蓝牙协议栈,那得累死。Zephyr 把这些脏活都干了,我们专注业务逻辑就好。
1.2 开发环境搭建
嗯,这里要注意。Zephyr 的环境搭建有两条路:一条是手动装,一条是用 Docker。我建议新手走手动路线,因为出了问题你知道去哪修。
1.2.1 安装依赖
以 Ubuntu 22.04 为例,先把基础工具装上:
sudo apt update
sudo apt install --no-install-recommends git cmake ninja-build gperf \
ccache dfu-util device-tree-compiler wget \
python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \
make gcc gcc-multilib g++-multilib libsdl2-dev
1.2.2 安装 west 工具
west 是 Zephyr 的元构建工具,说白了就是帮你管理多个仓库的脚本管家。
pip3 install --user west
记得把 ~/.local/bin 加到 PATH 里。我曾经在这卡了半小时,怎么敲 west 都提示找不到命令……后来发现是 PATH 没配。
1.2.3 获取 Zephyr 源码
west init ~/zephyrproject
cd ~/zephyrproject
west update
这一步会下载 Zephyr 主仓库以及所有模块(包括蓝牙栈、驱动、工具链描述文件)。网络不好的话,建议挂个代理。
1.2.4 安装 SDK
Zephyr SDK 提供了交叉编译工具链。下载并解压:
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.8/zephyr-sdk-0.16.8_linux-x86_64.tar.xz
tar xf zephyr-sdk-0.16.8_linux-x86_64.tar.xz
cd zephyr-sdk-0.16.8
./setup.sh
安装完成后,把工具链路径加到 ~/.zephyrrc:
export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk-0.16.8
1.3 第一个 BLE 示例:beacon 广播
环境搭好了,咱们跑个最简单的 BLE 示例——iBeacon 广播。这个例子的核心逻辑就是让开发板周期性发送蓝牙广播包。
1.3.1 创建项目
用 west 创建一个新项目:
cd ~/zephyrproject
west create -b nrf52840dk_nrf52840 my_ble_beacon
cd my_ble_beacon
-b 指定板子型号,这里我用的是 nRF52840 DK。如果你用别的板子,比如 nRF5340 DK,改成 nrf5340dk_nrf5340_cpuapp 就行。
1.3.2 编写代码
在 src/main.c 里写入以下代码:
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gap.h>
#define DEVICE_NAME "MyBeacon"
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
/* iBeacon 数据格式 */
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe), /* Apple 公司标识 */
BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA,
0x4c, 0x00, /* Apple Company ID */
0x02, 0x15, /* iBeacon 类型 */
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* UUID */
0x00, 0x01, /* Major */
0x00, 0x02, /* Minor */
0xc8), /* RSSI @ 1m */
};
void main(void)
{
int err;
printk("Starting BLE iBeacon example\n");
/* 初始化蓝牙协议栈 */
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
/* 开始广播 */
err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad),
NULL, 0);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
printk("iBeacon advertising started\n");
while (1) {
k_sleep(K_SECONDS(1));
}
}
1.3.3 配置 prj.conf
在项目根目录创建 prj.conf,打开蓝牙功能:
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="MyBeacon"
1.3.4 编译与烧录
west build -b nrf52840dk_nrf52840 .
west flash
烧录成功后,用手机上的 nRF Connect 或 LightBlue 扫描,你应该能看到名为 "MyBeacon" 的设备,UUID 为 01020304-0506-0708-090a-0b0c0d0e0f10 的 iBeacon 广播包。
minicom -D /dev/ttyACM0 -b 115200 连接,看有没有 "Bluetooth initialized" 和 "iBeacon advertising started" 的打印。没有的话,八成是硬件连接或配置问题。
1.4 知识体系总览
这一章虽然只跑了个简单的 beacon,但背后涉及的知识点不少。我画了张图,帮你理清脉络:
1.5 常见问题与避坑
west update -o=--depth=1 只拉最新版本,减少数据量。如果还不行,换个网络环境试试。
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| west 命令找不到 | PATH 未包含 ~/.local/bin | 在 ~/.bashrc 中添加 export PATH=$PATH:~/.local/bin |
| 编译报错 "undefined reference to `bt_enable'" | prj.conf 未开启 CONFIG_BT | 检查 prj.conf 是否包含 CONFIG_BT=y |
| 手机扫描不到设备 | 广播参数设置错误或硬件未初始化 | 检查串口日志,确认 bt_enable 返回 0 |
| 烧录失败 "No device found" | JLink 驱动未安装或板子未连接 | 运行 JLinkExe 测试连接,或重新插拔 USB |
1.6 小结
这一章我们完成了三件事:搭好了 Zephyr 开发环境、跑通了第一个 BLE beacon 示例、理清了整个知识体系。你想想看,从零到能广播,其实就几步。但每一步都有细节,别急,后面我们会一步步深入 GATT 和配对。