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,但背后涉及的知识点不少。我画了张图,帮你理清脉络:

Zephyr BLE 开发环境与第一个示例知识体系 开发环境搭建 项目创建与配置 BLE 广播示例 west init / update west create / build bt_enable / bt_le_adv_start SDK 安装与 PATH 配置 prj.conf 蓝牙配置 iBeacon 广播数据格式 核心流程:环境搭建 → 项目创建 → 代码编写 → 配置 → 编译烧录 → 验证 每个环节都可能踩坑,建议按步骤逐一验证

1.5 常见问题与避坑

避坑指南:我曾经在 west update 时遇到网络超时,结果少拉了几个模块,编译时疯狂报错。解决方案是: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 和配对。