
做嵌入式开发的人大概率已经注意到一个趋势近两年越来越多的开源项目从 FreeRTOS 迁到 Zephyr或者新项目直接默认选 Zephyr。但很多人的第一反应是这不过是一次常规换内核或者认为 Zephyr 就是“功能更多的 FreeRTOS”。真正接触过 Zephyr 之后你会发现它解决的问题层次和传统 RTOS 完全不一样。如果说 FreeRTOS 关心的是“帮你把线程、队列、信号量管好”那么 Zephyr 关心的是“从硬件描述、驱动匹配、编译配置到连接协议栈能不能建立一套可复用的工程体系”。在 2026 年做物联网产品项目复杂度已经不只是多几个任务的问题而是涉及蓝牙、Wi-Fi、OTA、日志、电源管理、多板卡适配这些事如果全靠手工胶水代码去粘维护成本会很快失控。这篇文章会从工程师视角拆解 Zephyr它到底是什么、关键概念有哪些、环境怎么搭、第一个应用怎么跑并且把 Zephyr 和 FreeRTOS 做一次偏工程实践的深度对比而不是停留在“谁更实时”这种层面上。读完以后你应该能判断自己的项目适不适合 Zephyr也能照着本文在本地跑通第一个例子。1. 为什么 2026 年还要重新聊 Zephyr1.1 困扰嵌入式团队的三类痛点如果你是做消费电子、工业物联网或者车载边缘节点的近几年大概率会遇到下面三类问题。第一类是“协议栈重复造轮子”。项目要用蓝牙先找一颗 SoC再找厂商 SDK然后把蓝牙协议栈和自家业务代码绑死。一旦换主控协议栈和驱动层几乎要重写。如果产品同时还要 Wi-Fi、Thread 或者 Matter这些协议栈往往各有各的 API工程结构很快变成一团乱麻。第二类是“多板卡适配困难”。同一个固件要跑在几套硬件版本上硬件差异可能只是某个 GPIO、一颗传感器或者一组电源控制引脚。传统做法是通过宏定义加#ifdef时间一长代码里全是平台分支改一个引脚配置可能影响三个产品线。第三类是“配置与构建不可复现”。工程师换了电脑或者同事拉下代码编译不过配置项散落在各种头文件里没有统一的构建入口。项目越做越大“能跑”和“可维护”之间的距离越来越远。1.2 Zephyr 本质上在解决什么问题Zephyr 的价值不在于它比 FreeRTOS 多了多少个内核 API而在于它把“嵌入式工程化”这件事往前推了一大步。它提供了一套基于 Kconfig 的配置系统一套基于 devicetree 的硬件描述机制以及基于 west 的代码管理方式。这三样东西组合起来解决的核心问题是把硬件差异从业务代码里剥离出来。同样是点亮一个 LED在 Zephyr 里写的是gpio_pin_toggle_dt(led)不管底层是 STM32、nRF52 还是 ESP32应用层代码基本一致。真正的硬件差异被放到 devicetree 文件里描述而功能开关被放进 Kconfig 配置里。这意味着团队在项目早期引入 Zephyr更多是在选择一种工程组织方式而不是多学一个内核调度器。对开发效率的影响会随着项目复杂度上升越来越明显。1.3 这篇文章写给谁如果你是下面这三类读者这篇文章会比较合适正在做嵌入式选型想在 Zephyr 和 FreeRTOS 之间做决定希望看到工程维度的对比而不是只看内核功能列表。已经选定或打算尝试 Zephyr但卡在环境搭建、构建流程、Kconfig 和 devicetree 这些概念上需要一条比较顺畅的入门路径。有嵌入式基础想理解 Zephyr 的模块化设计到底是怎么落地的并希望把一些最佳实践带到自己的项目里。如果只是想找一个 20KB ROM 内就能跑的最小内核Zephyr 不一定是最优解。但如果你的产品需要连接协议栈、多板卡支持、系统级日志和稳定可复现的构建Zephyr 值得你认真评估。2. Zephyr 到底是什么不只是 RTOS而是一套组件化平台2.1 内核只是起点Zephyr 是 Linux 基金会托管的开源项目名义上叫实时操作系统但它的定位更准确地讲是一个“嵌入式组件化平台”。除了传统 RTOS 的任务调度、信号量、消息队列、内存管理之外它还内置了大量子系统蓝牙、Wi-Fi、Thread、Zigbee、Matter 等连接协议栈。基于 devicetree 的驱动模型支持 GPIO、UART、SPI、I2C、PWM、ADC、USB 等常见外设驱动。日志系统、电源管理、Flash 分区、OTA 升级框架、Shell 组件。CMSIS、POSIX 兼容层以及面向安全的原生支持。这些子系统和内核一样都是可配置的。一个简单设备可以只保留调度器和 GPIO 驱动一个复杂的物联网网关又可以把蓝牙、Wi-Fi、日志、OTA 全部打开。这种“按需裁剪”的能力来自 Kconfig 配置系统。2.2 三个核心概念Kconfig、devicetree、west很多刚接触 Zephyr 的人被门槛劝退的原因往往不是 C 语言而是这三个工具链概念。Kconfig 是 Linux 内核同款的配置系统。它通过CONFIG_XXXy这种方式控制功能的开启和参数。比如CONFIG_GPIOy表示启用 GPIO 驱动CONFIG_LOGy表示启用日志系统。工程中的prj.conf文件写的就是这些配置项。Kconfig 帮你把“这个功能开不开、参数是多少”统一到一处而不是散落在 C 头文件里。devicetree 是一套描述硬件的树形结构格式与 Linux 设备树同源只是 Zephyr 有自己的绑定定义。某个外设挂在哪个总线、中断号是多少、引脚是哪一个都写在 devicetree 文件里。应用层通过DT_NODELABEL(led0)这类 API 去引用硬件节点。它的位置类似于芯片原厂硬件抽象层里的引脚配置表但表达能力更强。west 是 Zephyr 的多仓库管理工具负责拉取 Zephyr 内核、各子系统模块以及控制构建和刷写流程。它的核心是一个west.yml文件里面记录了项目依赖的所有仓库和版本。这三个概念共同构成了 Zephyr 的工作方式west 管理代码Kconfig 管理功能开关devicetree 管理硬件差异。2.3 Zephyr 与传统 RTOS 的本质区别传统 RTOS 的核心交付物是内核它假设驱动和协议栈由芯片厂商提供或由开发者自己编写。这种方式在单芯片、单产品阶段没问题但一旦需要跨平台、跨产品线复用厂商 SDK 之间 API 不统一的问题就会暴露出来。Zephyr 的交付物则是一个完整的平台。它不要求你把厂商 SDK 粘进来而是采用自己的驱动模型和硬件描述体系从底层就把“芯片差异”和“业务代码”隔离。芯片厂商需要做的是提供 Zephyr 的 board 支持而应用开发者直接调用 Zephyr 的抽象 API。这正是 Zephyr 看起来学习曲线更陡但很多人仍然推荐它的原因初期多花时间理解工具链后期换平台、换 SoC、做多板卡适配的时候省下的是数十倍的维护成本。3. Zephyr 环境搭建Ubuntu 下的最小可运行方案3.1 准备基础工具Zephyr 官方推荐的开发环境是 LinuxWindows 也支持但 Ubuntu 是最顺滑的路径。这套流程后面用到的命令在 Windows 的 WSL2 里也基本可以直接跑。先安装基础依赖sudo apt update sudo apt install -y 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这里有几个组件在后面会反复用到cmake和ninja-buildZephyr 的构建系统基于 CMakeNinja 是默认的生成器。device-tree-compiler处理 devicetree 描述文件时依赖。python3-pip用来安装 west。dfu-util通过 USB DFU 方式烧录固件时需要。如果你的网络环境访问官方仓库比较慢可以先配置好 git 的 HTTP 代理或镜像后面west update会省心很多。3.2 安装 west 与 Zephyr SDKwest 是 Zephyr 的官方命令行工具使用 Python 编写可以通过 pip 安装pip3 install --user west # 将用户 Python 工具目录加入 PATH export PATH$HOME/.local/bin:$PATH west --version注意如果系统同时存在多个 Python 版本建议确认pip3对应的版本和python3一致否则west装完之后可能在 shell 里找不到命令。接下来需要用 west 初始化一个 workspacecd ~ west init zephyr-workspace cd zephyr-workspace west update执行完以后~/.zephyr-workspace/zephyr目录下就是 Zephyr 源码~/.zephyr-workspace/modules下是各种依赖模块。Zephyr 官方建议使用 Zephyr SDK 作为工具链SDK 里包含了交叉编译所需的所有板级工具链和主机工具。下载 SDK 时建议到 zephyrproject-rtos 的 GitHub Releases 页面获取当前稳定版本本文以 0.16.x 系列为例cd ~ # 下载路径以官方 releases 页面为准例如 zephyr-sdk-0.16.x_linux-x86_64.tar.xz wget SDK下载链接 tar xf zephyr-sdk-0.16.x_linux-x86_64.tar.xz cd zephyr-sdk-0.16.x ./setup.sh执行setup.sh时它会自动检测本机已有的工具链并配置好 cmake 需要的包。安装完成后还需要告诉 Zephyr SDK 的安装位置export ZEPHYR_TOOLCHAIN_VARIANTzephyr export ZEPHYR_SDK_INSTALL_DIR$HOME/zephyr-sdk-0.16.x这两行环境变量建议写入~/.bashrc否则每次打开新终端都要重新设置。3.3 验证环境是否可用环境搭完以后可以使用 Zephyr 自带的 hello_world 示例做一次验证cd ~/zephyr-workspace/zephyr west build -b qemu_cortex_m3 samples/hello_world west build -t run如果输出中出现类似Hello World! qemu_cortex_m3的内容并且程序正常运行退出说明 west、CMake、SDK 工具链、QEMU 模拟器这一整条链路已经通了。这里有一个容易踩坑的地方如果你之前已经装过别的嵌入式工具链环境中可能存在多个编译器版本setup.sh在配置时可能会选择到不期望的版本。遇到问题时优先确认ZEPHYR_SDK_INSTALL_DIR是否指向了正确的安装目录。4. 跑通第一个应用程序从 hello_world 到 GPIO 闪烁4.1 构建 hello_world先解释一下west build的语法后面所有应用都遵循这个模式west build -b board 应用目录-b指定目标板卡例如qemu_cortex_m3、nrf52840dk_nrf52840、stm32f411e_disco。应用目录下必须有CMakeLists.txt、prj.conf、src/main.c等文件。构建产物默认生成在build目录。hello_world 是最小验证应用它的 main.c 本质上只是打印一行日志#include zephyr/kernel.h void main(void) { printk(Hello World! %s\n, CONFIG_BOARD); }执行构建后可以在build/zephyr/zephyr.elf中看到固件产物。如果编译出错优先检查 build 目录下的CMakeCache.txt确认 CMAKE 选择的工具链路径是不是你安装的 SDK。4.2 在 QEMU 中运行Zephyr 对 QEMU 的支持相当完善很多代码不需要真实硬件就能跑起来。对初学者来说这是一个非常友好的验证手段。cd ~/zephyr-workspace/zephyr west build -b qemu_cortex_m3 samples/hello_world west build -t runwest build -t run会自动调用 QEMU 加载固件。如果想退出模拟器一般是Ctrl A然后按X。QEMU 模拟并不是万能的但它足够用来验证任务调度、IPC、内核 API 和部分驱动逻辑。4.3 点亮一块真实开发板如果手上有一块支持的开发板建议以 GPIO 点灯作为第一个真实硬件实验。创建一个新的应用目录my-led/ ├── CMakeLists.txt ├── prj.conf └── src/ └── main.cCMakeLists.txt内容cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(my_led) target_sources(app PRIVATE src/main.c)prj.conf中启用 GPIO 驱动CONFIG_GPIOysrc/main.c#include zephyr/kernel.h #include zephyr/device.h #include zephyr/drivers/gpio.h static const struct gpio_dt_spec led GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios); int main(void) { if (!gpio_is_ready_dt(led)) { return -1; } gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE); while (1) { gpio_pin_toggle_dt(led); k_sleep(K_MSEC(500)); } return 0; }这里真正值得留意的不是 API 本身而是DT_NODELABEL(led0)。它从 devicetree 中查找名为led0的节点。不同开发板的 dts 文件里这个节点名可能不同有的叫green_led有的叫led_1。如果找不到可以通过 devicetree overlay 在应用层添加一个透明引用而不需要修改原厂 board 文件。编译命令west build -b nrf52840dk_nrf52840 my-led west flashwest flash会调用开发板默认的烧录方式。对于 nRF 开发板通常是 J-Link 调试器对于 STM32可能是 OpenOCD 或 dfu-util。如果烧录失败可以先检查 USB 设备是不是被系统正确识别再查看调试器日志。5. 配置系统实践Kconfig、prj.conf 与 Workbench for Zephyr Kconfig5.1 Kconfig 在工程里的作用Kconfig 是 Zephyr 工程里最容易被低估的部分。它解决的问题是同一份代码怎么在不同产品上实现不同的功能组合。比如你有一个产品线基础版不需要蓝牙高配版需要蓝牙和日志上报。在没有配置系统时通常需要用宏和条件编译去维护多套代码在 Zephyr 里只需要提供不同的配置文件。基础版用prj_base.conf高配版用prj_high.conf构建时指定即可。配置项的层次按文件位置划分应用级的prj.conf优先级低于 board 级的defconfig后者的优先级又低于 SoC 级配置。这个优先级关系在排查“为什么我的配置没生效”时非常重要。5.2 使用 Workbench for Zephyr 的 Kconfig 视图用命令行编辑 Kconfig 虽然有west build -t menuconfig这种文本菜单但对不熟悉选项位置的开发者来说仍然很痛苦。一些团队会使用 Antmicro 推出的 Workbench for Zephyr 作为开发环境它在 IDE 中提供了图形化的 Kconfig 配置界面。在 Workbench for Zephyr 中你可以直接搜索配置项、查看依赖关系、修改并保存到prj.conf。这比手工翻 Kconfig 文件高效很多尤其是面对蓝牙协议栈这种有大量子选项的配置组时。工程师不需要背配置树只需要知道“我要开蓝牙”然后搜索蓝牙相关配置即可。即使不用 Workbench我也建议在项目里建立一个“配置项变更记录”的习惯因为随意改 Kconfig 很容易引入依赖冲突。比如打开某个协议栈后它会强制依赖日志、Flash 接口或者 DMA 驱动如果这些配置项缺失编译阶段会直接报错。图形化工具的优势恰恰在于它会实时显示依赖关系避免你盲目勾选。5.3 配置项到底写在哪Zephyr 的配置读取顺序和覆盖规则不是一开始就能猜对的。这里有一个简化版的经验总结普通应用配置写在自己的prj.conf。针对特定板卡的配置写在 board 目录下的board_defconfig。需要在多个应用间共享的配置可以放到 shared 模块或者通过west.yml引入的模块里。构建时可以追加--参数覆盖配置比如west build -b xxx -- -DCONFIG_LOGy。排查配置问题时最快的验证方式是检查编译生成的.config文件。它位于 build 目录下是最终生效配置的合并结果。如果发现prj.conf里写了但.config里没有说明该项在某个更高优先级的位置被覆盖或者配置项没有被当前 board 启用。6. Zephyr vs FreeRTOS 深度对比2026 年项目选型怎么选6.1 对比维度做技术选型时最忌讳只盯着功能列表。FreeRTOS 和 Zephyr 的定位不同FreeRTOS 更多是纯内核 社区生态Zephyr 是完整平台 官方子系统。真正影响项目成本的是芯片适配、开发调试、维护升级、团队上手速度以及最关键的是“项目长期演进遇到新需求时体系能不能撑住”。下面这张表按照工程维度做对比而不是简单比较内核 API 的数量对比维度ZephyrFreeRTOS内核定位组件化 RTOS 平台轻量实时内核配置方式Kconfig类似 Linux 内核C 头文件 宏定义硬件描述devicetree 树形描述无统一标准驱动模型统一驱动框架厂商 SDK 自行负责连接协议栈内置蓝牙、Wi-Fi、Thread、Matter 等多依赖第三方或商业方案构建系统west CMake多仓库管理厂商工程模板为主学习曲线较陡需要理解构建系统与配置体系较平缓入门快内存占用可裁剪可做小但通常需要一定 Flash可做到非常小的占用社区生态Linux 基金会主导芯片厂商支持度持续增长历史悠久资料多生态庞大多板卡适配难度应用层与硬件描述隔离适配成本低通常需要按平台维护分支商业授权Apache 2.0MIT核心组件需单独确认6.2 关键判断一产品协议栈复杂度决定选择如果你的产品只需要跑三五个任务外设是 UART、GPIO、ADC 这类基础接口并且项目周期很短FreeRTOS 依然是一个非常务实的选择。它的学习成本低团队几乎不需要额外培训踩坑资料也多。尤其是小内存 MCU 上FreeRTOS 可以做到非常紧凑。但一旦产品需要蓝牙或 MatterFreeRTOS 的优势就会减弱。这时你面临的是“在 FreeRTOS 上移植蓝牙协议栈”还是“在 Zephyr 上直接启用蓝牙子系统”的选择。前者意味着你要协调厂商 SDK、内存管理、中断优先级、任务栈分配一整套工作足以消耗数周时间后者通常是打开配置、注册回调、编写应用逻辑。从 2026 年的市场看很多带连接的 IoT 设备默认选 Zephyr不是因为 Zephyr 的调度器更强而是因为它的协议栈和驱动体系让产品集成成本更低。6.3 关键判断二团队维护成本决定选择如果你所在团队只有两三个人并且产品形态是“一年出货几款不同的板卡”Zephyr 的 devicetree 机制会很值。你把硬件差异描述进 dts应用层代码可以保持同一套换板卡时只需要新增 board 支持和配置不用把业务逻辑拆得到处是#ifdef。反过来如果团队对 Zephyr 的构建体系不熟悉也没有时间系统学习 Kconfig 和 devicetree仓促上马 Zephyr 可能会在项目前期浪费很多时间在环境上。更稳妥的策略是先用一块官方开发板跑通全流程再评估是否把量产项目迁移过来。FreeRTOS 的资料确实更多几乎每个芯片厂商的 SDK 都自带 FreeRTOS 移植示例。这种成熟度在快速出原型阶段非常有价值。但资料多和体系化是两回事厂商移植版本之间 API 差异、调度策略差异、驱动层不一致长期看都是隐性成本。7. 常见问题与排查方法7.1 环境与构建问题问题现象可能原因排查方式解决方案west命令找不到Python 工具目录没加入 PATHtype west或which west将$HOME/.local/bin加入 PATHwest update超时或失败网络问题或子模块过多查看失败仓库名配置 git 镜像或使用可靠网络重试编译报错找不到交叉编译器ZEPHYR_SDK_INSTALL_DIR未设置检查环境变量重新export并写入~/.bashrcCMake 版本过低系统 CMake 不满足 Zephyr 要求cmake --version升级 CMake 或使用 pip 安装新版构建成功但烧录失败调试器驱动、USB 权限或板卡未识别查看west flash日志添加 udev 规则或改用其它烧录方式7.2 devicetree 相关问题问题现象可能原因排查方式解决方案DT_NODELABEL(led0)找不到节点当前板卡没有led0标签查看 board 的 dts 文件使用 overlay 添加别名或者改用有效节点GPIO 配置编译通过但硬件不动作引脚号、极性或 io-channel 描述错误检查 dts 中的 gpio 属性对照原理图修改 devicetree overlay外设注册失败节点 compatible 与驱动不匹配查看编译日志和绑定文档保证 dts 中 compatible 正确7.3 Kconfig 配置问题问题现象可能原因排查方式解决方案打开某项后编译报错说依赖缺失Kconfig 依赖项未开启查看报错提示的无依赖选项在prj.conf中补充依赖配置prj.conf修改后没反应配置被 board defconfig 覆盖查看 build 目录下.config确认写入位置是否正确配置项很多不知道从哪开始对配置树不熟悉使用menuconfig或 Workbench Kconfig 界面搜索目标项并查看依赖关系从实际工程经验看Zephyr 项目里百分之八十的早期问题不是内核 API 用错而是构建环境、devicetree 和 Kconfig 这三层工具链没有理顺。遇到问题不慌先看 build 目录下的日志和.config文件大多数情况都能找到直接原因。8. 工程落地建议与最佳实践8.1 用 west manifest 锁定版本Zephyr 迭代速度很快内核 API 和配置文件格式都在持续演进。如果不锁定版本团队成员的本地环境很容易出现“我这边编译好你那边编译不过”的问题。建议在工程根目录的west.yml中明确指定 Zephyr 版本manifest: projects: - name: zephyr revision: v3.7.0 url: https://github.com/zephyrproject-rtos/zephyr self: path: app这里revision字段可以写某个 release 标签也可以写具体 commit hash。供应链安全角度建议优先使用官方发布 tag确需使用非发布提交时要在文档里记录上下文。8.2 配置分层与设备树 overlay在生产项目中建议遵守一个原则不修改原厂 board 目录下的文件。硬件差异一律通过 overlay 和配置文件覆盖实现。这样当 Zephyr 版本升级时可以安全地合并上游改动而不会产生一堆本地补丁冲突。举个例子如果你的产品使用自定义 LED 引脚不要直接改板级 dts而是在应用目录下创建boards/board.overlay然后在 overlay 中重新定义节点属性。这种方式保证了 board 支持代码和产品业务代码之间的边界清晰也方便后续切换开发板。配置层面的分层建议通用功能开关放prj.conf。产品级差异放独立配置文件构建时选择对应文件。板卡级差异放 board 目录或 overlay。把每个配置项的用途记录下来避免三个月后没人知道某个CONFIG_XXX为什么存在。8.3 开发流程与验证建议Zephyr 工程的调试通常比传统 RTOS 更有体系。推荐团队在项目中尽早接入以下实践使用 Zephyr 的日志系统而不是随手printk。日志系统支持分级、标签过滤和后台适配后期问题定位效率会高很多。为每个应用维护一个最小可运行示例任何配置变更先在最小示例上验证再合入正式工程。这能避免“配置被复杂工程淹没”的情况。在 CI 中加入 QEMU 冒烟测试。虽然 QEMU 不能覆盖真实硬件行为但至少能保证内核、构建和基础逻辑不出现回归。对固件升级和 Flash 分区保持敬畏。Zephyr 提供了分区表机制新增 OTA 功能前先确认 bootloader、分区地址和刷写流程避免把设备刷成变砖状态。9. 小结与下一步这篇文章从工程视角重新梳理了 Zephyr 的价值它不像 FreeRTOS 那样只是解决任务管理问题而是通过 Kconfig、devicetree、west 这套体系把硬件差异、功能配置和代码依赖统一管理起来。对于带连接协议栈、多板卡适配和长期演进的产品Zephyr 的体系优势会随着时间越来越明显。如果你是第一次接触 Zephyr建议下一步不要急着移植复杂业务先按照本文的流程搭好环境跑通 hello_world再在开发板上实现一个 GPIO 闪烁。然后尝试修改 prj.conf 开启日志增加一个 devicetree overlay体验一下“配置而不是改代码”的工作方式。如果你的项目还在 FreeRTOS 和 Zephyr 之间犹豫建议以产品需求为判断依据协议栈复杂度和多板卡要求高Zephyr 值得投入资源极度紧张、项目周期极短FreeRTOS 仍然稳妥。没有绝对最优只有适不适合。最后补充一个经验Zephyr 项目里最怕的不是内核 API 不会用而是工程配置混沌。建议从一开始就把 west.yml、prj.conf、devicetree overlay 这三件事当成项目边界每次改动都明确知道它影响哪一层。把这条规矩立住Zephyr 才能真正变成一套提升效率的平台而不是另一个需要花大力气维护的玩具。