1. 课程导入

各位同学好,我是你们这趟嵌入式实战课的老司机。今天咱们先不急着敲代码,把地基打牢了,后面盖楼才稳当。

RT-Thread,说白了就是一个国产的、开源的、物联网操作系统。我最早接触它是在2017年,那时候项目里要用一个轻量级系统跑传感器采集,FreeRTOS太“裸”,Linux又太重。RT-Thread刚好卡在中间——既有实时内核,又有丰富的组件生态。嗯,这一用就再也没换过。

1.1 RT-Thread 到底是什么?

RT-Thread 是一个 实时多线程操作系统(RTOS)。它的核心是一个高效的任务调度器,能让你把复杂的嵌入式程序拆成多个独立的任务(线程),然后按优先级和时间片轮流跑。

我习惯把它比作一个“软件层面的中断控制器”——你不需要关心CPU下一秒在干嘛,系统会帮你安排好。

RT-Thread 的三大核心能力:

  • 线程管理:创建、删除、挂起、恢复线程
  • 同步与通信:信号量、互斥量、消息队列、事件集
  • 内存管理:静态/动态内存分配,内存池

你想想看,如果不用RTOS,你写一个STM32程序,主循环里要轮询按键、刷新屏幕、处理传感器数据、还要响应串口中断……代码很快就变成一坨“意大利面”。有了RT-Thread,每个功能独立成一个线程,清爽多了。

1.2 应用场景:什么时候该用它?

不是所有项目都需要上RTOS。我见过有人用RT-Thread点个LED灯,那纯属杀鸡用牛刀。但下面这些场景,我强烈建议你上RT-Thread:

场景 典型设备 为什么用RT-Thread
物联网终端 智能家居网关、数据采集器 需要同时处理网络协议栈、传感器驱动、用户交互
工业控制 PLC、电机驱动器 实时性要求高,多个控制环路并行
消费电子 智能手表、手持设备 低功耗管理 + 图形界面
车载电子 OBD诊断仪、车机控制 多任务并发,安全等级要求高

我的经验: 如果你项目里需要同时处理3个以上异步事件(比如按键、定时器、串口数据),或者需要用到TCP/IP协议栈、文件系统,直接上RT-Thread。别自己造轮子,浪费时间还容易出bug。

1.3 开发环境搭建:MDK / IAR / Studio

搭建环境是新手最容易卡壳的地方。我当年第一次装RT-Thread,光配置路径就折腾了一下午。今天我把三种主流IDE的搭建步骤给你捋清楚。

1.3.1 MDK (Keil) 环境搭建

MDK是STM32开发的老牌工具,很多公司还在用。我个人习惯用MDK做快速原型验证。

  1. 安装MDK:版本建议5.38以上,装好对应的STM32芯片包(DFP)。
  2. 下载RT-Thread源码:从GitHub或Gitee拉取最新稳定版(v5.0.x)。
  3. 创建工程模板:
    • 复制 rt-thread/bsp/stm32/stm32f407-atk-explorer 作为模板
    • 用MDK打开 project.uvprojx
    • 修改芯片型号为你手上的型号
  4. 配置编译选项:勾选“Use MicroLIB”,设置优化等级为-O2。

避坑指南: 我曾经在MDK里忘记勾选“Use MicroLIB”,结果程序一跑就进HardFault。原因是RT-Thread的printf实现依赖MicroLIB的底层函数。这个坑我踩过,你别再踩了。

1.3.2 IAR 环境搭建

IAR的编译器优化比MDK好一点,代码密度更小。如果你做产品级开发,我建议试试IAR。

  1. 安装IAR:版本8.50以上,装好STM32的器件支持包。
  2. 导入RT-Thread BSP:在IAR里打开 project.eww 工作区文件。
  3. 配置链接脚本:根据你的芯片Flash和RAM大小,修改 linker.icf 文件。
  4. 设置调试器:选J-Link或ST-Link,SWD接口,速度4MHz。

1.3.3 RT-Thread Studio(强烈推荐)

这是RT-Thread官方出的IDE,说白了就是“开箱即用”。我最近两年做项目基本都用它,省心。

  1. 下载安装:官网下载Studio,一路Next。
  2. 新建工程:选择芯片型号(比如STM32F407ZG),Studio会自动下载对应的BSP和SDK。
  3. 配置组件:在 rtconfig.h 里勾选你需要的组件(如FinSH控制台、DFS文件系统)。
  4. 编译下载:一键编译,一键下载到开发板。

我的建议: 如果你是初学者,直接上RT-Thread Studio。它帮你省掉了手动配置编译器、链接脚本、头文件路径这些脏活累活。等你熟悉了内核机制,再回头用MDK或IAR做深度定制。

1.4 工程模板创建:从零开始搭一个项目

下面我带你手把手创建一个RT-Thread工程模板。以STM32F407ZGT6 + RT-Thread Studio为例。

步骤1:新建RT-Thread项目

打开Studio,点击“文件” → “新建” → “RT-Thread项目”。填写项目名称,选择芯片型号,点击完成。

步骤2:配置内核参数

打开 board.h,找到下面几个关键宏定义:

/* 定义系统主频 */
#define BSP_CLOCK_SOURCE                  "HSE"
#define BSP_CLOCK_SOURCE_FREQ_MHZ         8
#define BSP_CLOCK_SYSTEM_FREQ_MHZ         168

/* 定义堆栈大小 */
#define RT_MAIN_THREAD_STACK_SIZE         2048
#define IDLE_THREAD_STACK_SIZE            512

步骤3:添加FinSH控制台

FinSH是RT-Thread的命令行交互工具,调试利器。在 rtconfig.h 中使能:

#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_THREAD_NAME        "tshell"
#define FINSH_THREAD_PRIORITY    20
#define FINSH_THREAD_STACK_SIZE  4096
#define FINSH_USING_HISTORY      1

步骤4:编写第一个线程

在 main.c 里写一个简单的LED闪烁线程:

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

#define LED_PIN    GET_PIN(F, 9)   // PF9 接LED

static void led_thread_entry(void *parameter)
{
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
    
    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,
                                              512,
                                              5,
                                              10);
    if (led_thread != RT_NULL)
    {
        rt_thread_startup(led_thread);
    }
    
    return 0;
}

关键点解析:

  • rt_thread_create 的第三个参数是线程入口函数的参数,这里传NULL
  • 第四个参数是栈大小,单位字节。512字节够用,但别小于256
  • 第五个参数是优先级,数值越小优先级越高。0-31,0给空闲线程用
  • 第六个参数是时间片,单位是系统时钟节拍(通常1ms)

1.5 RT-Thread 核心架构图

下面这张图是我手绘的RT-Thread核心架构,你看一眼就能明白整个系统的分层关系:

RT-Thread 核心架构分层图 应用层(用户线程) LED控制 / 传感器采集 / 网络通信 / 用户界面 组件与服务层 FinSH控制台 DFS文件系统 LwIP网络协议栈 设备驱动框架 RT-Thread 内核 线程调度器 同步与通信 内存管理 定时器管理 硬件抽象层(HAL / libcpu / BSP) STM32 硬件平台

从这张图你能看到,RT-Thread从下到上分五层:硬件、HAL、内核、组件、应用。每一层只依赖下一层,耦合度很低。我在做驱动移植时,通常只改HAL层和BSP,上层代码基本不动——这就是分层设计的好处。

1.6 本章小结

这一章我们干了三件事:

  • 搞清楚了RT-Thread是什么、能干什么
  • 搭建了三种主流开发环境(MDK / IAR / Studio)
  • 亲手创建了一个LED闪烁的工程模板

环境搭好了,模板跑起来了,后面咱们就可以放开手脚折腾任务调度和外设驱动了。记住,调试和故障定位才是这门课的核心——代码能跑只是开始,出了问题能快速找到根因,那才是真本事。