Zephyr RTOS入门实战:基于STM32F103C8T6的环境搭建与项目开发

发布时间:2026/7/17 19:06:48
Zephyr RTOS入门实战:基于STM32F103C8T6的环境搭建与项目开发 在实际嵌入式开发中很多开发者习惯了使用厂商提供的 HAL 库或直接寄存器操作但当项目需要跨平台、模块化或长期维护时一个稳定且可移植的 RTOS 就变得至关重要。Zephyr RTOS 作为 Linux 基金会旗下的开源项目不仅支持包括 STM32F103C8T6 在内的数百种开发板还提供了统一的设备树、配置系统和丰富的驱动生态特别适合需要长期迭代的物联网和边缘计算项目。但 Zephyr 的入门门槛并不低——它的构建系统基于 CMake 和 Python配置使用 Kconfig设备树描述硬件再加上 West 元工具管理多仓库新手很容易在环境搭建和项目创建阶段卡住。本文将以 STM32F103C8T6 最小系统板为例完整演示从环境准备、项目创建、配置修改、编译烧录到运行验证的全流程并重点解释每一步背后的设计逻辑和常见坑点。1. 理解 Zephyr 项目结构和工作机制Zephyr 不是一个传统的“库头文件”型 RTOS而是一个完整的嵌入式开发框架。它的核心设计思想是“描述而非硬编码”——硬件资源通过设备树Devicetree描述功能选项通过 Kconfig 配置构建流程通过 CMake 组织。这种设计让同一份应用代码可以无需修改就能在不同架构的芯片上运行。1.1 设备树Devicetree如何抽象硬件设备树是 Zephyr 硬件抽象的核心。它是一个树形结构的数据文件.dts用文本方式描述 CPU、内存、外设、中断、时钟、引脚复用等硬件信息。编译时设备树会被处理成头文件devicetree.h应用程序通过统一的 API 访问硬件资源。对于 STM32F103C8T6Zephyr 已经提供了现成的设备树定义。你不需要从头编写但需要知道如何查找和覆盖默认配置。例如默认的 UART 引脚可能不符合你的板子布局这时可以在项目层覆盖设备树节点。1.2 Kconfig 如何管理功能配置Kconfig 是 Linux 内核使用的配置系统Zephyr 继承了这一机制。所有可配置的功能如任务栈大小、日志级别、外设使能都通过 Kconfig 定义。用户可以通过prj.conf文件或交互式菜单menuconfig修改这些配置。理解 Kconfig 的层次很重要架构层ARM Cortex-M→ SoC 层STM32F1→ 板级层STM32F103C8T6→ 项目层。项目层的配置会覆盖底层默认值。1.3 West 元工具的作用West 是 Zephyr 的元工具用于管理多个 Git 仓库Zephyr 主仓库、模块仓库、项目仓库。它不仅能拉取代码还能执行构建、烧录、调试等命令。West 的设计避免了将全部代码放在一个仓库导致的臃肿但也意味着网络环境会影响初始化速度。2. 环境准备工具链、依赖和源码获取Zephyr 环境对主机平台有一定要求以下步骤在 Ubuntu 22.04 和 Windows 11WSL2 Ubuntu下验证通过。其他 Linux 发行版或 macOS 可能需要调整包管理器命令。2.1 安装系统依赖和工具链Zephyr 需要 Python 3.8、CMake 3.20 和合适的编译工具链。对于 STM32F103C8T6Cortex-M3我们使用 Zephyr SDK 中的 ARM None EABI 工具链。# 更新包索引并安装基础依赖 sudo apt update sudo apt install -y --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 版本需 ≥3.20 cmake --version如果 CMake 版本过低可以从 Kitware 或 CMake 官网下载最新版本。2.2 获取 Zephyr 源码和 SDKZephyr 推荐使用 West 管理源码。首先获取 West 并初始化工作空间# 安装 West pip3 install --user west echo export PATH~/.local/bin:$PATH ~/.bashrc source ~/.bashrc # 创建并进入工作目录 mkdir -p ~/zephyrproject cd ~/zephyrproject # 使用 West 初始化指定主分支避免版本过旧 west init -m https://github.com/zephyrproject-rtos/zephyr.git --mr main # 拉取所有模块需要网络畅通耗时较长 west update接下来安装 Zephyr SDK包含工具链和调试工具# 下载 SDK 安装脚本替换为最新版本号 cd ~ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.5/zephyr-sdk-0.16.5_linux-x86_64.tar.xz # 解压并运行安装脚本 tar xvf zephyr-sdk-0.16.5_linux-x86_64.tar.xz cd zephyr-sdk-0.16.5 ./setup.sh # 安装 udev 规则允许非 root 用户访问调试器 sudo cp ~/zephyr-sdk-0.16.5/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d/ sudo udevadm control --reload2.3 设置环境变量Zephyr 需要几个环境变量才能正确找到工具链和源码# 添加到 ~/.bashrc根据实际路径调整 echo export ZEPHYR_BASE~/zephyrproject/zephyr ~/.bashrc echo source $ZEPHYR_BASE/zephyr-env.sh ~/.bashrc source ~/.bashrc验证环境是否就绪# 检查工具链 arm-zephyr-eabi-gcc --version # 检查 West west --version如果命令都能正常输出版本信息说明基础环境已准备好。3. 创建第一个 Zephyr 项目Zephyr 项目可以放在工作空间内的任何位置。我们创建一个独立于 Zephyr 源码的项目便于版本管理。3.1 项目目录结构设计一个典型的 Zephyr 项目包含以下文件my_zephyr_app/ ├── CMakeLists.txt # 告诉 CMake 这是 Zephyr 项目 ├── prj.conf # Kconfig 配置功能选项 ├── boards/ # 板级覆盖文件可选 │ └── stm32f103c8t6.overlay # 设备树覆盖 └── src/ └── main.c # 应用代码创建这个结构mkdir -p ~/my_zephyr_app/{boards,src} cd ~/my_zephyr_app3.2 编写项目定义文件CMakeLists.txt是项目的入口必须包含以下内容# 最低 CMake 版本要求 cmake_minimum_required(VERSION 3.20.0) # 项目名称可任意但会影响生成的文件名 find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(my_zephyr_app) # 指定源码目录 target_sources(app PRIVATE src/main.c)prj.conf用于配置内核和组件功能。对于基础演示我们使能日志和串口# 启用控制台输出 CONFIG_PRINTKy CONFIG_CONSOLEy CONFIG_UART_CONSOLEy # 启用日志系统便于调试 CONFIG_LOGy CONFIG_LOG_MODE_IMMEDIATEy # 启用串口1STM32F103C8T6 的 USART1 CONFIG_SERIALy CONFIG_UART_INTERRUPT_DRIVENy3.3 编写应用代码在src/main.c中我们实现一个简单的闪烁 LED 和串口输出程序。STM32F103C8T6 最小系统板通常有一个连接在 PC13 的 LED#include zephyr/kernel.h #include zephyr/drivers/gpio.h #include zephyr/sys/printk.h /* 获取 LED0 的设备树节点对应 PC13 */ #define LED0_NODE DT_ALIAS(led0) /* 检查节点是否存在并获取 GPIO 设备 */ static const struct gpio_dt_spec led GPIO_DT_SPEC_GET(LED0_NODE, gpios); void main(void) { int ret; int count 0; printk(Zephyr LED blinky example started on STM32F103C8T6\n); /* 检查 LED 设备是否就绪 */ if (!device_is_ready(led.port)) { printk(Error: LED device is not ready\n); return; } /* 配置 GPIO 为输出模式 */ ret gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE); if (ret 0) { printk(Error configuring GPIO: %d\n, ret); return; } while (1) { /* 切换 LED 状态 */ ret gpio_pin_toggle_dt(led); if (ret 0) { printk(Error toggling GPIO: %d\n, ret); return; } printk(Blink count: %d\n, count); /* 延时 1000 毫秒 */ k_msleep(1000); } }3.4 处理设备树覆盖STM32F103C8T6 的 LED 通常接在 PC13但 Zephyr 的默认设备树可能没有定义led0别名。我们需要在boards/stm32f103c8t6.overlay中添加/dts-v1/; /plugin/; / { /* 定义 led0 别名指向 PC13 */ aliases { led0 led0; }; /* 在 soc 节点下添加 led0 定义 */ soc { led0: led { compatible gpio-leds; gpios gpioc 13 GPIO_ACTIVE_HIGH; label User LED; }; }; };这个覆盖文件会在编译时合并到默认设备树中确保DT_ALIAS(led0)能正确解析。4. 编译配置与构建过程详解Zephyr 的构建系统会根据目标板自动选择工具链、编译选项和链接脚本。我们需要指定目标板和构建类型。4.1 配置构建参数在项目目录下使用 West 构建cd ~/my_zephyr_app # 为 stm32f103c8t6 板卡构建生成调试版本便于调试 west build -b stm32f103c8t6 --build-dir build_debug关键参数说明-b stm32f103c8t6指定目标板必须与 Zephyr 支持的板卡名称完全一致--build-dir build_debug指定构建输出目录避免污染源码构建过程会解析设备树包括覆盖文件生成 Kconfig 配置合并 prj.conf 和默认配置运行 CMake 生成构建文件编译源码并链接为 ELF 文件4.2 处理常见构建错误第一次构建很容易遇到问题以下是典型错误和解决方案错误1板卡名称不存在ERROR: unknown board stm32f103c8t6解决方案检查板卡名称是否拼写正确。可用west boards查看支持的板卡列表。错误2设备树语法错误ERROR: .../boards/stm32f103c8t6.overlay:5.1-8 syntax error解决方案检查设备树覆盖文件语法确保节点路径和属性格式正确。错误3Python 模块缺失ModuleNotFoundError: No module named elftools解决方案安装缺失的 Python 模块pip3 install pyelftools。构建成功后会在build_debug/zephyr目录下生成zephyr.elf、zephyr.bin和zephyr.hex等文件。5. 烧录方法与运行验证STM32F103C8T6 支持多种烧录方式最常用的是 ST-Link 和串口 DFU。这里以 ST-Link V2 为例。5.1 连接硬件将 ST-Link V2 的 SWDIO、SWCLK、GND、3.3V 分别连接到 STM32F103C8T6 的对应引脚SWDIO → PA13SWCLK → PA14GND → GND3.3V → 3.3V同时连接串口用于查看输出USB-TTL 的 TX → STM32 的 PA10USART1_RXUSB-TTL 的 RX → STM32 的 PA9USART1_TXGND → GND5.2 烧录固件使用 West 烧录确保 ST-Link 驱动已安装# 烧录到板卡 west flash --build-dir build_debug如果烧录成功会看到类似输出-- west flash: using runner stm32cubeprogrammer [STLink]: connected! [STLink]: Erasing flash... [STLink]: Programming flash... [STLink]: Verifying flash... [STLink]: Reset the device... -- west flash: completed5.3 验证程序运行打开串口终端如 PuTTY、minicom 或 picocom配置为 115200 波特率、8 数据位、无校验、1 停止位# 查看可用串口设备 ls /dev/ttyUSB* # 使用 picocom 连接根据实际设备名调整 picocom -b 115200 /dev/ttyUSB0如果一切正常你会看到Zephyr LED blinky example started on STM32F103C8T6 Blink count: 0 Blink count: 1 Blink count: 2 ...同时板载 LEDPC13应该以 1 秒间隔闪烁。6. 环境验证与问题排查即使烧录成功程序也可能因配置错误而无法正常运行。以下是系统的验证和排查方法。6.1 环境完整性检查清单在进入复杂项目前先用这个清单验证基础环境[ ] West 能识别板卡west boards | grep stm32f103c8t6[ ] 工具链能编译简单程序arm-zephyr-eabi-gcc --version[ ] ST-Link 能被系统识别lsusb | grep ST-Link[ ] 串口设备权限正确ls -l /dev/ttyUSB0当前用户应有读写权限[ ] 设备树覆盖语法正确dtc -I dts -O dtb -o /dev/null boards/stm32f103c8t6.overlay6.2 常见运行问题排查表问题现象可能原因检查方法解决方案烧录成功但无串口输出1. 串口引脚配置错误2. 波特率不匹配3. 设备树覆盖未生效1. 检查设备树中 UART 引脚2. 确认代码和终端波特率一致3. 查看编译日志中的设备树合并结果1. 确认 USART1 使用 PA9/PA102. 统一使用 115200 波特率3. 检查覆盖文件路径和语法LED 不闪烁1. LED 引脚定义错误2. GPIO 配置错误3. 时钟未使能1. 检查设备树中 LED 节点2. 验证 gpio_pin_configure_dt 返回值3. 查看 GPIO 控制器状态1. 确认 PC13 对应 led0 别名2. 检查返回值处理逻辑3. 确保 GPIOC 时钟在设备树中使能程序运行但不打印日志1. 日志配置错误2. 控制台输出未指向串口3. 栈大小不足1. 检查 prj.conf 中的 LOG 配置2. 确认 CONFIG_UART_CONSOLE 指向正确 UART3. 增加主栈大小1. 确保 CONFIG_LOGy2. 确认使用 USART1 作为控制台3. 设置 CONFIG_MAIN_STACK_SIZE2048烧录失败1. ST-Link 连接问题2. 芯片写保护3. 电源不稳定1. 检查 SWD 连线2. 尝试擦除整个芯片3. 测量 3.3V 电压1. 重新连接 SWD 线2. 使用 ST-Link Utility 解除保护3. 确保供电充足6.3 调试技巧从简单到复杂当程序行为不符合预期时按这个顺序排查最小化测试先注释掉所有功能只保留一个 printk(Hello)确认基础通信正常。分模块验证先测试 GPIO 控制 LED再测试 UART 输出最后组合功能。检查设备树使用west build -t menuconfig查看最终配置确认设备树覆盖已生效。查看映射文件检查build_debug/zephyr/zephyr.dts查看合并后的设备树确认硬件资源分配正确。启用详细日志在prj.conf中添加CONFIG_LOG_LEVEL_DBGy查看内核详细运行日志。7. 生产环境注意事项学习环境能跑通只是第一步实际项目还需要考虑以下因素。7.1 配置管理策略版本控制将prj.conf和设备树覆盖文件纳入版本控制但不要提交build目录。配置分层为不同环境开发、测试、生产创建不同的配置文件如prj_dev.conf、prj_prod.conf通过-DOVERLAY_CONFIGprj_prod.conf切换。参数调优生产环境应关闭调试功能优化内存配置# 生产配置示例 CONFIG_DEBUGn CONFIG_LOGn CONFIG_ASSERTn CONFIG_MAIN_STACK_SIZE10247.2 烧录和部署流程批量烧录使用west flash --runner stm32cubeprogrammer --hex-file build_prod/zephyr.hex脚本化烧录。版本标识在代码中嵌入版本号便于现场排查printk(Firmware version: %s\n, CONFIG_VERSION_STRING);回滚机制如果支持 bootloader如 MCUboot设计双镜像备份和回滚策略。7.3 资源监控和优化STM32F103C8T6 只有 64KB Flash 和 20KB RAM需要密切关注资源使用# 查看内存占用 arm-zephyr-eabi-size build_debug/zephyr/zephyr.elf # 输出示例 text data bss dec hex filename 25456 156 4248 29860 74a4 zephyr.elf如果资源紧张可以考虑禁用不必要的外设驱动使用CONFIG_SIZE_OPTIMIZATIONSy启用尺寸优化减少任务栈大小但要留有余量使用内存池替代动态分配从学习到生产最关键的是理解 Zephyr 的配置系统和设备树机制。只有清楚每个配置项和硬件描述的作用才能在问题出现时快速定位。STM32F103C8T6 作为经典的 Cortex-M3 芯片是学习 Zephyr 的理想平台但实际项目中要根据资源需求选择合适的芯片。下一步可以尝试添加传感器驱动、网络协议栈或电源管理功能逐步掌握 Zephyr 的全套能力。