1 中断
1.1 中断
中断没什么说的,发生中断保存上下文,跳到相应的中断执行中断服务程序,执行完毕跳出来。但是对于不同的系统,对于中断跳出后的点是不一样的。
- 前后台系统,中断回到后台程序
- 不可剥夺内核系统,中断回到被中断了的任务
- 可剥夺系统,中断选取任务就绪表中优先级最高的任务执行
1.2 中断延迟
中断延迟对于实时内核来说是一项重要指标,表示着中断被关了多长时间。所有实时系统在执行临界区代码段都要关中断,执行完之后再打开中断。这段时间就是中断延迟。
中断延迟 = 关中断的最长时间 + 开始执行中断服务子程序的第一条指令的时间
1.3 中断响应
中断响应定义为从中断发生到开始执行用户的中断服务子程序代码来处理这个中断的时间。中断响应时间包括开始处理这个中断前的全部开销。典型地,执行用户代码之前要保护现场,将 CPU 的各寄存器推入堆栈。这段时间将被记作中断响应时间。不同系统内核的中断响应时间不同。
- 前后台系统中断响应时间 = 中断延迟 + 保存CPU内部寄存器的时间
- 不可剥夺型内核响应时间 = 中断延迟 + 保存CPU内部寄存器的时间
- 可剥夺型内核响应时间 = 中断延迟 + 保存CPU内部寄存器的时间 + 内核进入中断服务函数的执行时间
中断响应时间是以最坏情况下的中断响应时间为准。比如某系统100次里有99次都是50us内响应,只有一次是250us响应的,中断响应时间按照250us来算。
1.4 中断恢复
中断恢复时间定义为微处理器返回到被中断了的程序代码所需要的时间。在前后台系统中,中断恢复时间很简单,只包括恢复 CPU 内部寄存器值的时间和执行中断返回指令的时间。不同系统的中断恢复时间也不同。
- 前后台系统中断恢复时间 = 恢复 CPU 内部寄存器值的时间 + 执行中断返回指令的时间
- 不可剥夺型内核中断恢复时间 = 恢复 CPU 内部寄存器值的时间 + 执行中断返回指令的时间
- 可剥夺型内核中断恢复时间 = 判定是否有优先级更高的任务进入了就绪态的时间 + 恢复那个优先级更高任务的 CPU 内部寄存器的时间 + 执行中断返回指令的时间
1.5 非屏蔽中断
有时,中断服务必须来得尽可能地快,内核引起的延时变得不可忍受。在这种情况下可以使用非屏蔽中断,绝大多数微处理器有非屏蔽中断功能。通常非屏蔽中断留做紧急处理用,如断电时保存重要的信息。然而,如果应用程序没有这方面的要求,非屏蔽中断可用于时间要求最苛刻的中断服务。
2 时钟节拍
时钟节拍是特定的周期性中断。这个中断可以看作是系统心脏的脉动。中断之间的时间间隔取决于不同的应用,一般在 10ms到 200ms 之间。时钟的节拍式中断使得内核可以将任务延时若干个整数时钟节拍,以及当任务等待事件发生时,提供等待超时的依据。时钟节拍率越快,系统的额外开销就越大。
说白了时钟节拍就是一个定时发生的中断,比如时钟节拍是10ms,那么这个中断就是10ms发生一次,在可剥夺型内核,这个中断产生之后,也会切换到优先级最高的任务,这就是可剥夺型内核所谓的任务会被高优先级任务抢断,即使用户没有使用任何中断。只要时钟节拍在,就会每次时钟节拍发生一次高优先级抢占低优先级任务的情况。当然,当中断被禁止时,时钟节拍的中断也会被禁止,这也是为什么禁止中断能有效的防止高优先级任务抢占低优先级任务。
时钟节拍还可以用于延时使用,但是这个延时不是精确的,而是有一定的延迟,如果一个任务至少需要延迟5个时钟节拍,那么在程序中需要延时6个时钟节拍才能够保证至少5个时钟节拍的延时。
延时抖动第一种情况,如下图所示,时钟节拍为20ms,所谓的延时20ms,其实就是延时一个时钟节拍,但是在延时申请时,等到下一个时钟节拍到来,就认为延时了一个时钟节拍,但是这个时间,就是开始延时到认为延时结束,实际上是不够20ms 的,因为它虽然是触发了一次时钟节拍,但是这个延时是在两次时钟节拍间隔产生的。
延时抖动第二种情况,时钟节拍也是20ms。如下图所示,由于有比这个任务优先级更高的任务,还有其他的中断发生,以至于这个任务开始的时候已经快接近下一个时钟节拍了(t1 6ms处)。那么就是说这个延时只有6ms。
还有第三种延时抖动的情况,如上两副图的t3。延时在时钟节拍开始没多久就开始了,但是因为下一个时钟节拍处,比该任务优先级高的任务占了大部分时间,导致这个任务被推后了,等到它的时候延时已经超过了20ms很多。
综上,假如需要延时x个时钟节拍,时钟节拍时间为t,那么实际延时的时间y应该是:
( x - 1 ) * t < y < ( x+1 ) * t
延时抖动总是存在的,而尽量缩减延时抖动倒是有些办法:
- 增加微处理器的时钟频率
- 增加时钟节拍的频率
- 重新安排任务的优先级
- 避免使用浮点运算(如果非使用不可,尽量用单精度数)
- 使用能较好地优化程序代码的编译器
- 时间要求苛刻的代码用汇编语言写
3 小结
关于实时操作系统的一些概念算是介绍完了。接下来才是真正开始进入uC/OS-II操作系统的探究。
总的来说,个人觉得实时操作系统,或者只是针对uC/OS-II来说,比较重要的一些字眼,像任务、任务调度、优先级、信号量、消息邮箱、消息队列、时钟节拍。之前觉的操作系统这种东西离自己还很远,也并不了解这一块的知识,现在接触了这个,也只能说我能透着门缝看一看里面的世界,还不够格说入门。以后路还长,要学的还多着。
我不确定我会怎么记录接下来的这些东西,因为现在工作上也急需用到这些东西,不一定有时间一点点去磕源码。如果没有时间的话,也希望自己以后能有时间并且有兴趣去磕一磕内核的源码。
后记
毕业两个多月,工作了也快四个月了。真正接触这些东西,这些代码,加起来的时间可能不到半年。之前也不知道自己想学什么,自己自学过一些后期,小语种,安卓开发之类,也都不了了之。连找工作也是投了嵌入式和安卓两种简历,算是逮着哪个是哪个,然后后来就还是做了嵌入式。之前对嵌入式的理解还是很局限,现在也不敢说了解太多,甚至觉得自己做的工作可能还称不上嵌入式开发。刚入职时梦想自己可以从硬件做到前端,成一名物联网全栈工程师。今天老大给了我一份前端的代码,凭借着可怜的JS知识愣是一点没看懂。懂得所谓的物联网全栈工程师有多么的遥远,毕竟所谓的全栈工程师,连百度词条上也写的只是web开发全栈工程师,物联网全栈工程师可能只是自己编篡的一个好听的名字罢了。何况连现在本职都做不好,还谈什么别的。还是那句话,要走的路还很长,等到一年之后再回来看到这段话,应该会颇有感慨吧。