Zephyr - 特别篇|Higgsfield 原创系列(2026):为什么它正在成为嵌入式开发者的“第二个 Linux”

2026 年再讨论嵌入式 RTOS,很多人会默认“选 FreeRTOS 准没错”。这个判断放在五年前基本成立,但放在今天已经不够准确了。原因很简单:当你的产品开始需要联网、需要 OTA、需要复杂的电源管理、需要多协议栈共存时,FreeRTOS 能做的和你真正想做的事情之间,会拉开一条巨大的鸿沟。

Zephyr 在这条鸿沟上搭了一座桥。它不是一个传统的、以最小资源占用为唯一目标的 RTOS,而是一整套面向连接设备和物联网场景的操作系统级解决方案。这篇文章不是帮你“再认识一个 RTOS”,而是用实际开发链路告诉你:Zephyr 到底解决了什么问题,它在 2026 年嵌入式项目选型中应该摆在什么位置,以及你从零开始搭建 Zephyr 环境、配置 Kconfig、写一个能跑起来的工程,要经过哪些步骤。

无论你是做 MCU 应用开发、物联网网关、可穿戴设备,还是正在考虑把现有 FreeRTOS 项目迁移到 Zephyr,读完这篇文章后,你对“该不该用 Zephyr”这个问题会有一个清晰的技术判断。

1. 这篇文章真正要解决的问题

很多工程师第一次接触 Zephyr 时,第一个反应是:这个系统怎么这么“重”?又是 Kconfig、又是 Devicetree、又是 west 工具链,一个 Hello World 都要配置半天。相比之下,FreeRTOS 只需要加两个 C 文件就能跑起来。

但如果你正在做的事情超出了“点亮 LED”或“跑一个任务调度”的范畴,体验会完全不同。

举一个典型场景:你要做一个带有 BLE、Wi-Fi、FOTA 升级和低功耗管理的智能家居设备。用传统 FreeRTOS 方案,你需要自己选协议栈(是 NimBLE 还是 Zephyr 自带的)、自己对接 OTA 分区表、自己处理不同硬件版本的板级差异、自己设计功耗控制框架。这些工作不是不能做,而是大量时间会花在“搭框架”而不是“做产品”上。

Zephyr 换了一种思路:把内核、驱动、协议栈、电源管理、构建系统全部纳入一个统一框架。你不再需要反复拼装不同开源项目,而是通过配置系统按需裁剪。这正是它和 FreeRTOS 在 2026 年最本质的区别:FreeRTOS 是“一个调度器”,Zephyr 是“一个系统”。

所以这篇文章的核心目标有三个:

第一,帮你建立 Zephyr 的正确心智模型。它不是“复杂版的 FreeRTOS”,而是“面向 MCU 的类 Linux 工程体系”。

第二,给你一份可落地的环境搭建和工程运行指南,包括 west 工具链、Kconfig 配置、Devicetree 基本用法。

第三,用表格和场景对比 Zephyr 和 FreeRTOS 的差异,让选型这件事有依据,而不仅仅是凭感觉。

2. Zephyr 基础概念:Kconfig、Devicetree 与 west 工具链

在动手之前,先把 Zephyr 的三个核心概念说清楚。这三个概念理解了,后面所有配置和编译过程都不会觉得别扭。

2.1 Kconfig:不再靠宏定义开关功能

Kconfig 最早来自 Linux 内核配置体系,Zephyr 把它完整带到了 MCU 领域。它的作用是在编译之前,决定“这个固件包含哪些功能模块”。

传统 RTOS 的做法是在代码里写一堆 #ifdef XXX_ENABLE 。功能少的时候没问题,功能上百个之后,宏管理的复杂度会非常高。Kconfig 把这个过程集中到统一的配置入口,所有可选项都有清晰的依赖关系。

比如你想启用某种传感器驱动,只需要在配置文件中加上:

CONFIG_BOARD_GPIO_SENSOR=y
CONFIG_SENSOR_LOG_LEVEL_INF=y

系统会自动检查这个驱动依赖哪些硬件资源、是否和当前板卡兼容、是否需要连带开启其他配置项。

2.2 Devicetree:硬件描述与代码逻辑分离

Devicetree(设备树)也是从 Linux 引入的概念。它的作用,是用一套统一的数据格式描述硬件拓扑:CPU 内核、内存地址、外设寄存器、中断号、引脚复用。

这样做的好处在于:当你的产品换了同系列但引脚不同的 MCU 时,不需要改 C 代码,只要改设备树文件里的引脚描述即可。这在传统 STM32 裸机开发中几乎不敢想象。

// 文件路径:boards/board_name/board_name.dts
/ {
    model = "Example Board";
    compatible = "example,board";

    leds {
        compatible = "gpio-leds";
        red_led: led_0 {
            gpios = <&gpioa 5 GPIO_ACTIVE_HIGH>;
            label = "Red LED";
        };
    };
};

2.3 west:一切命令的统一入口

west 是 Zephyr 的项目管理工具,类似 Linux 下的 repo,但它做的事情更多:拉取代码、管理多仓库版本、编译、烧录、调试,全部通过 west 完成。

初次接触 Zephyr 的人最容易被 west 绕晕。其实只需要记住两件事:

第一,west 的所有子命令都与项目构建流程相关,比如 west build 、 west flash 、 west debug 。

第二,west 管理的是一个 workspace,也就是以 zephyr 主仓库为中心的一组相关仓库。整个 Zephyr 生态不是单一代码库,而是由 zephyr、hal_stm32、hal_nordic、mcuboot 等多个仓库组成的集合。

3. Zephyr 与 FreeRTOS 深度对比:2026 年嵌入式项目选型参考

这一章节直接给结论:Zephyr 和 FreeRTOS 在 2026 年并不是完全对立的替代关系,而是两种不同项目需求下的不同答案。下面从六个维度做对比。

对比维度 Zephyr FreeRTOS
本质定位 面向物联网和连接设备的操作系统 轻量级实时调度内核
内核最小体积 几十 KB 级,可以裁剪 几 KB 级,极致轻量
硬件抽象层 Devicetree + 驱动框架,统一接口 无标准硬件抽象,驱动由厂商提供
协议栈支持 BLE、Wi-Fi、Thread、Zigbee、802.15.4 等原生集成 需自行集成第三方协议栈
构建系统 CMake + west,支持 Kconfig 配置 Makefile / CMake,无统一配置体系
许可证 Apache 2.0 MIT(内核部分)
主要适用场景 智能家居、可穿戴、工业物联网、车联网 简单任务调度、资源受限 MCU、教学
社区生态 Linux 基金会主导,厂商参与度高 生态成熟,资料海量

从这张表可以提炼出三个关键判断。

第一,如果项目只有一个传感器采集任务和一个上报任务,MCU 资源极度紧张,FreeRTOS 仍然是最好的选择。它轻、快、稳定,而且团队里几乎人人都会用。

第二,如果项目需要同时跑 BLE 和 Wi-Fi,还要考虑 OTA 和功耗管理,Zephyr 的集成度优势非常明显。你不会想把 NimBLE、LwIP、MCUboot 一个个手动拼起来。

第三,Zephyr 的学习曲线更陡,但学到的知识可迁移性强。因为它背后的 Devicetree、Kconfig、CMake 体系,和 Linux 开发经验是相通的。换句话说,学会 Zephyr,你掌握的其实是一套更接近现代嵌入式工程化的思维。

4. Zephyr 环境搭建与基础配置

明确一下环境假设:本文以 Ubuntu 22.04 或 Windows 10/11 + WSL2 为主要开发环境。如果你只装了 Windows 原生环境,建议优先装一个 WSL2,因为 Zephyr 的官方工具链脚本对类 Unix 环境支持最好。这不是说 Windows 完全不可行,而是从工程效率角度,WSL2 会让后续操作顺畅很多。

4.1 安装必要依赖

无论什么环境,先确保 Python 版本在 3.8 以上,并准备好 pip 和 cmake。下面以 Ubuntu 环境为例:

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

这里用到 dfu-util 是因为很多 Zephyr 支持的开发板通过 DFU 模式烧录; device-tree-compiler 用来编译设备树; ninja-build 是 Zephyr 默认的构建后端,比 Make 快很多。

4.2 安装 west 并初始化工作目录

Zephyr 不推荐直接把源码 clone 到任意文件夹,而是用 west 创建一个规范的 workspace。建议给代码单独建一个目录,例如 zephyrproject 。

pip install west
mkdir ~/zephyrproject && cd ~/zephyrproject
west init
west update

west init 会拉取默认的 manifest 文件, west update 则会根据 manifest 把 zephyr、hal 库、第三方模块全部下载到本地。这个操作需要联网,首次拉取数据量在 1GB 以上,耐心等待即可。

4.3 安装编译工具链

Zephyr 官方推荐使用 Zephyr SDK。SDK 里包含了针对不同架构的交叉编译器、调试器和 QEMU 支持。

cd ~
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/latest/download/zephyr-sdk-<VERSION>_linux-x86_64.tar.xz
tar xf zephyr-sdk-<VERSION>_linux-x86_64.tar.xz
cd zephyr-sdk-<VERSION>
./setup.sh

安装完成后,把工具链路径导出到环境变量中:

export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk-<VERSION>
export ZEPHYR_TOOLCHAIN_VARIANT=zephyr

注意: <VERSION> 请替换为你实际下载的 SDK 版本号,不要照抄。如果你使用的开发板是 STM32 系列,也可以直接用 ARM GCC 工具链,但用 Zephyr SDK 能少踩很多版本匹配的坑。

4.4 环境变量验证

安装完成后,验证环境是否基本就绪。进入 zephyr 仓库目录并查看版本信息:

cd ~/zephyrproject/zephyr
source zephyr-env.sh
west --version

如果能看到 west 版本号和 Zephyr 版本提示,环境就基本搭建完成了。

5. 使用 Workbench for Zephyr 与 Kconfig 图形化配置

Zephyr 的 Kconfig 体系在命令行下确实能完成所有配置,但配置项太多时,记忆成本很高。这就是“Workbench for Zephyr”这类工具能发挥作用的地方。

5.1 什么是 Workbench for Zephyr

简单说,Workbench for Zephyr 是基于 VS Code 的图形化开发环境。它将工程管理、Kconfig 配置、编译、烧录、调试集成到一个界面中,降低纯命令行操作的认知负担。对于刚接触 Zephyr 的开发者,它可以让你先通过图形界面理解配置体系,再逐步过渡到命令行。

在 2026 年的实际开发中,团队里往往是懂内核的人用命令行,应用层开发者在 Workbench 中完成日常构建和调试。

5.2 Kconfig 图形化配置入口

即使不使用 Workbench 的完整 IDE,Zephyr 自身也提供了终端 UI 方案。进入任意一个 build 目录后运行:

west build -t guiconfig

系统会打开图形化配置界面。你也可以用:

west build -t menuconfig

menuconfig 是基于终端菜单方式的配置界面,操作逻辑与 Linux 内核配置完全一致。对于习惯键盘操作的人,这种方式的效率反而更高。

在实际项目里,我们更常采用的方式是直接维护 prj.conf 文件。下图是一个典型的 BLE 项目配置:

# 文件路径:prj.conf
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Zephyr_BLE_Device"
CONFIG_BT_PRIVACY=y
CONFIG_LOG=y

Kconfig 的价值在于:它把所有功能开关收敛到可审查、可版本管理的配置文件中,而不是散落在代码各处。这一点在后期的工程维护中价值极大。

6. Zephyr 完整示例:最小工程编译与运行

现在进入真正的实操环节。我们从一个最基础的 Hello World 工程开始,再到一个带 GPIO 控制的 Blinky 工程,完整跑通编译、烧录、验证的整个流程。

6.1 Hello World 示例

Zephyr 官方自带大量示例,Hello World 位于 zephyr/samples/hello_world 。先查看目录结构:

cd ~/zephyrproject/zephyr/samples/hello_world
ls -l

核心文件有三个:

  • prj.conf :工程配置文件,本示例中保持为空即可。
  • src/main.c :程序入口。
  • CMakeLists.txt :构建脚本。

main.c 的内容如下:

// 文件路径:samples/hello_world/src/main.c
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

void main(void)
{
    printk("Hello World! %s\n", CONFIG_BOARD);
}

注意这里的头文件写法。 <zephyr/kernel.h> 是 Zephyr 2.6 以后推荐的标准头文件路径,老代码里常见的 <zephyr.h> 如今也会被兼容,但新项目建议统一使用带 zephyr/ 前缀的路径。

6.2 编译命令

在 hello_world 目录下执行:

west build -b qemu_cortex_m3

这里 -b 指定目标板卡。 qemu_cortex_m3 是模拟的 Cortex-M3 开发板,不需要真实硬件就能验证编译和运行流程。如果你手上有具体的开发板,例如 nucleo_f103rb 或 nrf52840dk_nrf52840 ,直接替换板卡名即可。

第一次编译会初始化构建目录并下载相关依赖,可能需要几分钟。

6.3 运行与验证

因为目标平台是 QEMU 模拟板,编译完成后可以直接用 QEMU 运行:

west build -t run

如果一切正常,终端会输出类似下面的结果:

*** Booting Zephyr OS build zephyr-v3.x-xxxx ***
Hello World! qemu_cortex_m3

看到这行输出,说明 Zephyr 的最小系统已经成功运行。

6.4 Blinky 示例:GPIO 与设备树结合

接下来做一个小而完整的硬件示例。以 nrf52840dk_nrf52840 开发板为例,演示如何通过设备树配置 LED 引脚。

官方 Blinky 示例路径是 samples/basic/blinky ,其 main.c 核心逻辑如下:

// 文件路径:samples/basic/blinky/src/main.c
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/devicetree.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 (!device_is_ready(led.port)) {
        return -1;
    }

    gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);

    while (1) {
        gpio_pin_toggle_dt(&led);
        k_msleep(500);
    }
    return 0;
}

这段代码很短,但包含两个重要知识点:

第一, DT_ALIAS(led0) 通过设备树别名获取 LED 节点的引用,实际引脚在 nrf52840dk_nrf52840.dts 中定义。

第二, gpio_pin_configure_dt 和 gpio_pin_toggle_dt 是 Zephyr 的新版 GPIO API,它们自动适配设备树里的引脚配置,开发者不需要手写寄存器操作。

编译命令:

west build -b nrf52840dk_nrf52840 samples/basic/blinky
west flash

烧录成功后,开发板上的 LED 会以 0.5 秒间隔闪烁。

7. Devicetree 机制:Zephyr 硬件抽象的精髓

如果说 Kconfig 解决了“软件功能怎么选”,Devicetree 解决的就是“硬件资源怎么描述”。这一章用通俗的语言拆解 Devicetree,因为它是许多 Zephyr 初学者最不容易跨过的坎。

7.1 没有 Devicetree 时的开发方式

传统 MCU 开发中,开发者通常依赖厂商提供的 HAL 库。比如 STM32 项目里,要让某个引脚输出高电平,需要打开 .ioc 文件,在可视化界面里配置引脚模式,然后重新生成初始化代码。一旦换了引脚或 MCU 型号,需要重新生成工程。

这种方式的缺点在于:硬件配置过程和业务代码是强绑定的,板级资源变更会直接引发代码级修改。

7.2 Devicetree 的解决思路

Devicetree 将硬件描述固化成文本文件,与 C 代码分离。当硬件引脚变化时,只改 dts 文件,不需要改 main.c。

看一个实际的 LED 定义:

/ {
    aliases {
        led0 = &red_led;
    };

    leds {
        compatible = "gpio-leds";
        red_led: led_0 {
            gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
            label = "Red LED";
        };
    };
};

这段描述告诉系统两件事:LED 连接在 GPIO0 的第 13 号引脚,低电平有效。对应的 C 代码只需要通过 DT_ALIAS(led0) 获取引用,系统会自动完成寄存器映射。

7.3 使用 Overlay 文件做板级适配

实际项目更常见的情况是:开发板本身有默认的设备树,但你的产品硬件改了引脚。这时候不要直接修改厂商板级 dts 文件,而是使用 overlay 文件覆盖。

在工程根目录下创建 app.overlay :

// 文件路径:app.overlay
/ {
    aliases {
        led0 = &custom_led;
    };
};

&gpio1 {
    status = "okay";
};

custom_led: led_custom {
    compatible = "gpio-leds";
    gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
    label = "Custom LED";
};

然后在 CMakeLists.txt 中指定:

set(DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/app.overlay")

这样,同一套业务代码可以支持不同引脚定义的不同硬件版本。在产品线需要做到“一套固件多种硬件”时,这个能力非常有价值。

8. Zephyr 常见问题与排查方法

从环境搭建到实际编译,开发者最常遇到的坑集中在工具链匹配、依赖下载速度和设备树配置三个方面。下面整理成表格,方便日常检索。

问题现象 可能原因 排查方式 解决方案
west init 拉取失败 网络不通或 manifest 仓库被墙 检查网络,重试 配置代理或镜像源,重试 west init
west update 中途报错 某个子仓库拉取失败 查看错误提示中的仓库名 单独进入对应仓库目录 git pull 后再执行 west update
编译时报找不到头文件 SDK 环境变量未设置 运行 echo $ZEPHYR_SDK_INSTALL_DIR source zephyr-env.sh ,重新 export 环境变量
板卡名称拼写错误 对目标板不熟悉 west boards 查看支持的板卡 从列表中找到准确的板卡名
烧录提示无法连接设备 板卡未进入烧录模式或驱动问题 检查 USB 设备是否被识别 按开发板手册进入 DFU/Bootloader 模式
设备树中引脚配置无效 overlay 文件未生效 确认 DTC_OVERLAY_FILE 设置 在 CMakeLists.txt 中显式指定 overlay 文件
编译很慢 首次构建拉取 HAL 库并全量编译 观察构建日志 使用 ccache, sudo apt install ccache

这里单独强调一个高频问题:在 Windows 原生环境下, west update 比较容易因为路径过长或软链接问题失败。使用 WSL2 后,这一系列问题基本消失。这也是为什么前文建议直接从 WSL2 开始。

9. 最佳实践与工程建议

Zephyr 的项目实践,有一些经验值得在工作开始前就固化到流程中。

9.1 使用版本管理锁定 Zephyr 版本

Zephyr 的迭代速度很快,不同版本之间的 API 变动不小。团队项目一定要把 west 的 manifest 文件纳入 Git 管理,并在文档中明确声明使用的 Zephyr 版本。否则“昨天还能编译,今天突然报错”的问题会频繁出现。

9.2 项目目录与源码目录分离

不要在 Zephyr 官方源码目录里直接改代码。更规范的做法是新建自己的 application 目录,把 src 、 prj.conf 、 CMakeLists.txt 、 boards 、 dts 等文件组织在项目仓库中。

my_app/
├── CMakeLists.txt
├── prj.conf
├── src/
│   └── main.c
└── boards/
    └── my_board.overlay

这样不仅便于 Git 版本管理,也让多个产品复用同一套 Zephyr SDK 成为可能。

9.3 配置文件与环境变量脚本化

环境变量( ZEPHYR_SDK_INSTALL_DIR 、 ZEPHYR_BASE 等)最好不要每次手动 export,而是写入 ~/.zephyrrc 或项目入口脚本。这样换一台电脑、新同事入职时,只需要执行一条 source 命令就能完成环境初始化。

9.4 先跑官方 samples,再修改,最后造轮子

Zephyr 的官方 samples 覆盖了内核、驱动、BLE、传感器、显示等几乎全部模块。遇到新外设时,优先找对应 sample,在其基础上改动,远比从零开始研究 HAL 手册效率高。

9.5 理解安全启动和 OTA 的设计

如果你的产品需要 FOTA 升级,Zephyr 生态里默认使用 MCUboot 作为 bootloader。这意味着从产品设计初期就要考虑分区表、密钥管理、签名校验等问题。这部分内容不是简单的功能叠加,而是系统级设计,建议在项目规划阶段就纳入技术选型。

9.6 团队学习路线的建议

对于从 FreeRTOS 迁移而来的团队,不建议一上来就追求复杂的多协议栈工程。更务实的路径是:先跑通 Hello World,再用 Blinky 理解设备树,接着做 GPIO 按键中断,然后逐步引入传感器驱动、通信协议、日志系统。每一步都验证通过后,再进入整体产品集成。

10. 选型判断:你的下一个项目到底该用谁

最后回到最开始的问题:2026 年做嵌入式项目,到底选 Zephyr 还是 FreeRTOS?

如果是做一个简单的温湿度传感器节点,一颗 8 位或低端 Cortex-M0 就能完成,整机资源紧张、固件体积要求苛刻,FreeRTOS 依然合适。因为这种项目几乎不需要考虑复杂的协议栈、低功耗管理和 OTA 流程,轻量就是最大的优势。

如果产品需要长久维护、需要保持多硬件版本兼容、需要不断加入新的连接协议或云平台能力,Zephyr 是更符合“系统工程”思路的选择。它前期投入的学习成本,会换来后续开发中更少的“野生封装”和“重复造轮子”。

还有一类项目需要特别提醒:如果你正在为公司内部的多个产品线做统一软件平台,Zephyr 的价值会成倍放大。因为它统一的构建方式、设备树描述和驱动接口,让不同产品线之间复用固件工程成为可能,而不是每个产品都变成一座独立的“技术孤岛”。

Zephyr 不是“另一个 RTOS”,它代表的是嵌入式开发向系统化、工程化演进的方向。选型没有绝对的对错,只有是否匹配你的项目阶段和团队能力。希望这篇 Zephyr 特别篇,能让你在 2026 年的技术选型中多一个清晰的选择项。

更多推荐