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的一些主要特性:

  1. 实时性能:RT-Thread提供了高实时性能,能够满足嵌入式系统对实时性的需求。

  2. 可伸缩性:系统设计为可伸缩,可以运行在从几百字节内存的简单嵌入式设备到拥有大量内存的复杂系统。

  3. 组件丰富:RT-Thread拥有丰富的组件库,包括文件系统、TCP/IP网络协议栈、设备驱动框架等。

  4. 易用性:RT-Thread提供了简洁明了的API设计,易于学习和使用。

  5. 开源社区:拥有活跃的开源社区,众多开发者和公司贡献代码和组件。

  6. 跨平台:支持多种处理器架构,如ARM Cortex-M、Cortex-R、Cortex-A系列,以及MIPS、x86、XTensa等。

  7. 工具链支持:与多种编译器和集成开发环境(IDE)兼容,如Keil、IAR、GCC等。

  8. 软件包生态:RT-Thread Studio提供了丰富的软件包管理,方便开发者快速集成和使用。

  9. 文档和教程:提供详细的文档和教程,帮助开发者快速上手。

  10. 商业友好: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启动流程就大致的分析完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/29002.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MTANet: 多任务注意力网络,用于自动医学图像分割和分类| 文献速递-深度学习结合医疗影像疾病诊断与病灶分割

Title 题目 MTANet: Multi-Task Attention Network for Automatic Medical Image Segmentation and Classification MTANet: 多任务注意力网络,用于自动医学图像分割和分类 01 文献速递介绍 医学图像分割和分类是当前临床实践中的两个关键步骤,其准…

Springboot3+自动装配

导言:这里主要讲述springboot3以后spring.factories功能失效,带来的解决办法。 之前有一次希望用springboot模块拿到工具模块的配置configuration的时候,想通过之前的spring.factories来实现自动装配,但是发现一直拿不到配置&…

数据仓库与数据挖掘(期末复习)

数据仓库与数据挖掘(期末复习) ETL的含义Extract 、 Transformation、Load。 ODS的全称Operational Data Store。 DW全称 Data Warehourse DM全称是Data Mart 数据仓库数据抽取时所用到技术是增量、全量、定时、调度 STAGE层作用是提供业务系统数据…

因果卷积和递归神经网络

因果卷积(causal convolution)和递归神经网络(RNN)在处理序列数据时各有优劣。这里我们分析两者的工作机制和性能特点。 ### 因果卷积 1. **因果卷积的特点**: - **不使用未来信息**:因果卷积只利用当前及…

全国各区县地区生产总值数据(GDP及人均生产总值),精度超高 区县级数据

数据名称: 全国各区县地区生产总值数据 数据格式: shpexcel 数据几何类型: 面 数据精度:区县 数据坐标系: WGS84 数据来源:网络公开数据 数据可视化.

稳了?L3规模化落地在即,激光雷达公司成首批赢家

作者 | 芦苇 编辑 | 德新 在中国,距L3级自动驾驶的规模化落地,又近了一步。 随着国内试点政策刷新,越来越多的车企在部分市域获得了自动驾驶测试牌照,能上路测试的L3级自动驾驶车辆正在快速增加。 其中一个重要节点是&#xf…

C语言最终文章-二叉树

文章目录 前言二叉树的性质二叉树的存储方式顺序存储堆及其应用TopK问题堆排序 链式存储二叉树的练习1.二叉树查找值为x的节点2.判断是否为完全二叉树LC226.翻转二叉树[LC572. 另一棵树的子树](https://leetcode.cn/problems/subtree-of-another-tree/description/)两道选择题 …

如何开展接口测试

项目中如何开展接口测试 需求分析 接口文档解析 设计测试用例 脚本开发 执行及缺陷跟踪 生成测试报告 接口自动化持续集成(可选)

音视频开发_SDL音频播放器的实现

今天向大家介绍一下如何通过 SDL 实现一个PCM音频播放器。这是一个最简单的播放器,它不涉及到音频的解复用,解码等工作。我们只需要将音频原始数据喂给 SDL 音频接口就可以听到悦耳的声音了。在下面的列子中我将向你演示,使用 SDL 做这样一个…

目标检测:IOU

IOU(Intersection over Union)交并比: 它计算的是“预测的边框”和“真实的边框”的交叠率,即它们的交集和并集的比值。这个比值用于衡量预测边框与真实边框的重叠程度,从而评估目标检测的准确性。 在目标检测任务中…

嵌入式操作系统_2.嵌入式操作系统的一般架构

1.嵌入式操作系统的概念 嵌入式操作系统通常由硬件驱动程序、调式代理、操作系统内核、文件系统和可配置组件等功能组成,并为应用软件提供标准的API(Application Programming Interface)接口服务。 2.一般嵌入式操作系统的体系结构 从嵌入…

Mysql特殊用法分享

不存在则插入,存在则更新的2种写法 前置使用条件,必须有唯一索引 -- 1 REPLACE INTO REPLACE INTO typora.ip_view_times_record (ip, view_times, url) VALUES(10.25.130.64, 1, https://10.25.168.80/fhh/index.html?urlindex.md543);-- 2 ON DUPLI…

HTTP服务器实现长连接的思路(Java语言)

一、背景 目前的HTTP服务器很多,只要是编程语言支持线程和网络通信,就能开发一个HTTP协议服务器。 市场上常用的是Tomcat、Ngnix、Httpd等技术。 二、本文目的 介绍使用Java语言来开发HTTP服务器的处理逻辑。 这是个人可以参考的HTTP服务器通用逻辑。…

使用Selenium进行元素定位的全面指南

使用Selenium进行元素定位的全面指南 引言 Selenium 是一个广泛使用的开源工具,用于自动化Web浏览器的操作。无论你是进行自动化测试,还是需要抓取网页数据,Selenium 都是一个非常有用的工具。而在Selenium中,定位网页元素是自动…

LabVIEW机械设备故障诊断中,振动分析的有效性与局限性如何

LabVIEW作为一种强大的图形化编程工具,在机械设备故障诊断中的振动分析中发挥了重要作用。振动分析通过监测机械设备的振动信号,能够有效地诊断设备故障。然而,尽管其有效性显著,但也存在一些局限性。本文将探讨LabVIEW在振动分析…

C# —— for循环语句

基本语法 for (初始表达式; 条件表达式; 增量表达式) { // 循环体 } for循环中 有三个空 第一个空(初始表达式): 一般用来声明一个临时的局部变量 用来计数 第二个空(条件表达式): 表明进入循环的条件 一个bool类型的值(bool类型 条…

深度神经网络——什么是NLP(自然语言处理)?

自然语言处理(NLP) 是对使计算机能够处理、分析、解释和推理人类语言的技术和工具的研究和应用。 NLP 是一个跨学科领域,它结合了语言学和计算机科学等领域已建立的技术。 这些技术与人工智能结合使用来创建聊天机器人和数字助理,…

海成蜘蛛池广州官网下载

baidu搜索:如何联系八爪鱼SEO? baidu搜索:如何联系八爪鱼SEO? baidu搜索:如何联系八爪鱼SEO? 当我们给自己的泛目录设置仅蜘蛛抓取生成缓存的时候,我们需要模拟蜘蛛抓取测试我们的设置是否成功。绝大部分时候我们都使用网页蜘蛛模拟抓取测…

Comparable和Comparator区别

相同点:都是用于比较排序。 不同点: 1、接口所在的包不同:comparable:java.lang.Comparable;Comparator:java.util.Comparator 2、比较逻辑不同:Comparable:内部比较器&#xff1…

2024.618到底买什么数码值得?带你一起来看看!

在618期间,这些新品可能会有特别的优惠活动,包括但不限于折扣、满减、赠品等。因此,如果你正在寻找一款适合自己的数码产品,不妨关注各大电商平台的618促销活动,把握机会,以优惠的价格购买到心仪的产品。 …