RT-Thread简介及启动流程分析
阅读引言: 最近在学习RT-Thread的内部机制,觉得这个启动流程和一些底层原理还是挺重要的, 所以写下此文。
目录
1, RT-Thread简介
2,RT-Thread任务的几种状态
3, 学习资源推荐
4, 启动流程分析开始
1, RT-Thread简介

RT-Thread是一个来自中国的开源、中英文双语的实时操作系统(RTOS),它适用于各种资源受限的嵌入式系统。自2006年由熊谱翔(Bernard Xiong)创建以来,RT-Thread已经发展成为一个功能丰富、高度可伸缩、完全开源的实时操作系统。
以下是RT-Thread的一些主要特性:
-
实时性能:RT-Thread提供了高实时性能,能够满足嵌入式系统对实时性的需求。
-
可伸缩性:系统设计为可伸缩,可以运行在从几百字节内存的简单嵌入式设备到拥有大量内存的复杂系统。
-
组件丰富:RT-Thread拥有丰富的组件库,包括文件系统、TCP/IP网络协议栈、设备驱动框架等。
-
易用性:RT-Thread提供了简洁明了的API设计,易于学习和使用。
-
开源社区:拥有活跃的开源社区,众多开发者和公司贡献代码和组件。
-
跨平台:支持多种处理器架构,如ARM Cortex-M、Cortex-R、Cortex-A系列,以及MIPS、x86、XTensa等。
-
工具链支持:与多种编译器和集成开发环境(IDE)兼容,如Keil、IAR、GCC等。
-
软件包生态:RT-Thread Studio提供了丰富的软件包管理,方便开发者快速集成和使用。
-
文档和教程:提供详细的文档和教程,帮助开发者快速上手。
-
商业友好:RT-Thread的BSD许可协议非常友好,允许商业和个人用户免费使用和修改。
RT-Thread适用于各种嵌入式应用场景,包括智能家居、智能穿戴、智能安防、工业自动化、车载设备等。它的设计目标是为嵌入式开发提供稳定、高效、易用的解决方案。
2,RT-Thread任务的几种状态

| 状态 | 特点 |
|---|---|
| 初始状态 | 创建完任务还未开启任务调度器, 此时任务就属于此种状态 |
| 就绪状态 | 启动调度器后, 任务属于此种状态 |
| 挂起(阻塞) | 任务因为等待某种资源而阻塞 |
| 运行 | 运行 |
| 关闭 | 线程退出 |
- 初始状态
当线程刚开始创建还没开始运行时就处于初始状态:
使用rt_thread_init()创建,但是未调用rt_thread_startup使它就绪
使用rt_thread_create()创建,但是未调用rt_thread_startup使它就绪
- 就绪状态
这个线程完全准备好了,随时可以运行:只是还轮不到它:这时它就处于就绪态(Ready)。
在下面几种情况下,线程都处于就绪状态:
我们创建线程后,使用rt_thread_startup()函数使它进入就绪态。
它在运行过程中,被更高优先级的线程抢占了,这时它处于就绪状态。
它在运行过程中,轮到同优先级的线程运行了,这时它处于就绪状态。
它因为等待某些资源而没有运行,别的线程或者中断函数把它唤醒了,这时它处于就绪状态。
- 运行状态
当处于就绪状态的线程运行时,它就处于运行状态。
- 挂起状态
在日常生活的例子中,母亲在电脑前跟同事沟通时,如果同事一直没回复,那么母亲的工作就被卡住了、被堵住了、处于挂起状态。
重点在于:母亲在等待。
在RTOS中创建多个任务后, 如果别的这些任务中优先级最高的任务(线程)在循环执行过程中不调用休眠相关的函数让出CPU的资源, 那么比它优先级低的任务根本呢不会执行。
在实际产品中,我们不会让一个线程一直运行,而是使用"事件驱动"的方法让它运行:
线程要等待某个事件,事件发生后它才能运行
在等待事件过程中,它不消耗CPU资源
在等待事件的过程中,这个线程就处于挂起状态, 就是阻塞状态
在挂起状态的线程,它可以等待两种类型的事件:
时间相关的事件
可以等待一段时间:我等2分钟
也可以一直等待,直到某个绝对时间:我等到下午3点
同步事件:这事件由别的线程,或者是中断程序产生
例子1:线程A等待线程B给它发送数据
例子2:线程A等待用户按下按键
同步事件的来源有很多(这些概念在后面会细讲):
信号量(semaphores)
互斥量(mutexe)
事件集(event)
在等待一个同步事件时,可以加上超时时间。比如等待队里数据,超时时间设为10ms:
10ms之内有数据到来:成功返回
10ms到了,还是没有数据:超时返回
- 关闭状态
当线程运行结束时,将处于关闭状态:
可由运行状态正常退出,进入关闭状态
或者通过线程删除函数进入关闭状态
rt_err_t rt_thread_detach(),用来删除使用rt_thread_init()创建的线程
rt_err_t rt_thread_delete(),用来删除使用rt_thread_create()创建的线程
在进入关闭状态时,线程所占据的资源(比如栈)不会立即释放,需等到空闲进程运行时才能清理。在这两个删除任务的函数内部实现是将任务控制块从不同的状态链表中进行搬移, 实际在回收任务控制块和任务栈的任务是在操作系统的空闲任务中做的。
3, 学习资源推荐
FreeRTOS
RT-Thread
没有系统学习过RTOS的兄弟建议去学第一个, 正点原子推出的FreeRTOS教程, 讲得很仔细, 很底层。
4, 启动流程分析开始

追一下代码: 这里简单补充一下一般mcu的启动流程, 一般在固化程序运行完成之后就到了启动代码, 不太明白为什么mcu启动的第一个处理的函数(符号)是复位处理的可以去看我之前写的这篇文章: http://t.csdnimg.cn/DUkKK
Reset_Handler:
; Reset handler
Reset_Handler PROCEXPORT Reset_Handler [WEAK] @导出Reset_Handler符号, 别的源文件可见IMPORT __main @导入编译器生成的__main引导函数IMPORT SystemInit @导入SystemInit函数符号LDR R0, =SystemInit @初始化时钟等BLX R0 LDR R0, =__mainBX R0ENDP
mcu上电之后执行完固化的引导程序之后, 会根据拨码开关的指示来存储器中取出指令执行, 执行的指令的开始是启动代码, 启动代码中的第一个函数符号是复位处理, 在复位处理中调用到了SystemInit函数, 接下来到了SystemInit函数了。
SystemInit:
/*** @brief Setup the microcontroller system* Initialize the Embedded Flash Interface, the PLL and update the * SystemCoreClock variable.* @note This function should be used only after reset.* @param None* @retval None*/
void SystemInit (void)
{/* Reset the RCC clock configuration to the default reset state(for debug purpose) *//* Set HSION bit */RCC->CR |= 0x00000001U;/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)RCC->CFGR &= 0xF8FF0000U;
#elseRCC->CFGR &= 0xF0FF0000U;
#endif /* STM32F105xC */ /* Reset HSEON, CSSON and PLLON bits */RCC->CR &= 0xFEF6FFFFU;/* Reset HSEBYP bit */RCC->CR &= 0xFFFBFFFFU;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */RCC->CFGR &= 0xFF80FFFFU;#if defined(STM32F105xC) || defined(STM32F107xC)/* Reset PLL2ON and PLL3ON bits */RCC->CR &= 0xEBFFFFFFU;/* Disable all interrupts and clear pending bits */RCC->CIR = 0x00FF0000U;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000U;
#elif defined(STM32F100xB) || defined(STM32F100xE)/* Disable all interrupts and clear pending bits */RCC->CIR = 0x009F0000U;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000U;
#else/* Disable all interrupts and clear pending bits */RCC->CIR = 0x009F0000U;
#endif /* STM32F105xC */#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)#ifdef DATA_IN_ExtSRAMSystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM */
#endif #ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}

建议各位先看一些大型工程代码的时候使用SourceInsight。总结一下Systeminit函数做了啥, 初始化Flash, 系统时钟。
RTOS的启动, 需要在特定的编译环境下才能成功, 举个例子

在绝大多数的编程语言中, 数字、字母、下划线是构成字符串的要求, 这种写法防到标准C语言语法中肯定就报错了, 只是在嵌入式C语言中, 可以根据不同的平台, 不同的应用场景将编译器修改配套, 这样就不会报错了。
在复位处理中, 当SystemInit执行完之后, 会接着调用编译器提供的__main引导函数, 找到函数的main函数入口, 从而去执行用户代码。在这里有一点特殊的是, __main引导找到的函数是 $Sub$$main, 所有接下来我们该去分析一下 $Sub$$main做了什么了。

int rtthread_startup(void)
{rt_hw_interrupt_disable();/* board level initialization* NOTE: please initialize heap inside board initialization.*/rt_hw_board_init();/* show RT-Thread version */rt_show_version();/* timer system initialization */rt_system_timer_init();/* scheduler system initialization */rt_system_scheduler_init();#ifdef RT_USING_SIGNALS/* signal system initialization */rt_system_signal_init();
#endif/* create init_thread */rt_application_init();/* timer thread initialization */rt_system_timer_thread_init();/* idle thread initialization */rt_thread_idle_init();/* start scheduler */rt_system_scheduler_start();/* never reach here */return 0;
}
可以看到在这个函数中还是做了蛮多事情的, 但是主要的就两个函数。

看一下这两个源文件的实现


可以看到比较核心的是创建了一个主线程, 要不先去看看这个主线程干了啥?

可以看到, 在初始化一些系统组件之后, 调用到了我们的main函数。

具体任务切换是如何切的就要看cpu架构了, 本质通过一些链表, 定时器, 找到需要运行的任务, 将正在运行的任务和需要运行的任务进行一次上下文切换。
到此, RT-Thread启动流程就大致的分析完成了。
相关文章:
RT-Thread简介及启动流程分析
阅读引言: 最近在学习RT-Thread的内部机制,觉得这个启动流程和一些底层原理还是挺重要的, 所以写下此文。 目录 1, RT-Thread简介 2,RT-Thread任务的几种状态 3, 学习资源推荐 4, 启动流程分…...
MCU嵌入式AI开发笔记-视频笔记同步更新
MCU嵌入式AI开发笔记 抖音B站等站点笔记视频同步更新 01嵌入式AI大的方向 STM32跑神经网络 http://news.eeworld.com.cn/mp/EEWorld/a134877.jspx 为什么可以在STM32上面跑神经网络?简而言之就是使用STM32CubeMX中的X-Cube-AI扩展包将当前比较热门的AI框架进行C代码的转化,…...
DoIP——step2:车辆发现
文章目录 前言一、IP地址配置1.1 AutoIP1.2 DHCP1.3 DoIP实体的IP地址配置流程二、车辆发现车辆声明报文内容如下:前言 完成诊断设备到车辆的物理连接并通过激活线使能诊断连接后边缘节点将会将连接状态传递至应用层,在开始车辆发现过程之前,需要先进行各自的IP地址配置,获…...
【动态规划】0-1背包问题
【动态规划】0-1背包问题 题目:现在有四个物品,背包总容量为8,背包最多能装入价值为多少的物品? 我的图解 表格a【i】【j】表示的是容量为j的背包装入前i个物品的最大价值。 拿a【1】【1】来说,它的值就是背包容量为1,只考虑…...
WordPress 高级缓存插件 W3 Total Cache Pro 详细配置教程
说起来有关 WordPress 缓存插件明月已经发表过不少文章了,但有关 W3 Total Cache Pro 这个 WordPress 高级缓存插件除了早期【网站缓存插件 W3 Total Cache,适合自己的才是最好的!】一文后就很少再提及了,最近因为明月另一个网站【玉满斋】因为某些性能上的需要准备更换缓存…...
每日一题——Python实现PAT乙级1012 数字分类(举一反三+思想解读+逐步优化)五千字好文
一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码优点 代码缺点 时间复杂度 空间复杂度 代码改进建议 我要更强 哲…...
Unity2D游戏制作入门 | 13 ( 之人物三段攻击 )
上期链接:Unity2D游戏制作入门 | 12(之人物受伤和死亡的逻辑动画)-CSDN博客 上期我们聊了人物的受伤和死亡的逻辑和动画,我们主要学习了事件的执行,即我们在人物受伤时可能会触发很多的事件,比如触发人物受伤的动画以及播放音乐等…...
DAY04 HTMLCSS
文章目录 一 表单(1) 数字控件(2) 颜色控件(3) 日期控件(4) 月份控件(5) 星期控件(6) 搜索控件(7) 范围控件 二 浮动框架三 结构化标签四 CSS1 CSS概述2 CSS的编写位置1. inline style 行内样式2. inner style 内部样式3. outer style 外部样式4. 小结 3 CSS选择器1. 通用选择器…...
Linux_理解程序地址空间和页表
目录 1、进程地址空间示意图 2、验证进程地址空间的结构 3、验证进程地址空间是虚拟地址 4、页表-虚拟地址与物理地址 5、什么是进程地址空间 6、进程地址空间和页表的存在意义 6.1 原因一(效率性) 6.2 原因二(安全性) …...
NAND闪存市场彻底复苏
在全球内存市场逐渐走出阴霾、迎来复苏曙光之际,日本存储巨头铠侠(Kioxia)凭借敏锐的市场洞察力和及时的战略调整,成功实现了从生产紧缩到全面复苏的华丽转身。这一转变不仅彰显了企业在逆境中的生存智慧,也为全球半导…...
过拟合与正则化
Location Beijing 过拟合 对于一个模型 A A A,解向量空间为 θ \theta θ,误差函数用式1表示 J ( θ ) J a c c [ y θ ( x ) − y ] 2 (1) J(\theta)J_{acc}[y_\theta(x)-y]^2\tag{1} J(θ)Jacc[yθ(x)−y]2(1) 首先我们考虑用模型 A A A拟合下…...
VMware挂载NAS存储异常处理
问题概述 由于非法关机或恢复,NFS存储可能会出现以下问题: 数据存储处于挂起状态或无法正常识别。虚拟机的配置文件或虚拟磁盘仍然注册在异常数据存储上。系统误认为有虚拟机在使用该数据存储。 问题对策 下面是详细的排查步骤和解决对策:…...
Redis 7.x 系列【4】命令手册
有道无术,术尚可求,有术无道,止于术。 本系列Redis 版本 7.2.5 源码地址:https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 说明2. 命令手册2.1 Generic2.2 数据类型2.2.1 String2.2.2 Hash2.2.3 List2.2.4 S…...
走进Elasticsearch
什么是ES 是一个分布式、RESTful风格的搜索和数据分析引擎 中文参考文档: 《Elasticsearch中文文档》 | Elasticsearch 技术论坛 elasticSearch官网: Functions and Operators | Elasticsearch Guide [7.11] | Elastic查询方式 Kibana查询(原…...
QT TCP服务器和客户端示例程序
下面是一个简单的 Qt TCP 服务器和客户端示例,演示了如何使用 vSetDriver、vSetListener 和 vTcpServerStart 函数。假设 vSetDriver 和 vSetListener 是你定义的自定义函数。 TCP 服务器部分 tcpserver.h #ifndef TCPSERVER_H #define TCPSERVER_H#include <QT…...
Xlua三方库Android编译出错解决办法
Xlua三方库Android编译出错解决办法 最近听老师的热更教程,讲到xlua编译android平台会报错,也是看了老师的博客,按照方法去解决,然而问题并没有解决。应该是因为代码更新或者版本不一样,在此简单记录一下解决过程。 参…...
美国犹他州立大学《Nature Geoscience》(IF=18)!揭示草本植物对土壤有机碳的重要贡献!
随着全球变暖的影响越来越显著,碳固定成为了一个备受关注的话题。在这个背景下,热带草原被认为是一个潜在的碳固定区域。然而,目前的研究主要关注于在热带草原中种植树木,以期望增加土壤有机碳含量。但是,热带草原中的…...
高考专业抉择计算机专业热度不减,兴趣、实力与挑战并存。
作为一名即将步入大学校门的高考生,我对于计算机相关专业是否仍是热门选择感到困惑。在过去几年里,计算机科学与技术、人工智能、网络安全、软件工程等专业一直备受追捧,吸引了无数学生。然而,随着市场竞争加剧和市场饱和度提高&a…...
Flask-RQ
Flask-RQ库教程 Flask-RQ 是一个用于在 Flask 应用中集成 RQ(Redis Queue)的扩展。RQ 是一个简单的 Python 库,用于将任务排入 Redis 队列并异步执行这些任务。这对于处理长时间运行的任务(如发送电子邮件、生成报告等࿰…...
LeetCode 58. 最后一个单词的长度
LeetCode 58. 最后一个单词的长度 你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串 示例 1: 输入:s “Hello World”…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...
