
在嵌入式开发领域Zephyr RTOS 凭借其模块化设计、跨平台支持和丰富的协议栈正成为越来越多开发者的首选。特别是对于 STM32F103C8T6 这类经典微控制器Zephyr 提供了完整的支持让开发者能够快速构建稳定可靠的嵌入式应用。本文将完整演示从零开始创建 Zephyr 项目、配置 STM32F103C8T6 最小系统板环境并进行全流程验证的实战过程。无论你是刚接触嵌入式开发的新手还是希望从其他 RTOS 迁移到 Zephyr 的有经验开发者本文都将提供一套可复现的完整方案。我们将从基础概念讲起逐步深入到具体的环境搭建、项目创建、代码编写和烧录验证确保每个步骤都有详细的说明和可运行的代码示例。1. Zephyr RTOS 与 STM32F103C8T6 基础介绍1.1 Zephyr RTOS 核心特性Zephyr 是一个开源的、可扩展的实时操作系统RTOS专为资源受限的嵌入式设备设计。与传统的 FreeRTOS 或 μC/OS 相比Zephyr 具有以下几个显著优势模块化架构Zephyr 采用高度模块化的设计开发者可以根据具体需求选择需要的组件避免不必要的资源占用。这种设计特别适合存储空间有限的嵌入式设备。完整的协议栈支持Zephyr 内置了对 Bluetooth、Wi-Fi、TCP/IP 等常用协议栈的支持大大简化了物联网设备的开发难度。跨平台兼容性Zephyr 支持多种处理器架构包括 ARM、x86、RISC-V 等为不同硬件平台的迁移提供了便利。活跃的社区支持作为 Linux 基金会旗下的项目Zephyr 拥有活跃的开发社区和定期的版本更新确保了技术的持续演进和完善。1.2 STM32F103C8T6 硬件特性分析STM32F103C8T6 是基于 ARM Cortex-M3 内核的微控制器因其性价比高、外设丰富而广受欢迎。该芯片的主要技术参数包括核心ARM Cortex-M3最高主频 72MHz存储64KB Flash20KB SRAM外设3个USART、2个SPI、2个I2C、1个CAN、2个ADC等封装LQFP48引脚数量适中适合学习和项目开发对于初学者而言STM32F103C8T6 最小系统板价格低廉相关资料丰富是学习嵌入式开发和 RTOS 的理想选择。1.3 为什么选择 Zephyr STM32F103C8T6 组合这个组合的优势在于平衡了学习成本和技术先进性。STM32F103C8T6 作为经典的入门级微控制器硬件资源足够运行完整的 Zephyr 系统同时 Zephyr 提供的现代化开发体验和丰富功能能够让开发者接触到当前嵌入式开发的最佳实践。2. 开发环境准备与工具安装2.1 系统环境要求在开始之前请确保你的开发环境满足以下基本要求操作系统Windows 10/11、Ubuntu 18.04 或 macOS 10.15磁盘空间至少 5GB 可用空间网络连接稳定的网络连接用于下载工具链和依赖包2.2 安装必要的开发工具Python 环境配置# 检查 Python 版本要求 3.8 及以上 python3 --version pip3 --version # 安装 west 工具这是 Zephyr 的主要项目管理工具 pip3 install west安装 Zephyr SDK Zephyr SDK 包含了编译、调试和烧录所需的所有工具链。# 下载 Zephyr SDK以 Linux 为例 wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.0/zephyr-sdk-0.16.0_linux-x86_64.tar.xz # 解压到合适目录 tar xvf zephyr-sdk-0.16.0_linux-x86_64.tar.xz -C ~/ # 运行安装脚本 cd zephyr-sdk-0.16.0 ./setup.sh安装设备树编译器# Ubuntu/Debian sudo apt-get install device-tree-compiler # macOS brew install dtc2.3 获取 Zephyr 源码使用 west 工具获取 Zephyr 主源码和所有模块# 初始化 Zephyr 项目 west init ~/zephyrproject cd ~/zephyrproject # 更新所有模块 west update # 导出 Zephyr 环境变量 source zephyr/zephyr-env.sh2.4 验证环境安装完成安装后运行以下命令验证环境是否正确配置# 检查 west 版本 west --version # 检查工具链是否可用 arm-zephyr-eabi-gcc --version # 检查 Zephyr 环境变量 echo $ZEPHYR_BASE3. 创建第一个 Zephyr 项目3.1 项目结构规划在开始编码之前我们先规划项目的基本结构。一个标准的 Zephyr 项目通常包含以下文件my_zephyr_app/ ├── CMakeLists.txt # 项目构建配置 ├── prj.conf # 项目配置文件 ├── src/ │ └── main.c # 主程序文件 └── boards/ └── stm32f103c8t6.overlay # 设备树覆盖文件3.2 创建项目目录和文件首先创建项目目录结构# 创建项目目录 mkdir -p ~/zephyr_workspace/my_first_zephyr_app cd ~/zephyr_workspace/my_first_zephyr_app # 创建源代码目录 mkdir src mkdir boards3.3 编写 CMakeLists.txt创建 CMakeLists.txt 文件这是 Zephyr 项目的构建入口# CMakeLists.txt cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(my_first_zephyr_app) target_sources(app PRIVATE src/main.c)3.4 配置项目参数创建 prj.conf 配置文件设置项目的基本参数# prj.conf - 项目配置文件 # 启用控制台输出 CONFIG_PRINTKy CONFIG_STDOUT_CONSOLEy # 启用串口支持 CONFIG_SERIALy CONFIG_UART_CONSOLEy # 设置主频 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC72000000 CONFIG_SYS_CLOCK_TICKS_PER_SEC1000 # 启用 GPIO 支持 CONFIG_GPIOy # 设置堆栈大小 CONFIG_MAIN_STACK_SIZE2048 CONFIG_IDLE_STACK_SIZE10244. STM32F103C8T6 硬件配置4.1 引脚功能映射了解 STM32F103C8T6 的引脚功能对于正确配置设备树至关重要。以下是关键引脚的功能说明PA9/PA10USART1常用于串口通信PA2/PA3USART2备用串口PB6/PB7I2C1用于 I2C 设备连接PA4-PA7SPI1用于 SPI 设备PC13用户按钮在最小系统板上常用PA0用户LED在最小系统板上常用4.2 设备树配置创建 boards/stm32f103c8t6.overlay 文件配置硬件特性// stm32f103c8t6.overlay /dts-v1/; /plugin/; #include dt-bindings/pinctrl/stm32-pinctrl.h #include dt-bindings/clock/stm32_clock.h / { chosen { zephyr,console usart1; zephyr,shell-uart usart1; }; }; usart1 { status okay; current-speed 115200; pinctrl-0 usart1_tx_pa9 usart1_rx_pa10; pinctrl-names default; }; usart2 { status okay; current-speed 115200; pinctrl-0 usart2_tx_pa2 usart2_rx_pa3; pinctrl-names default; }; i2c1 { status okay; clock-frequency I2C_BITRATE_STANDARD; pinctrl-0 i2c1_scl_pb6 i2c1_sda_pb7; pinctrl-names default; }; spi1 { status okay; pinctrl-0 spi1_sck_pa5 spi1_miso_pa6 spi1_mosi_pa7; pinctrl-names default; }; gpioa { status okay; }; gpiob { status okay; }; gpioc { status okay; };5. 编写应用程序代码5.1 主程序框架创建 src/main.c 文件实现基本的 LED 闪烁功能// src/main.c #include zephyr/kernel.h #include zephyr/device.h #include zephyr/drivers/gpio.h #include zephyr/sys/printk.h /* 定义 LED 引脚 */ #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led GPIO_DT_SPEC_GET(LED0_NODE, gpios); /* 定义线程栈大小 */ #define STACKSIZE 1024 #define PRIORITY 7 /* 线程函数声明 */ void blink_thread(void *dummy1, void *dummy2, void *dummy3); /* 线程定义 */ K_THREAD_DEFINE(blink_id, STACKSIZE, blink_thread, NULL, NULL, NULL, PRIORITY, 0, 0); void main(void) { int ret; printk(Zephyr RTOS 应用程序启动\n); /* 检查 LED 设备是否就绪 */ if (!device_is_ready(led.port)) { printk(错误: LED 设备未就绪\n); return; } /* 配置 LED 引脚为输出 */ ret gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE); if (ret 0) { printk(错误: 无法配置 LED 引脚 (%d)\n, ret); return; } printk(应用程序初始化完成LED 线程已启动\n); } /* LED 闪烁线程 */ void blink_thread(void *dummy1, void *dummy2, void *dummy3) { ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); while (1) { /* LED 亮 */ gpio_pin_set_dt(led, 1); k_msleep(500); /* LED 灭 */ gpio_pin_set_dt(led, 0); k_msleep(500); printk(LED 状态切换\n); } }5.2 添加设备树别名为了正确识别 LED 引脚需要在设备树中定义别名。修改之前的 overlay 文件添加 LED 定义// 在 stm32f103c8t6.overlay 中添加以下内容 / { aliases { led0 user_led; }; leds { compatible gpio-leds; user_led: led_0 { gpios gpioa 0 GPIO_ACTIVE_HIGH; label User LED; }; }; };6. 项目构建与编译6.1 配置构建环境在项目根目录下设置构建目标板和工具链# 进入项目目录 cd ~/zephyr_workspace/my_first_zephyr_app # 设置环境变量 export ZEPHYR_BASE~/zephyrproject/zephyr source $ZEPHYR_BASE/zephyr-env.sh6.2 使用 west 构建项目使用 west 工具进行构建指定目标开发板# 构建项目目标板为 stm32f103c8t6 west build -b stm32f103c8t6 . # 或者使用完整的板卡名称如果上述不行 west build -b stm32_min_dev_blue .6.3 编译输出分析构建成功后会在项目目录下生成 build 文件夹包含以下重要文件build/zephyr/zephyr.elfELF 格式的可执行文件build/zephyr/zephyr.bin二进制烧录文件build/zephyr/zephyr.hexHex 格式烧录文件build/zephyr/.config最终使用的配置文编译过程中控制台会显示详细进度信息成功编译的典型输出如下[1/123] Building C object zephyr/CMakeFiles/offsets.dir/arch/arm/core/offsets/offsets.c.obj [123/123] Linking C executable zephyr/zephyr.elf Memory region Used Size Region Size %age Used FLASH: 14256 B 64 KB 21.76% SRAM: 4504 B 20 KB 21.99%7. 烧录与调试7.1 烧录工具准备根据你的开发环境选择合适的烧录工具ST-Link V2 烧录器推荐# 安装 openocd支持 ST-Link sudo apt-get install openocd # 使用 west 烧录 west flashJ-Link 烧录器# 确保 J-Link 驱动已安装 west flash --runner jlink7.2 硬件连接检查在烧录前确保硬件连接正确电源连接使用 USB 线或外部 3.3V 电源为开发板供电调试接口ST-Link 的 SWDIO、SWCLK、GND、3.3V 正确连接串口连接USB 转 TTL 模块连接到 PA9(TX)、PA10(RX)、GND7.3 执行烧录操作# 使用 west flash 命令烧录 west flash # 如果自动检测失败可以指定编程器 west flash --runner stm32cubeprogrammer烧录成功的输出示例-- west flash: using runner stm32cubeprogrammer -- runners.stm32cubeprogrammer: mass erase requested -- runners.stm32cubeprogrammer: flashing file: /path/to/zephyr.bin [] 100% -- runners.stm32cubeprogrammer: verify succeeded -- runners.stm32cubeprogrammer: resetting target8. 运行验证与调试8.1 串口监控配置烧录完成后使用串口工具监控程序输出# 安装 minicomLinux sudo apt-get install minicom # 配置串口根据实际端口调整 minicom -D /dev/ttyUSB0 -b 115200 # 或者使用 screenmacOS screen /dev/tty.usbserial-* 1152008.2 预期运行结果程序正常运行后串口终端应该显示类似以下信息*** Booting Zephyr OS build v3.4.0 *** Zephyr RTOS 应用程序启动 应用程序初始化完成LED 线程已启动 LED 状态切换 LED 状态切换 ...同时开发板上的 LED 应该以 1 秒的间隔闪烁。8.3 调试技巧如果程序运行不正常可以使用以下方法进行调试增加调试输出// 在代码中添加更多 printk 语句 printk(调试信息: 变量值 %d\n, variable); // 启用更详细的日志 CONFIG_LOGy CONFIG_LOG_MODE_IMMEDIATEy使用 GDB 调试# 启动 GDB 服务器 openocd -f interface/stlink.cfg -f target/stm32f1x.cfg # 另一个终端中启动 GDB arm-zephyr-eabi-gdb build/zephyr/zephyr.elf (gdb) target remote :3333 (gdb) monitor reset halt (gdb) load (gdb) continue9. 常见问题与解决方案9.1 编译阶段问题问题1west 命令未找到解决方案确保已正确安装 west 工具 pip3 install west export PATH$PATH:~/.local/bin问题2工具链路径错误错误信息arm-zephyr-eabi-gcc: command not found 解决方案重新安装 Zephyr SDK 并设置环境变量 source ~/zephyr-sdk-0.16.0/environment-setup问题3板卡配置不支持错误信息No board named stm32f103c8t6 found 解决方案使用正确的板卡名称或创建自定义板卡配置 west build -b stm32_min_dev_blue .9.2 烧录阶段问题问题4ST-Link 连接失败解决方案检查硬件连接安装正确的驱动 sudo apt-get install stlink-tools 确保 ST-Link 固件是最新版本问题5权限不足错误信息Unable to open USB device 解决方案将用户添加到 dialout 组 sudo usermod -a -G dialout $USER 重新登录生效9.3 运行阶段问题问题6程序运行但无输出解决方案检查串口连接和波特率设置 确认 TX/RX 线序正确波特率设置为 115200 检查设备树中串口配置是否正确问题7LED 不闪烁解决方案检查 LED 引脚定义和设备树配置 使用万用表测量引脚电压 确认 GPIO 配置为输出模式10. 项目扩展与进阶实践10.1 添加更多外设支持在现有项目基础上可以逐步添加更多功能模块添加按钮输入检测// 在 main.c 中添加按钮检测 #define BUTTON0_NODE DT_ALIAS(sw0) static const struct gpio_dt_spec button GPIO_DT_SPEC_GET(BUTTON0_NODE, gpios); // 配置按钮中断 gpio_pin_configure_dt(button, GPIO_INPUT); gpio_pin_interrupt_configure_dt(button, GPIO_INT_EDGE_TO_ACTIVE);添加 PWM 控制// 配置 PWM 控制 LED 亮度 #include zephyr/drivers/pwm.h static const struct pwm_dt_spec pwm_led PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));10.2 多线程编程实践创建多个协作线程体验 Zephyr 的多任务能力// 创建传感器读取线程 K_THREAD_DEFINE(sensor_id, STACKSIZE, sensor_thread, NULL, NULL, NULL, PRIORITY, 0, 0); void sensor_thread(void *dummy1, void *dummy2, void *dummy3) { while (1) { // 读取传感器数据 int sensor_value read_sensor(); printk(传感器值: %d\n, sensor_value); k_msleep(1000); } }10.3 电源管理优化对于电池供电设备实现低功耗优化// 配置低功耗模式 #include zephyr/pm/pm.h #include zephyr/pm/policy.h // 在空闲时进入低功耗模式 void enter_low_power_mode(void) { // 配置外设进入低功耗状态 // 设置唤醒源 // 进入睡眠模式 }通过本文的完整演示你应该已经掌握了 Zephyr RTOS 在 STM32F103C8T6 上的基本开发流程。从环境搭建到项目创建从代码编写到烧录验证每个步骤都提供了详细的说明和可运行的示例。Zephyr 作为一个现代化的 RTOS其模块化设计和丰富的功能栈为嵌入式开发带来了很多便利。建议在掌握基础之后继续探索 Zephyr 的更多高级特性如网络协议栈、文件系统、安全功能等这些都将帮助你在嵌入式开发领域走得更远。实际开发中遇到问题时不要忘记查阅 Zephyr 官方文档和社区资源这些通常能提供最权威的解决方案。