在开始 RT-Thread 内核学习之前,先来体验一下 RT-Thread。

要体验 RT-Thread,首先需要具备运行环境或者实验环境。RT-Thread 不仅可以在实际硬件平台上运行,也可以在虚拟环境下实验运行。

如果只是为了学习内核知识,并配合练习实验,虚拟环境就可以了。如果有实际的硬件环境,当然会更好。

官方的学习资料中,介绍了两种虚拟环境:

•QEMU 虚拟机•Keil 模拟器

下面分别以这两种环境体验一下 RT-Thread 运行。

接着介绍了一下 RT-Thread 内核对象模型架构的基础知识。

QEMU 虚拟机

RT-Thread 提供了 QEMU 模拟的 ARM vexpress A9 开发板的板级支持包 (BSP)。

在 Windows 平台即可运行 qemu-vexpress-a9 BSP 工程,但是需要先搭建 Env 开发环境,可以参考:

RT-Thread 学习-Env开发环境搭建

(备注:此处示例的源码版本为 v4.0.2)

QEMU 模拟的 ARM vexpress A9 开发板的板级支持包 (BSP) 位于 RT-Thread 源码 BSP 目录下的 qemu-vexpress-a9 文件夹,其内容如下图所示:

RT-Thread快速入门-体验RT-Thread_嵌入式硬件

 

qemu-vexpress-a9 BSP 主要文件及目录描述如下所示:

文件 / 目录

描述

.vscode

vscode 配置文件

applications

用户应用代码目录

drivers

RT-Thread 提供的底层驱动

qemu.bat

Windows 平台运行脚本文件

qemu.sh

Linux 平台运行脚本文件

qemu-dbg.bat

Windows 平台调试脚本文件

qemu-dbg.sh

Linux 平台调试脚本文件

README.md

BSP 说明文件

rtconfig.h

BSP 配置头文件

编译运行

进入 bsp\qemu-vexpress-a9 文件夹,打开 Env 工具,输入 scons 指令,开始编译,编译成功后如下图:

RT-Thread快速入门-体验RT-Thread_串口_02

 

编译成功后,输入qemu.bat,运行程序

RT-Thread快速入门-体验RT-Thread_Windows_03

 

Env 命令界面显示 RT-Thread 系统过程中打印的信息,包括初始化信息和版本号信息等。

RT-Thread 支持 Finsh 功能,用户调试和查看系统信息,用户可以使用命令进行操作。输入 help 或者按 tab 键可以查看系统支持的命令:

RT-Thread快速入门-体验RT-Thread_Windows_04

 

我们尝试输入指令 list_thread,显示系统当前正在运行的线程,以及线程状态和堆栈大小等信息:

RT-Thread快速入门-体验RT-Thread_内核对象_05

 

Finsh 具有自动补全功能,输入命令的部分字符,按下 Tab 键盘,则系统会根据当前已经输入的字符,从系统中查找已经注册好的相关命令。这个功能与 Linux 下的命令终端非常相似。

RT-Thread快速入门-体验RT-Thread_嵌入式硬件_06

 

Keil 模拟器

MDK-ARM 软件中的软件仿真模拟器,采用完全软件模拟方式解释执行 ARM 的机器指令,并实现外围的一些外设逻辑,从而构成一套完整的虚拟硬件环境,使得用户能够不借助真实的硬件平台就能够在电脑上执行相应的目标程序。

RT-Thread 官方提供了一个示例工程,可以在模拟 STM32F103 的软件仿真环境下运行。工程下载链接如下(由于微信不能添加外部链接,需要复制到浏览器打开):

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/quick-start/stm32f103-simulator/stm32f103-simulator

下载完成后,解压完成的目录结构如下:

RT-Thread快速入门-体验RT-Thread_内核对象_07

 

各个目录所包含的文件类型的描述如下表所示:

目录名

描述

applications

RT-Thread 应用程序文件。

rt-thread

RT-Thread 的源文件。

- components

RT-Thread 的各个组件目录。

- include

RT-Thread 内核的头文件。

- libcpu

各类芯片的移植代码,此处包含了 STM32 的移植文件。

- src

RT-Thread 内核的源文件。

- tools

RT-Thread 命令构建工具的脚本文件。

drivers

RT-Thread 的驱动,不同平台的底层驱动具体实现。

Libraries

ST 的 STM32 固件库文件。

kernel-sample-0.1.0

RT-Thread 的内核例程。

双击 project.uvprojx 打开工程:

RT-Thread快速入门-体验RT-Thread_内核对象_08

 

此示例工程,示例工程实现了一个模拟 LED 闪烁的功能函数,并用 RT-Thread 的宏 MSH_CMD_EXPORT 导出一个指令 led。在控制终端输入 led ,可以运行这个函数。

编译完成后,我们可以通过 MDK-ARM 的模拟器来仿真运行 RT-Thread,如下图:

RT-Thread快速入门-体验RT-Thread_嵌入式硬件_09

 

进入仿真页面后,再按 F5 开始运行;然后点击工具栏中的按钮,或者选择菜单栏中的 “View→Serial Windows→UART#1”,打开串口 1 窗口,可以看到串口的输出只显示了 RT-Thread 的 LOGO,这是因为用户代码是空的,其模拟运行的结果如图所示:

RT-Thread快速入门-体验RT-Thread_串口_10

 

在提示符 msh> 后输入 led,执行 LED 模拟闪烁的函数:

RT-Thread快速入门-体验RT-Thread_内核对象_11

 

FinSH 控制台

在以上两种模拟运行 RT-Thread 实验中,均提到了 FinSH。那么 FinSH 到底是什么呢?

在此,只做简单的介绍,达到了解的程度即可。随着学习的深入,后期可以自己详细地学习一下。

FinSH 是 RT-Thread 的命令行组件,类似于 Linux 下的 shell,提供了一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息,它可以使用串口、网口、USB 等与 PC 进行通信。

当使用串口连接设备与控制终端时,FinSH 命令的执行流程如图:

RT-Thread快速入门-体验RT-Thread_嵌入式硬件_12

 

用户在控制终端输入命令,控制终端通过串口、 USB、网络等方式将命令传给设备里的 FinSH, FinSH 会读取设备输入命令,解析并自动扫描内部函数表,寻找对应函数名,执行函数后输出回应,回应通过原 路返回,将结果显示在控制终端上 。

FinSH 支持自动补全、查看历史命令等功能,通过键盘上的按键可以很方便的使用这些功能 。

RT-Thread 源码

为了方便学习 RT-Thread,我们下载标准版源码。官方提供了源码下载通道:

https://www.rt-thread.org/page/download.html

RT-Thread快速入门-体验RT-Thread_嵌入式硬件_13

 

下载完成后,源码目录如下(注意,源码存放路径位置不能存在中文):

RT-Thread快速入门-体验RT-Thread_Windows_14

 

RT-Thread 源代码目录结构如下所示:

名称

描述

BSP

Board Support Package(板级支持包)基于各种开发板的移植

components

RT-Thread 的各个组件代码,例如 finsh,gui 等。

documentation

相关文档,如编码规范等

examples

相关示例代码

include

RT-Thread 内核的头文件。

libcpu

各类芯片的移植代码。

src

RT-Thread 内核的源文件。

tools

RT-Thread 命令构建工具的脚本文件。

内核对象模型

RT-Thread 内核采用面向对象的设计思想进行设计,系统级的基础设施都是一种内核对象,例如线程,信号量,互斥量,定时器等。

内核对象分为两类:静态内核对象和动态内核对象,静态内核对象通常放在RW 段和 ZI 段中,在系统启动后在程序中初始化;动态内核对象则是从内存堆中创建的,而后手工做初始化。

静态对象会占用 RAM 空间,不依赖于内存堆管理器,内存分配时间确定。动态对象则依赖于内存堆 管理器,运行时申请 RAM 空间,当对象被删除后,占用的 RAM 空间被释放。

关于动态对象和静态对象的创建,后面会进行介绍。

内核对象管理

RT-Thread 内核对象包括:线程,信号量,互斥量,事件,邮箱,消息队列和定时器,内存池,设备 驱动等。对象容器中包含了每类内核对象的信息,包括对象类型,大小等。

对象容器给每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上,如图 RT-Thread 的内核对象容器及链表如下图所示:

RT-Thread快速入门-体验RT-Thread_嵌入式硬件_15

 

每一种具体的内核对象和对象控制块,除了基本的结构外,还有自己的扩展属性。

例如,对于线程控制块,在基类对象基础上进行扩展,增加了线程状态、优先级等属性。这些属性在基类对象的操作中不会用到,只有在与具体线程相关的操作中才会使用。

从面向对象的角度来看,每一种具体对象是抽象对象的派生,继承了基本对象的属性,并在此基础上扩展了与自己相关的属性。如下图所示,各类内核对象的派生和继承关系:

RT-Thread快速入门-体验RT-Thread_内核对象_16

 

在对象管理模块中,定义了通用的数据结构,用来保存各种对象的共同属性,各种具体对象只需要在 此基础上加上自己的某些特别的属性,就可以清楚的表示自己的特征 。

这种设计方法的优点有:

(1)提高了系统的可重用性和扩展性,增加新的对象类别很容易,只需要继承通用对象的属性再加少 量扩展即可。

(2)提供统一的对象操作方式,简化了各种具体对象的操作,提高了系统的可靠性。

OK,今天先到这,下次继续。加油~

RT-Thread快速入门-体验RT-Thread_串口_17