STM32 RT-Thread多任务同步与调度调试 - 第1节

1.1 RT-Thread 到底是什么?

先聊聊 RT-Thread 的背景。我最早接触它是在 2017 年,当时项目里需要一个轻量级 RTOS,又不想用 FreeRTOS 那种纯 C 风格——说实话,FreeRTOS 的 API 设计有点「原始」。RT-Thread 给我的第一印象是:它更像一个「小而全」的物联网操作系统,而不只是调度器。

它的内核架构,说白了就三层:

  • 底层:硬件抽象层(HAL),负责屏蔽芯片差异
  • 中间层:内核对象管理、调度器、IPC 通信
  • 上层:组件层(文件系统、网络协议栈、设备框架)

我习惯把 RT-Thread 比作「乐高积木」——你可以只拿内核跑裸机任务,也可以把文件系统、网络、GUI 全堆上去。嗯,这跟 Linux 的思路有点像,但资源开销小得多。

核心特点:

  • 支持多线程抢占式调度,优先级 256 级
  • 对象化设计:线程、信号量、互斥锁、事件、邮箱、消息队列都是对象
  • 组件丰富:DFS(虚拟文件系统)、LwIP、Finsh 控制台
  • 标准版 + Nano 版双线并行,Nano 版最小 ROM 仅 3KB

应用场景?我见过有人拿它做智能门锁、工业采集器、无人机飞控。说白了,只要你的 MCU 有 64KB Flash 以上,RT-Thread 就能跑得很舒服。

1.2 内核架构速览

RT-Thread 的内核不是「大而全」的宏内核,而是微内核风格。我画了张图帮你快速理解:

RT-Thread 内核架构图 硬件抽象层(HAL / libcpu / BSP) 内核层 线程管理 IPC(信号量/互斥锁/邮箱/消息队列) 内存管理 定时器 调度器(优先级抢占 + 时间片轮转) 设备驱动框架 组件层 DFS 文件系统 LwIP 网络协议栈 Finsh 控制台 POSIX 接口 用户应用层(你的业务代码)

你看,从下往上依次是:硬件抽象层 → 内核层 → 组件层 → 应用层。每一层都只依赖下层,不跨层调用。这种设计的好处是——你换芯片时,只需要改 BSP 和 HAL,上层代码基本不动。

我的经验: 刚开始学 RT-Thread 时,别急着研究组件层。先把内核层的线程、信号量、消息队列玩熟,后面加组件就是「搭积木」的事。

1.3 开发环境搭建

1.3.1 工具链选择

RT-Thread 官方推荐两套工具链:

工具 适用场景 我的建议
Keil MDK STM32 系列,调试方便,IDE 集成度高 新手首选,上手快
Env + GCC 跨平台,命令行操作,适合 CI/CD 我习惯用这个,灵活
RT-Thread Studio 官方 IDE,集成 Env + 调试器 适合不想折腾的人

我个人习惯用 Keil MDK + Env 的组合。Keil 负责编译调试,Env 负责包管理和配置。为什么这么搭?因为 Env 的 menuconfig 能帮你自动生成工程,省去手动添加文件的麻烦。

1.3.2 安装步骤

  1. 安装 Keil MDK:去 ARM 官网下载 MDK-ARM,版本 5.27 以上。注意要装好对应芯片的 Pack(比如 STM32F4xx_DFP)。
  2. 安装 Env 工具:从 RT-Thread 官网下载 Env 压缩包,解压到无中文路径。双击 env.exe 启动。
  3. 配置环境变量:Env 会自动配置 Python、scons、gcc 路径。如果报错,检查一下系统 PATH 里有没有冲突。
  4. 验证安装:在 Env 终端输入 scons --version,看到版本号就说明成功了。

避坑指南: 我曾经在 Win10 上装 Env 时,因为 Python 3.9 版本太高,导致 scons 报错。后来换成 Python 3.8 就好了。建议用 Env 自带的 Python,别自己装。

1.4 创建第一个 RT-Thread 工程

好,环境搭好了,咱们动手创建一个工程。以 STM32F407ZGT6 为例。

1.4.1 使用 Env 生成工程

打开 Env 终端,cd 到你的工作目录,执行:

mkdir my_first_rtthread
cd my_first_rtthread
scons --dist

这个命令会从 RT-Thread 源码仓库拉取最新代码,并生成一个 dist 目录。里面包含了完整的工程模板。

然后进入 dist 目录,找到 bsp/stm32f407-atk-explorer(根据你的板子选对应的 BSP)。执行:

menuconfig

你会看到一个图形化配置界面。这里可以开关组件、配置内核参数。第一次用,保持默认就行。按 Esc 退出并保存。

最后执行:

scons --target=mdk5

这会在 BSP 目录下生成 Keil 工程文件 project.uvprojx。

1.4.2 在 Keil 中编译与下载

双击打开 project.uvprojx,你会看到工程里已经包含了 RT-Thread 内核源码、BSP 驱动、启动文件。直接点 Build(F7),应该能零错误编译通过。

然后连接 ST-Link,点 Download(F8),把固件烧进板子。打开串口助手(波特率 115200),按复位键,你会看到 RT-Thread 的启动 Logo:

 \ | /
- RT -     Thread Operating System
 / | \     4.0.3 build Mar 10 2023
 2006 - 2022 Copyright by RT-Thread team
msh >

看到 msh > 提示符了吗?恭喜,你的第一个 RT-Thread 系统跑起来了!

1.4.3 写一个简单的线程

咱们来写个线程,让 LED 闪烁。在 applications/main.c 中添加:

#include <rtthread.h>
#include <board.h>

#define LED_PIN    GET_PIN(F, 9)   // 根据你的板子改引脚

static void led_thread_entry(void *parameter)
{
    while (1)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
}

int main(void)
{
    rt_thread_t led_thread = rt_thread_create("led",
                                              led_thread_entry,
                                              RT_NULL,
                                              1024,
                                              20,
                                              10);
    if (led_thread != RT_NULL)
        rt_thread_startup(led_thread);

    return 0;
}

编译下载后,LED 应该以 1Hz 频率闪烁。嗯,这里要注意:rt_thread_mdelay 是毫秒级延时,它会主动让出 CPU,不会阻塞其他线程。

我的经验: 刚开始写线程时,栈大小(第三个参数)别给太小。我见过有人给 256 字节,结果线程一跑就崩。STM32 上建议至少 1024 字节起步。

1.5 本章小结

这一章我们干了三件事:

  • 理解了 RT-Thread 的「三层架构」——硬件抽象、内核、组件
  • 搭好了 Keil + Env 的开发环境
  • 跑通了第一个多线程程序(LED 闪烁)

说白了,RT-Thread 没那么神秘。它就是一个帮你管理 CPU 时间的「管家」。你只需要告诉它:什么时候该做什么事,剩下的调度、同步、通信,它都帮你搞定。