RT-Thread

目录

RT-Thread

 启动流程

rtthread_startup()函数

rt_application_init()函数     

void  main_thread_entry(void*parameter)

重映射串口到rt_kprintf函数

SysTick_Handler()

线程管理

消息队列

信号量

互斥量

事件

软件定时器

邮箱


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()中执行。

和freertos一样,在pend_sv()中断中切换线程。


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

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

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


线程管理

rtthread的线程控制函数分别为线程挂起函数rt_thread_suspend()和线程恢复函数rt_thread_resume()还有线程删除函数rt_thread_delete() 。

这些函数的作用与freertos中的任务挂起vTaskSuspend ( TaskHandle_t xTaskToSuspend )

任务恢复vTaskResume ( TaskHandle_t xTaskToResume )    任务删除vTaskDelete( TaskHandle_t xTaskToDelete )的功能是一样的。

都是填入任务(线程)的控制句柄(线程控制块指针)。

但是好像没有freertos的挂起所有任务函数和恢复所有任务函数,算了,感觉这俩函数也没什么用武之地!


消息队列

和FreeRTOS的功能几乎没有什么区别,无非是函数的名字或者形式不太一样。


信号量

在RT-Thread中,创建二值信号量和创建计数信号量共用一个信号量创建函数rt_sem_create()。

他们的区别就是在使用信号量创建函数的时候的信号量初始值不同。

二值信号量可用个数的取值范围是0~1,计数信号量可用个数的取值范围是0~65535,用户可以根据需求选择。

其他的信号量获取与释放还有删除什么的功能都差不多。参数都是消息控制块和等待时间什么的。


互斥量

互斥量的作用是在保护临界资源的同时避免产生优先级翻转的情况,在使用的同时也注意避免产生死锁的现象。

其函数互斥量的创建删除释放获取都和freertos差不多,重要的是明白互斥量的原理以及和二值信号量的区别。


事件

事件集合用32位无符号整型变量来表示,每一位代表一个事件,线程通过“逻辑与” 或“逻辑或”与一个或多个事件建立关联,形成一个事件集。事件的“逻辑或”也称作是 独立型同步,指的是线程感兴趣的所有事件任一件发生即可被唤醒;事件“逻辑与”也称 为是关联型同步,指的是线程感兴趣的若干事件都发生时才被唤醒。

与freertos不同的是,freertos只支持24个事件,而rtthread支持32个。

RT-Thread 提供的事件具有如下特点:

  •  事件只与线程相关联,事件相互独立,一个 32位的事件集合(set 变量),用于 标识该线程发生的事件类型,其中每一位表示一种事件类型(0 表示该事件类型 未发生、1表示该事件类型已经发生),一共32种事件类型。
  •  事件仅用于同步,不提供数据传输功能。
  •  事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),等效于 只发送一次。
  •  允许多个线程对同一事件进行读写操作。
  • 支持事件等待超时机制。

其余功能都是相似的,事件的创建与删除,发送和接受(置位和等待)。


软件定时器

软件定时器都是一样的,分为多次和单次模式,对定时器进行创建启动停止和删除

RT-Thread 提供的软件定时器支持单次模式和周期模式,单次模式和周期模式的定时 时间到之后都会调用定时器的超时函数,用户可以在超时函数中加入要执行的工程代码。 单次模式:当用户创建了定时器并启动了定时器后,定时时间到了,只执行一次超时 函数之后就将该定时器删除,不再重新执行。 周期模式:这个定时器会按照设置的定时时间循环执行超时函数,直到用户将定时器 删除

与freertos不同的是,在rtthread中的单词模式定时器到时间会主动把自己删除,而freertos到达事件之后只会把自己休眠,如果在其他任务中去复位该休眠定时器,可以再次使用。

而且rtthread也没有定时器复位功能。

其余的要求和freertos的差不多诸如不允许调用 rt_thread_delay()等导致上下文挂起的API接口,软件定时器的所定时数值必须是这 个节拍周期的整数倍等。


邮箱

这个是freertos中没有的功能。

邮箱在操作系统中是一种常用的 IPC 通信方式,邮箱可以在线程与线程之间。中断与 线程之间进行消息的传递,此外,邮箱相比于信号量与消息队列来说,其开销更低,效率 更高,所以常用来做线程与线程、中断与线程间的通信。

邮箱中的每一封邮件只能容纳固 定的 4字节内容(STM32是 32位处理系统,一个指针的大小即为 4个字节,所以一封邮 件恰好能够容纳一个指针),当需要在线程间传递比较大的消息时,可以把指向一个缓冲 区的指针作为邮件发送到邮箱中。

通过邮箱,线程或中断服务函数可以将一个或多个邮件放入邮箱中。同样,一个或多 个线程可以从邮箱中获得邮件消息。当有多个邮件发送到邮箱时,通常应将先进入邮箱的 邮件先传给线程,也就是说,线程先得到的是最先进入邮箱的消息,即先进先出原则 (FIFO),同时 RT-Thread 中的邮箱支持优先级,也就是说在所有等待邮件的线程中优先级 最高的会先获得邮件。

RT-Thread 中使用邮箱实现线程异步通信工作,具有如下特性:

  •  邮件支持先进先出方式排队与优先级排队方式,支持异步读写工作方式。
  •  发送与接收邮件均支持超时机制。
  •  一个线程能够从任意一个消息队列接收和发送邮件。
  •  多个线程能够向同一个邮箱发送邮件和从中接收邮件。
  •  邮箱中的每一封邮件只能容纳固定的4字节内容(可以存放地址)。
  •  当队列使用结束后,需要通过删除邮箱以释放内存。

邮箱与消息队列很相似,消息队列中消息的长度是可以由用户配置的,但邮箱中邮件 的大小却只能是固定容纳 4字节的内容,所以,使用邮箱的开销是很小的,因为传递的只 能是4字节以内的内容,那么其效率会更高。

具体怎么用的看野火的文档和例程吧。实在懒得写了。


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

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

RT-Thread Web是一个基于RT-Thread实时操作系统的开源Web服务器框架。RT-Thread是一个轻量级的实时操作系统,它具有低内存占用、快速启动、可裁剪性的特点,适用于资源受限的嵌入式系统。而RT-Thread Web作为其扩展模块之一,为嵌入式设备提供了一个简单、高效的Web服务能力。 RT-Thread Web充分利用了RT-Thread的特性,通过与RT-Thread实时内核的集成,可以使嵌入式设备具备Web服务器的功能,支持HTTP和HTTPS协议。RT-Thread Web具有多线程支持和相对较小的内存占用,使嵌入式设备可以同时处理多个web请求,拥有更好的实时性和性能表现。 RT-Thread Web提供了丰富的功能,包括HTTP请求处理、静态页面服务、动态脚本解析、文件上传、Cookie管理等。同时,RT-Thread Web还支持对URL的路由处理和HTTP的各种请求方法(GET、POST、PUT、DELETE等)的处理,可以根据不同的需求进行灵活的配置和扩展。 使用RT-Thread Web,开发者可以方便地将Web服务嵌入到嵌入式设备中,使其具备与PC或手机等终端设备进行数据交互和远程控制的能力。这对于物联网设备、智能家居、工业自动化等领域的嵌入式系统来说,具有十分重要的意义。 总之,RT-Thread Web作为RT-Thread实时操作系统的一个重要组成部分,为嵌入式设备提供了简单、高效的Web服务能力,使其可以方便地与外部环境进行通信和交互。在嵌入式系统领域中,RT-Thread Web具有广泛的应用前景和市场潜力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值