
过去十年嵌入式领域最热闹的赛道无疑是物联网和智能硬件。但如果你关注过 MCU 市场报告会发现一个有趣的现象在底层操作系统层面真正实现“增速领跑全球”的并不是老牌商业 RTOS也不是 Linux 的简化版而是由 Linux 基金会托管的开源实时操作系统——Zephyr。而在这条开源之路上走得最坚决、投入最深的公司之一就是 Nordic Semiconductor。从 nRF52 系列开始Nordic 就把 Zephyr 当成 nRF Connect SDK 的根基而不是把它当作一个“可选的实验性框架”。十年下来这一策略正在收获回报Zephyr 在 GitHub 上的提交数、贡献者数量、以及商业落地项目数都保持了高速增长而 Nordic 的 nRF54 系列芯片也顺理成章地成为新一代低功耗蓝牙和 Matter 开发的首选平台。这篇文章想解决三个问题Zephyr 到底是什么级别的 RTOS为什么它能成为物联网时代的“增量市场”选择Nordic 为什么敢于把自家 SDK 押注在 Zephyr 上这背后改变了嵌入式开发的哪些环节以及如果你现在要在一个新项目里选型 RTOSZephyr 和 FreeRTOS 到底该怎么选上手时需要跨过哪些真实的坑。文章会以 Nordic nRF52840 DK 为硬件参照带你从零搭建 Zephyr 开发环境跑通一个最小工程并完成一次简单的 GPIO 点灯和传感器数据读取。整个过程不依赖任何商业 IDE全部使用命令行工具方便你理解 Zephyr 的构建系统和设备树机制。1. 为什么是 Zephyr一个“系统级”的嵌入式开源平台很多开发者对 RTOS 的印象还停留在“一个内核 一堆信号量 一个调度器”。FreeRTOS 之所以普及就是因为它足够轻、足够简单跑在 STM32 和 ESP32 上毫无压力网上资料也多。但如果你把视野放到“物联网设备的完整软件栈”上FreeRTOS 提供的只是一个内核而 Zephyr 提供的是一个平台。这两者本质区别在哪我用一个实际场景来解释。假设你要做一个智能门锁功能包括蓝牙配网、指纹识别、低功耗待机、OTA 升级、本地日志、以及和手机 App 的安全通信。如果用 FreeRTOS你需要自己拼装选择一个 BLE 协议栈比如 NimBLE、一个加密库mbedTLS、一个 Bootloader、一个文件系统LittleFS、还要写设备树去管理引脚和外设配置。这些组件之间的 API 风格不一致版本兼容性靠你自己维护出了问题要分别去各自的社区查。如果用 Zephyr这些能力大多是内置的BLE 协议栈是内置子系统加密库、OTAMCUboot、文件系统LittleFS / NVS、设备树管理硬件、内核提供线程和 IPC所有子系统共用一套 Kconfig 配置体系。你只需要在prj.conf里打开对应的开关在设备树里声明硬件连接然后写应用层的业务逻辑。这种“系统级”的思路很像从“裸机开发 自己拼库”切换到“Linux 开发 标准子系统”。对小型项目来说Zephyr 反而显得重但一旦项目复杂度上来或者需要在多款芯片之间移植Zephyr 的工程优势就非常明显。更关键的是Zephyr 不是 Nordic 一家的私有系统。它由 Linux 基金会管理贡献者包括 Nordic、NXP、ST、Intel、ADI、Garmin 等数十家公司。这意味着你在 Nordic 芯片上写的驱动和应用逻辑迁移到 NXP 或 ST 的芯片上时API 基本不变变的只是设备树里的引脚声明。对于做多平台产品线的团队这是巨大的成本节省。从增速来看Zephyr 近年来的每一个 LTS 版本都会加入大量新 SoC 支持社区规模持续扩大尤其在 Matter、Thread、低功耗蓝牙、汽车电子和工业物联网这几个方向上Zephyr 已经是事实上的标准选项之一。这一节的小结论Zephyr 不是“又一个 RTOS”它更像“嵌入式领域的 Linux 用户态”。内核只是它最基础的部分真正的价值在统一的子系统、统一的构建系统和跨厂商生态。2. Zephyr 的核心设计理念设备树 Kconfig 子系统上手 Zephyr 之前你必须理解它的三大支柱。不理解这三点你会发现它的工程结构到处都是“魔法”很难调通。2.1 设备树硬件描述不再藏在 C 代码里传统嵌入式开发中外设初始化通常是这样GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin LED_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(LED_PORT, GPIO_InitStruct);这种方式在芯片固定、板子固定时没什么问题。但如果同一颗芯片做了多种板型LED 接到了不同的引脚就得用宏定义切换或者维护多份工程。Zephyr 的做法是把“这块板上有什么外设、每个外设连接在哪”全部写进设备树文件.dts/.overlay。应用代码只通过设备树节点获取设备实例然后用统一的 API 操作设备。比如在 Nordic nRF52840 DK 上LED0 在设备树中定义为/ { leds { compatible gpio-leds; led0: led_0 { gpios gpio0 13 GPIO_ACTIVE_LOW; label Green LED 0; }; }; };应用代码里这样获取设备#include zephyr/kernel.h #include zephyr/drivers/gpio.h #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led GPIO_DT_SPEC_GET(LED0_NODE, gpios); void main(void) { gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE); gpio_pin_set_dt(led, 1); }注意看应用代码里没有出现“13”这个引脚号。引脚定义在设备树里应用代码通过DT_ALIAS(led0)拿设备。这样换板子时只需要改.overlay文件应用代码一行不用动。这正是 Zephyr 强调的“硬件描述与业务逻辑分离”。2.2 Kconfig模块像 Linux 内核一样可裁剪Kconfig 是 Linux 内核同款的配置系统。Zephyr 用.conf文件如prj.conf来打开或关闭功能。比如打开蓝牙和日志CONFIG_BTy CONFIG_LOGy CONFIG_BT_PERIPHERALy每个功能模块都有对应的 Kconfig 选项。构建时Kconfig 会根据配置生成最终的编译头文件Zephyr 的源码会按这些宏条件编译。这个设计带来的好处是你可以按需裁剪但不需要手动删除源码文件。关闭某个子系统后构建系统会自动不编译对应的源文件最终固件体积可以控制得很小。2.3 子系统RTOS 不再只是调度器Zephyr 的子系统覆盖了你开发物联网产品需要的大部分模块蓝牙BT支持 BLE、Mesh、Beacon、定向广播等传感器SENSOR统一接口读取温度、湿度、加速度计等显示DISPLAY支持 SSD1306、ST7789 等常见驱动存储NVS、LittleFS、FCB网络NET支持 Wi-Fi、Ethernet、Thread、6LoWPAN安全TLS、mbedTLS、Secure Boot电源管理PM支持 system off、deep sleepOTAMCUboot引导加载器这意味着你不需要像使用 FreeRTOS 那样“搬运轮子”而是直接在统一的框架里调用现成的子系统。学习成本在初期会高一些但项目进入维护期后收益非常明显。3. 环境准备在 Ubuntu 上搭建 Zephyr 开发环境Zephyr 官方支持 Linux、macOS 和 WindowsWSL2 模式。这里推荐Ubuntu 22.04 LTS或更高版本命令行体验最顺畅很多编译工具链的依赖问题也能少踩坑。3.1 安装系统依赖打开终端先更新软件源并安装必要的工具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 libmagic1这里重点解释几个工具的作用cmake和ninja-buildZephyr 的构建系统基于 CMakeNinja 负责并行编译。dfu-utilNordic 和很多开发板通过 USB DFU 烧录固件时要用。device-tree-compiler编译设备树源文件需要。python3-pip后续用west工具管理多仓库源码它是 Python 写的。3.2 安装 west 命令west是 Zephyr 的元工具它负责拉取 Zephyr 仓库、指定版本、更新依赖模块、构建、刷写等。pip3 install --user west安装完成后确认版本west --version如果提示“command not found”可能是用户级 Python 包路径不在 PATH 里执行export PATH$PATH:~/.local/bin3.3 获取 Zephyr 源码Zephyr 的源码采用多仓库管理主仓库是zephyr还有hal_nordic、hal_stm32、mcuboot等依赖仓库。用west init会生成一个工作目录然后west update拉取所有依赖。mkdir zephyr-workspace cd zephyr-workspace west init -m https://github.com/zephyrproject-rtos/zephyr.git --mr main cd zephyr west update注意这一步会下载较多代码耗时取决于网络。执行完后在zephyr-workspace目录下会看到zephyr、bootloader、modules、tools等文件夹。3.4 安装 Python 依赖Zephyr 源码里带了一个requirements.txt包含所有构建时用到的 Python 包pip3 install -r zephyr/scripts/requirements.txt3.5 安装 ARM 交叉编译工具链Nordic 芯片目前主流是 Cortex-M4 / Cortex-M33需要 ARM 交叉编译工具链。sudo apt install gcc-arm-none-eabi验证版本arm-none-eabi-gcc --version如果你的发行版自带的版本过旧低于 10.2建议从 ARM 官网下载最新的gcc-arm-none-eabi-*-x86_64-linux.tar.bz2解压后把bin目录加入 PATH。到这里Zephyr 开发环境就准备好了。接下来用一个最小工程验证整个工具链是否正常。4. 最小工程实践Nordic nRF52840 DK 点灯4.1 创建一个新工程Zephyr 官方提供了很多示例。最简单的路径是直接使用samples/hello_world或samples/basic/blinky。我们先用blinky。cd zephyr-workspace/zephyr west build -b nrf52840dk/nrf52840 samples/basic/blinky如果一切正常编译完成后会在build/zephyr目录下生成zephyr.hex和zephyr.bin。4.2 烧录到开发板用 USB 线连接 nRF52840 DK确认系统识别出开发板lsusb你应该能看到类似0x1915:0x521f的设备就是 Nordic 的 USB 接口。然后执行west flashwest flash会调用nrfjprog或dfu-util自动烧录。如果没有安装 nrfjprog也可以直接用dfu-utildfu-util -a 0 -s 0x00000000:leave -D build/zephyr/zephyr.bin烧录完成后开发板上的 LED0 会开始闪烁。4.3 修改为自己的点灯逻辑接下来我们把默认点灯逻辑改一下让 LED 亮 1 秒、灭 500 毫秒。blinky示例的主文件路径是zephyr-workspace/zephyr/samples/basic/blinky/src/main.c修改它#include zephyr/kernel.h #include zephyr/drivers/gpio.h #include zephyr/sys/printk.h #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led GPIO_DT_SPEC_GET(LED0_NODE, gpios); int main(void) { if (!gpio_is_ready_dt(led)) { printk(LED device not ready\n); return 0; } gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE); while (1) { gpio_pin_set_dt(led, 1); k_msleep(1000); gpio_pin_set_dt(led, 0); k_msleep(500); } return 0; }重新编译烧录west build -b nrf52840dk/nrf52840 samples/basic/blinky --pristine west flash4.4 串口日志输出Zephyr 的 printk 输出会重定向到串口。用 minicom 或 putty 打开/dev/ttyACM0波特率 115200可以看到日志。sudo apt install minicom sudo minicom -D /dev/ttyACM0 -b 115200如果看不到输出先检查开发板上的 VCOM 开关是否拨到默认开启位置再确认CONFIG_SERIAL是否使能。blinky 默认有CONFIG_PRINTKy一般会正常输出。5. 使用设备树 overlay 修改引脚开发中经常遇到这种情况LED 或传感器没有接在默认引脚上需要改设备树。假设你的 nRF52840 DK 外接了一个 LED接在P1.02引脚。我们创建一个 overlay 文件来覆盖默认定义。5.1 创建 overlay 文件在samples/basic/blinky目录下新建led.overlay/ { leds { compatible gpio-leds; led0: led_0 { gpios gpio1 2 GPIO_ACTIVE_LOW; label External LED 0; }; }; };然后指定 overlay 文件编译west build -b nrf52840dk/nrf52840 samples/basic/blinky --pristine -d build_led -- -DOVERLAY_CONFIGled.overlay-d build_led指定新的构建目录避免覆盖默认构建结果。5.2 验证设备树编译结果Zephyr 在构建时会生成一个可视化的设备树描述文件路径是build_led/zephyr/zephyr.dts打开这个文件搜索leds你会看到你的 overlay 内容已经被合并到最终的设备树中。如果 overlay 写错了会在构建阶段直接报错这是 Zephyr 对“硬件配置错误”最友好的防线。这一节的小结论设备树是 Zephyr 硬件适配的核心机制。新手最容易踩坑的地方是 GPIO 标志写错GPIO_ACTIVE_HIGHvsGPIO_ACTIVE_LOW以及DT_ALIAS拿不到节点时报编译错误。6. 一个更完整的实例读取温度传感器点灯只是验证工具链。为了让读者更直观地理解 Zephyr 的传感器子系统这里写一个读取 nRF52840 内置温度传感器的示例。6.1 创建工程cd zephyr-workspace/zephyr west build -b nrf52840dk/nrf52840 samples/sensor/temperature这是 Zephyr 官方自带的温度传感器示例支持读取板载温度传感器。源码路径samples/sensor/temperature/src/main.c核心逻辑是#include zephyr/kernel.h #include zephyr/device.h #include zephyr/drivers/sensor.h #include zephyr/sys/printk.h int main(void) { const struct device *dev DEVICE_DT_GET_ANY(nordic_nrf_temp); struct sensor_value temp; if (dev NULL) { printk(No temperature device found\n); return 0; } while (1) { sensor_sample_fetch(dev); sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, temp); printk(Temp: %d.%d C\n, temp.val1, temp.val2); k_sleep(K_SECONDS(1)); } }6.2 编译与运行west build -b nrf52840dk/nrf52840 samples/sensor/temperature --pristine west flash连接串口会看到类似下面的输出Temp: 27.4 C Temp: 27.5 C这里的关键点是DEVICE_DT_GET_ANY(nordic_nrf_temp)。nordic_nrf_temp是设备树里温度传感器的 compatible 字符串Zephyr 通过它自动匹配驱动。整个过程中应用层代码完全不需要关心这个传感器挂在哪条 I2C 或 SPI 总线上——如果是外接传感器你只需要在设备树里声明总线和地址。7. Zephyr 与 FreeRTOS 的选型对比很多开发者会问既然 FreeRTOS 已经很成熟为什么还要学 Zephyr我从业界的实际项目角度给一个比较清晰的判断。7.1 从项目复杂度看维度FreeRTOSZephyr内核体积极小可裁剪到 4-8KB中等配置裁剪得当可到 20-40KBBLE/网络协议栈需自己集成 NimBLE / lwIP内置子系统统一 API设备驱动芯片厂商提供统一的设备驱动模型跨厂商复用多平台移植需自行适配 HAL设备树 SoC 抽象移植成本低社区活跃度老牌资料多增速快厂商投入大学习曲线平缓较陡需要理解 Kconfig/设备树/构建系统如果你的产品是单一型号、功能简单、团队规模小、生命周期短FreeRTOS 的性价比更高。大部分工程师看几周文档就能上手。但如果你的产品线有多款芯片、需要 BLE OTA 加密 文件系统、或者要对接 Matter/Thread 这类新型物联网协议Zephyr 的集成优势会越来越明显。尤其是当项目进入维护期需要升级协议栈或更换主控时Zephyr 的系统级抽象能帮你省下大量时间。7.2 从生态趋势看当前智能家居领域最重要的标准之一 Matter其 Thread 协议栈在 Zephyr 上是原生支持。很多智能门锁、传感器、灯具的参考设计都基于 Zephyr。Nordic 的 nRF54 系列、Silicon Labs 的 MG24、NXP 的 RW612 等新芯片首发 SDK 都深度集成 Zephyr。这说明 Zephyr 已经不是“玩具系统”而是厂商主推的规模化平台。7.3 什么时候该避免用 Zephyr也有几种情况不建议用 Zephyr你只需要一个任务调度器不需要任何协议栈。芯片资源极其紧张Flash/RAM 只有几十 KB。团队完全没有 Linux 或构建系统的使用经验且没有时间学习。项目要求纯裸机开发不需要 RTOS。选型没有绝对的对错关键是看项目约束和时间成本。Zephyr 在 2025 年前后的生态位更像“中大型物联网设备的标准选项”而不是所有 MCU 项目的默认选项。8. 常见问题与排查思路我根据实际开发经验整理了几个高频问题。问题现象可能原因排查方式解决方案west: command not foundwest 未安装或不在 PATH执行pip3 list | grep west将~/.local/bin加入 PATH编译报错fatal error: zephyr/kernel.h: No such file工程不在 Zephyr 工作空间内检查是否在zephyr-workspace目录下在 workspace 根目录执行west build烧录失败No device foundnrfjprog 未安装或驱动异常执行lsusb确认 USB 枚举安装 nrf-command-line-tools 或改用dfu-util点灯无效但编译成功GPIO 有效电平配置反了查看zephyr.dts中 gpio 标志将GPIO_ACTIVE_HIGH改为GPIO_ACTIVE_LOW或相反编译时提示 Python 依赖缺失requirements.txt未安装执行pip3 list检查重新安装pip3 install -r zephyr/scripts/requirements.txtFlash 空间不足打开了过多子系统检查CONFIG_*裁剪情况关闭未使用的子系统启用CONFIG_MINIMAL_LIBC等精简选项另一个特别建议不要直接使用默认配置跑大型示例。很多示例为了演示功能打开了大量日志和调试选项实际产品需要逐个检查prj.conf里的开关。9. 最佳实践与工程建议9.1 使用 west 管理多板型工程在产品开发中一套代码往往要支持多个板型。建议在工程根目录下创建boards/目录按板型放.overlay和prj_xxx.conf文件编译时指定west build -b nrf52840dk/nrf52840 -d build_v1 -- -DOVERLAY_CONFIGboards/board_v1.overlay9.2 注意日志级别的选择开发阶段用CONFIG_LOG_DEFAULT_LEVEL4DEBUG能看到大量信息但在发布版本里一定要降到CONFIG_LOG_DEFAULT_LEVEL2WRN或CONFIG_LOG_DEFAULT_LEVEL1ERR。日志输出非常消耗 CPU 和功耗在低功耗物联网产品中影响尤其明显。9.3 养成查看构建摘要的习惯每次west build成功后终端会输出 Flash 和 RAM 使用情况。关注这两项Memory region Used Size Region Size %age Used FLASH: 123.4 KB 1 MB 12.0 % RAM: 45.6 KB 256 KB 17.8 %如果 Flash 占用异常增加优先检查是不是误开了CONFIG_BT_DEBUG_LOG或CONFIG_DEBUG_OPTIMIZATIONS。9.4 设备树不是万能药但它是硬件团队的沟通语言很多硬件工程师和软件工程师之间的沟通常常卡在“这个 LED 到底接在哪个引脚”。使用 Zephyr 后软件工程里的设备树文件就是一份“可编译的硬件配置单”硬件改了引脚直接在 overlay 里改然后提交到 Git。代码评审时可以直观地看到硬件变更比口头沟通可靠得多。9.5 版本锁定与可复现构建Zephyr 迭代速度很快为了工程可维护性建议把 workspace 的 manifest 文件west.yml锁定到一个 LTS 版本或固定 release tag。不要长期使用 main 分支做产品开发否则依赖模块的升级可能带来隐性编译错误。锁定方式west init -m https://github.com/zephyrproject-rtos/zephyr.git --mr v3.7-lts west update10. 总结与下一步学习方向这篇文章从“Zephyr 为什么增速领跑”切入介绍了 Nordic 在 Zephyr 生态上的布局随后带你走通了 Zephyr 开发环境搭建、nRF52840 DK 点灯、设备树 overlay 修改、传感器数据读取以及 Zephyr 与 FreeRTOS 的选型对比。读完你至少应该掌握了Zephyr 和 FreeRTOS 的定位差异设备树和 Kconfig 在工程中的实际作用以及如何用命令行完成一次完整的 Zephyr 开发流程。如果你想继续深入建议按这个顺序学习拿到一块 nRF52840 DK 或 nRF54L15 DK跑通官方 samples 中至少 5 个例程包括blinky、hello_world、sensor/temperature、bluetooth/peripheral_hr、mcumgr/smp_svr。认真读一遍samples/bluetooth/peripheral_hr的代码理解 Zephyr 蓝牙服务和 GATT 数据回调的组织方式这是后续开发 BLE 产品的基础。学习 MCUboot 和 OTA 升级流程Zephyr 的 OTA 是配套 MCUboot 的理解双 bank 升级和交换机制对量产设备至关重要。尝试自己写一个简单的传感器驱动用设备树暴露设备实例再通过sensor_channel_get读取数据。这是理解 Zephyr 驱动模型最快的路径。Zephyr 的入门曲线确实比 FreeRTOS 陡但它带来的“硬件配置工程化、驱动跨平台复用、子系统开箱即用”这些能力在 2025 年之后的物联网开发中会越来越值钱。建议收藏这篇文章在搭建环境或选型对比时当成一份速查手册。