RT-Thread

2024-06-07 03:28
文章标签 rt thread

本文主要是介绍RT-Thread,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RT-Thread

RT-Thread 版权属于上海睿赛德电子科技有限公司,于 2006年 1月首次发布,初始版 本号为0.1.0,经过 10来年的发展,如今主版本号已经升级到3.0,累计开发者达到数百万, 在各行各业产品中装机量达到了惊人的2000多万,占据国产RTOS的鳌头。


在接触RT-Thread之前我已经深入学习过FreeRTOS实时操作系统,感觉这些操作系统的形式都大差不差,自认为无非是各种功能的函数名字不一样,时间片的实现,启动流程有些许不同。

RT-Thread和FreeRTOS类似,都拥有线程管理(在RT-Thread中叫线程,在FreeRTOS中叫任务),消息队列,信号量(二值,计数),互斥量,事件,软件定时器,内存管理,中断管理。比

FreeRTOS多了个邮箱(目前看来根据野火的源码分析,感觉和消息队列功能差不多)。


 启动流程

接下来讲一下RT-Thread的启动流程

当你拿到一个移植好的 RT-Thread工程的时候,你去看 main函数,只能在 main函数 里面看到创建线程和启动线程的代码,硬件初始化,系统初始化,启动调度器等信息都看 不到

那是因为RT-Thread拓展了main函数,在main函数之前把这些工作都做好了。

我们知道,在系统上电的时候第一个执行的是启动文件里面由汇编编写的复位函数 Reset_Handler。复位函数的最后会调用 C 库函数__main,__main 函数的主要工作是初始化系统的堆和栈,最后调用 C 中 的main函数,从而去到C的世界。

执行完__main之后,并不是跳转到C 中的main函数,而是跳转到component.c中的$Sub$$main函数,这是为什么?因为RT Thread使用编译器(这里仅讲解KEIL,IAR或者GCC稍微有点区别,但是原理是一样的) 自带的$Sub$$和$Super$$这两个符号来扩展了main函数。

使用$Sub$$main可以在执行 main之前先执行$Sub$$main,在$Sub$$main函数中我们可以先执行一些预操作,当做完这 些预操作之后最终还是要执行main函数。

这个就通过调用$Super$$main来实现。当需要扩展的函数不是main的时候,只需要将main换成你要扩展的函数名即可,即$Sub$$function 和$Super$$function。(mdk的扩展功能)


首先执行$Sub$$main函数,在其中包含的内容有:

  1. 关闭中断,除了硬FAULT和NMI可以响应外,其它统统关掉。
  2.  执行rtthread_startup()函数。

rtthread_startup()函数

RT-Thread 启动的时候会调用一个名为 rt_hw_board_init()的函数, 从函数名称我们可以知道它是用来初始化开发板硬件的,需要把硬件相关的初始化都放在 rt_hw_board_int()函数里面完成,比如时钟,比如串口等,具体初 始化什么由用户选择。

当这些硬件初始化好之后,RT-Thread 才继续往下启动,(就是把各种外设初始化放在这个函数之中去执行),RT-Thread该函数需要我们在board.c中自己编写。


由图片可见,在rtthread_startup()函数中先是关闭中断,板级硬件初始化。打印RT-Thread的版本号(要想成功打印,必须重映射一个控制台到rt_kprintf函数  )后面进行定时器,调度器,信号的初始化

最终创建一个初始线程。这个初始线程类似于FREERTOS中的创建任务的任务,就是在这个任务中去创建工程所用到的所有的任务。


RT-Thread的启动流程是这样的: 即先创建一个初始线程,等调度器启动之后,在这个初始线程里面创建各种应用线程,当 所有应用线程都成功创建好后,初始线程就把自己关闭。那么这个初始线程就在 rt_application_init()里面创建。

该函数也在component.c里面定义,我们可以去component.c中修改,一般情况下是在rt_application_init()中创建main主函数的线程,在main主函数线程中去创建其他的线程,其中硬件各种外设的初始化已经在rt_hw_board_int()中完成了,所以main主函数中只需要去创建其他的线程就可以了。


rt_application_init()函数     

在这个函数中判断使用静态还是动态方法创建main线程,也就是void  main_thread_entry(void*parameter),并初始化相关参数。


void  main_thread_entry(void*parameter)

在main主函数线程中除了调用rt_components_init()函数进行 RT-Thread的组件初始化外,最终是调用main的扩展函数$Super$$main()回到main函数。

这个是必须的,因为我们一开始在进入main函数之前,通过$Sub$$main()函数扩展了main 函数,做了一些硬件初始化,RTOS系统初始化的工作,当这些工作做完之后最终还是要 回到main函数,那只能通过调用$Super$$main()函数来实现。$Sub$$和$Super$$是MDK 自带的用来扩展函数的符号,通常是成对使用。


main函数执行到最后,通过LR寄存器指定的链接地址退出,在 创建main线程的时候,线程栈对应LR寄存器的内容是rt_thread_exit()函数,在 rt_thread_exit里面会把main线程占用的内存空间都释放掉。

至此,结束了,RT-Thread的整个启动流程。

在我看来这也是RT-Thread和FreeRTOS的主要区别。


重映射串口到rt_kprintf函数

在RT-Thread中,有一个打印函数rt_kprintf()供用户使用,方便在调试的时候输出各 种信息。如果要想使用rt_kprintf(),则必须将控制台重映射到rt_kprintf(),这个控制台可以 是串口、CAN、USB、以太网等输出设备,用的最多的就是串口,


SysTick_Handler()

这一部分是rtthread用于更新时基,实现时间片的功能代码。将这一部分直接放在SysTick_Handler()中执行。


在线程里面的延时函数必须使用RT-Thread里面提供的延时函数,并 不能使用我们裸机编程中的那种延时。这两种的延时的区别是RT-Thread里面的延时是阻 塞延时,

即调用rt_thread_delay()函数的时候,当前线程会被挂起,调度器会切换到其它就 绪的线程,从而实现多线程。如果还是使用裸机编程中的那种延时,那么整个线程就成为 了一个死循环,如果恰好该线程的优先级是最高的,那么系统永远都是在这个线程中运行, 根本无法实现多线程。

该特性在所有操作系统都是一样的,可以在所有外设初始化的时候使用delay,在任务或者线程中只能使用操作系统提供的延时函数。

关于RT-Thread的其他系统功能,其实和FreeRTOS差不多,总而言之还是去查询API函数的使用方法在工程中。感觉掌握了一款实时操作系统其他的操作系统入门相对来说也更加容易了。

共勉,绝望之为虚妄,正与希望相对。我的理解是现实有多绝望的同时,希望就有多大!

这篇关于RT-Thread的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038041

相关文章

jmeter之Thread Group(线程组)

Thread Group(线程组) 1.线程组,或者可以叫用户组,进行性能测试时的用户资源池。 2.是任何一个测试计划执行的开始点。 3.上一篇提到的“控制器”和“HTTP请求”(采集器)必须在线程组内;监听器等其他组件,可以直接放在测试计划下。 线程组设置参数的意义 我们以下图为例,进行详细说明。见下图:  区域1(在取样器错误后要执行的动作) 这个区域的主要作用很明显,在线程内

Exception processing async thread queue Exception processing async thread queue

错误信息描述: eclipse 在debug中弹出异常信息框 Exception processing async thread queue Exception processing async thread queue 解决方法: eclipse 中有一个Expressions窗口,里面添加的 expression 没有正确执行,并且没有删除,只要 Remove All Expressio

no thread-bound request found:are you referring to request

问题描述: 通过webservice接口调用程序时,发现在执行查询的时候一直报一个错误,错误信息如下: java.lang.IllegalStateExceptino:No thread-bound request found:are you referring to request attributes outside of an actual web request,or processi

FFplay源码分析-video_thread

《FFmpeg原理》的社群来了,想加入社群的朋友请购买 VIP 版,VIP 版有更高级的内容与答疑服务。 本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 FFplay 源码分析系列以一条简单的命令开始,ffplay -i a.mp4。a.mp4下载链接:百度网盘,提取码:nl0s 。 上一篇文章已经讲解完了 audio_thread() 音频解码

FFplay源码分析-read_thread

《FFmpeg原理》的社群来了,想加入社群的朋友请购买 VIP 版,VIP 版有更高级的内容与答疑服务。 本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 FFplay 源码分析系列以一条简单的命令开始,ffplay -i a.mp4。a.mp4下载链接:百度网盘,提取码:nl0s 。 如下图所示,本文主要讲解 read_thread() 函数的内

「生信Debug」OpenBLAS blas_thread_init: pthread_create: Resource temporarily unavailable

BLAS(Basic Linear Algebra Subprograms),翻译为基础线性代数子程序库,里面拥有大量已经编写好的关于线性代数运算的程序。OpenBLAS是其中一个实现了相关运算的开源程序库,其他软件在开发的时候就不需要额外造轮子,直接调用相关的API即可。 之前在使用OrthoFinder遇到了类似的问题,见https://github.com/davidemms/OrthoF

std :: this_thread

this_thread 包装了一组可以访问当前线程信息的函数 functions 1、get_id()      获取当前线程的id。 // thread::get_id / this_thread::get_id#include <iostream> // std::cout#include <thread> // std::thread, std

std :: thread

头文件<thread>中包含两个类,thread和this_thread 在讲thread之前,首先要了解线程的一个状态:joinable 一个正规初始化后的线程是一个可执行线程,这种线程joinable为true,并且有一个独一无二的线程id。 相反,一个默认构造函数构造出的thread(thread(),没有参数,未初始化),joinable为false,且线程id通常和其他所有的non

thread joinable

bool jionable() const noexcept; 用于检测线程是否joinable joinable : 代表该线程是可执行线程。 not-joinable :通常一下几种情况会导致线程成为not-joinable      1) 由thread的缺省构造函数构造而成(thread()没有参数)。      2) 该thread被move过(包括move构造和move赋值)

Documentation_scheduler_sched-rt-group.txt

如果想评论或更新本文的内容,请直接联系原文档的维护者。 如果你使用英文交流有困难的话,也可以向中文版维护者求助。 如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。 中文版维护者: 陶莹莉  tyl18768122426@163.com 中文版翻译者:  陶莹莉  tyl18768122426@163.com 中文版校译者:  陶莹莉  tyl18768122426@163.co