type
status
date
slug
category
tags
icon
password
summary

碎碎念

自己接触到RTOS其实算来也已经有一年多了,但是自己其实不能说已经弄懂它了,因为对于其内部机理,我并不了解。而且还有一点就是,现在我连它的API也忘得差不多了,我想,我算是忘记完了,那就重新再学一遍吧。相当于重新复习一遍,为秋招做准备。那么,暑假的第一个任务就是复习RTOS,把FreeRTOS和RT-Thread的内部机制原理搞明白,然后重新做一遍自己之前的项目。
然后,我的学习过程可能是跟着韦东山老师的视频进行学习,博客的内容算是当作笔记。

为什么需要RTOS?

为什么需要RTOS呢?用韦东山老师的话来说就是,逻辑程序代码有缺陷。接下来我们先从裸机编程的几个方法来讨论各个方法之间的缺陷。
 
  1. 裸机-轮询结构
    1. 裸机开发的第一种程序结构就是顺序执行结构。这种结构一般是只有主函数再跑,没有中断程序。假设在main函数中有两个函数A和B在跑,那么这个程序的逻辑结构大概就像下面这样。
      也就是说,咱们的代码是先执行A在执行B,那么就会出现这样的一个问题:如果A和B的执行时间比较长,那么A在执行的过程中B就不能响应,B在执行的过程中A就不能响应。我们假设A是按键检测程序,B是数码管显示函数。因为数码管是需要不停扫描的,此时因为A执行时间比较长,数码管的内容就得不到更新,也就是数码管数值此时就会更新不流畅;同样的,如果B在执行,此时按键按下,由于这是A并没有在执行,那么我们的这个按键就得不到响应。
       
      从上面的例子可以发现,在顺序执行的裸机代码结构中,A和B之间会互相影响,对于需要实时性比较高的功能可能实现效果就会很差了。比如上面的按键检测和数码管扫描基本都需要实时去扫描状态。
       
  1. 裸机-前后台系统
    1. 所谓的前后台系统就是把中断加了进来。有了中断之后,系统的实时性就得到了很大的提升。我们还是假设有两个函数A和B,其中A在中断程序中执行,B在主函数中执行,那么他们的代码结构如下所示。
      我们还是假设A是按键检测函数,B是数码管扫描函数。此时,按键按下的时候触发中断,A程序得到执行,A程序执行完之后B程序也得到执行。而且按键检测一般也不会丢失了,因为中断触发之后就马上响应。然后在没有按键触发的时候,数码管的扫描函数就能够一直得到执行,那么也不会出现卡顿的现象了。
       
      好像这样子并没有什么问题了,两个程序都能正常执行。但是我们忽略了一点,那就是我们默认了在中断中的程序A()执行时间很短,触发中断它很快就响应完了,所以对在主程序中的B影响不是很大。
      如果,中断中的程序执行时间比较长呢?我们会发现,A又影响到B了,因为A执行时间比较长的话,B程序数码管就长时间得不到更新,就造成了卡顿。也就是说,在前后台系统下,前台程序(中断)会影响后台程序(主程序)的执行。
      说中断程序是前台程序,因为它需要和外界进行交互,相当于接待客户中的前台。而主程序只是不断的循环,就是在后台工作,不需要接触客户,也就是后台程序。
       
  1. 裸机-时间片框架
    1. 这个框架就是里利用定时器中断作为中间管理程序,从而安排两个程序A和B的执行。大致原理是这样:在定时器服务函数中设置一个计数值,对计数值进行相应的取余操作判断哪个程序执行,大致框架如下:
      这种框架有一个优点是通过定时器来安排两个程序之间的执行时间,相当于安排好两个程序之间的执行时间,A先执行一段然后再是B执行一段。这样看的话其实我们发现它又退回到了轮询的结构中。如果A的执行时间比较长的话,那么此时就会一直执行A,就连中断都触发不了了。也就是,这两个程序之间,A、B会互相影响。
       
  1. 裸机-状态机框架
    1. 通过上面的几种裸机程序,我们发现,两个程序之间只要是单个程序的执行时间过长,就会影响到另一个程序。那么我们可以这样做,把一个程序A拆分成多个独立的部分,每次执行的时候只执行其中一部分,下一次执行的时候在执行另一个部分。对于另一个程序B也是如此。那么我们可以在程序A内部设置一个状态,程序A得到执行的时候,通过状态来判断执行哪一部分内容,然后更新状态,从而减少程序A的占用时间,让程序B也能得到较快的响应。状态机的代码结构大致如下:
      可以发现,程序A被分为了A1和A2两段,每次只执行其中一段,然后交出CPU控制权。程序B的代码也是这样,每次只执行其中一小段。这样A和B程序都能得到比较均匀的CPU使用时间,不会因为谁占用的时间比较久而导致另一个程序得不到响应。也就是A和B两个程序大家都是使用一小段时间之后就让给另一个使用。
       
      这个代码结构其实就是比较好的裸机结构了,其本质就是将大的程序分解为很多个独立小的,不让单个程序占用太多的时间。但是这样的框架会存在这样的一个问题:那就是需要程序员将大的程序分解为多个独立的小程序,这对程序员来说,任务就增多了,还有另一方面,那就是有些程序不能分成多个小的,那这样的话就很难办了,就又变成了时间片的哪个框架了。
       
综合上面的四个裸机开发框架,我们可以发现他们的比较统一的缺陷:那就是如果一个程序执行时间比较长,很有可能会影响别的程序的执行。也就是说,裸机开发需要程序员具有控制每个程序执行时间的能力,也就是不能让一个程序执行时间太长,这对程序员的代码能力要求比较高,就像状态机框架中的将大程序拆分成多个小程序那样。
正是因为这样的原因,所以我们需要学习RTOS,从而更加方便我们进行编码和管理各个程序。
 

RTOS为什么可以解决裸机缺陷

其实,通过上面裸机的分析流程我们可以发现,要想让两个程序之间的影响尽量小,那么就要求这两个程序要尽量快的执行完毕,执行时间不能太长。这个我们通过状态机框架就可以发现,状态机的这个框架其实是比较理想的,只要能把大程序分解成很多个小的程序,然后每个小的程序执行时间都比较短就能做到比较好的效果。
然后代码的执行流程大概就像下面这张图这样。两个程序(或多个)交替执行,每个程序占用较小的时间段,这样A和B之间就不会存在太大的影响。
notion image
上面的每一段都是一小段时间,那么我们可以这样想,如果我把每一段的时间给的再小一些,那么类似于A1这样的小程序的执行时间就更短了,A和B之间的就会更小。这样,我们再极端一点,我们把这个时间段想得很小很小,假设是1ms,那么我们的效果是不是更加理想了呢,答案是是的。我们下面通过一张图来理解为什么。
notion image
通过上面这张图我们可以发现A和B的程序被分成和很多段执行,每段的执行时间都很短,假设每一段都是1ms。那么我们可以这么想,在2ms的时间内,A和B都执行了1次;但是在1s的时间内,A和B都执行了500个小程序段。那如果A和B刚好都只是被分成了500个小程序段,也就是说,在1s时间后,A和B同时完成了!!!
 
也就是说,这样子细分成很多个代码片段之后,在宏观的角度上A和B差不多可以看作是同时执行的!!这就是操作系统的魅力。
 
那问题就来了,上面讲裸机-状态机框架的时候,我们说了要把程序分成小程序段对程序员来说比较困难,到这里的时候你却更加过分,还把一个程序分成了这么小的部分,那不是更加难了吗?是的,这对程序员来说是很难,但是对于CPU来说不难。也就是说,我们可以把代码分段的这个任务交给硬件去完成,而我们写代码的时候还是正常写大的程序,在运行的时候操作系统就会帮我们把大的程序按照小块来执行,也就是操作系统帮我们做了裸机的状态机框架,不需要程序员来干这个活了。
 
这么说的话,使用了操作系统,就相当于使用了时间片非常小的裸机-状态机框架,这样,我们的编码不需要考虑将代码分成小程序来写,而且两个任务之间的影响还非常小。我们上面说到了,在使用操作系统的情况下,我们的两个程序在宏观上来看几乎是并行运行的,那么他们之间自然也就不会相互影响,也就可以独立工作了。
 
到了这里,我想,我已经讲明白了为什么使用操作系统能克服裸机的缺陷了。这时候你可能会问,你上面说的不是RTOS吗?到这里怎么就变成了操作系统了?其实,RTOS就是在嵌入式设备上使用的操作系统,它的全称是实时操作系统,也就是对实时性要求很高。至于实时操作系统和非实时操作系统之间的区别,就请自行查找资料了,这里不多赘述。
 

总结

本篇文章先通过讲解4种裸机开发框架下的缺陷,即同时运行多个程序时,程序之间会相互影响,从而影响程序的实时响应,通过状态机框架可以比较好的解决这个问题,但是需要程序员对代码进行分块,难度较大。分析了4种裸机开发框架之后通过对状态机框架的进一步分析,引出操作系统的对程序的切片操作,从而说明操作系统可以克服裸机开发过程中的缺陷问题。
 
操作系统的使用方便了程序员编写代码,程序员不需要像编写裸机程序那样过于在意多个程序之间依赖关系,只需要专心完成某个任务的代码编写,不同程序之间的依赖关系交给操作系统去处理。
操作系统的使用也提高了程序的实时性,可以让多个程序同时运行,实现多线程开发。
这里说的多线程是伪的多线程,只是在宏观上的多线程,在微观上在某一时间点还是只有一个程序在执行。
 
基于以上的内容,在嵌入式开发过程中,为什么要使用操作系统?我想,你应该也有了自己的答案了吧。
大学第一次情绪崩溃Nowcoder-C-day2
ycloong
ycloong
要做一个苦行僧,探索自己的人生道路