1 体系中止与时钟节拍
1.1 体系中止
中止是一种硬件机制,用于告诉CPU有个异步作业产生了。中止一旦被体系辨认,CPU则保存部分(或悉数)现场(context),即部分(或悉数)寄存器的值,跳转到专门的子程序,称为中止服务子程序(ISR)。中止服务子程序做作业处理,处理完结后履行使命调度,程序回到安排妥当态优先级最高的使命开端运转(关于可掠夺型内核)。
中止使得CPU能够在作业产生时才予以处理,而不用让微处理器接连不断地查询(polling)是否有作业产生。经过两条特别指令:关中止 (disable interrupt)和开中止(enable interrupt)能够让微处理器不呼应或呼应中止。在实时环境中,关中止的时刻应尽量的短,关中止影响中止呼应时刻,关中止时刻太长或许会引起中止丢掉。中止服务的处理时刻应该尽或许的短,中止服务所做的作业应该尽或许的少,应把大部分作业留给使命去做。
1.2 体系时钟节拍
时钟节拍是特定的周期性中止(时钟中止),这个中止能够看作是体系心脏的脉动。操作体系经过时钟中止来确认时刻距离,完结时刻的延时及确认使命超时。中止之间的时刻距离取决于不同的使用,一般在10~200 ms之间。时钟的节拍式中止使得内核能够将使命延时若干个整数时钟节拍,以及当使命等候作业产生时供给等候超时的根据。时钟节拍频率越快,体系的额定开支就越大。体系界说了32位无符号整数OSTime来记载体系启动后时钟滴答的数目。用户必须在多使命体系启动今后再敞开时钟节拍器,也就是在调用 OSStart()之后。μC/OSII中的时钟节拍服务是经过在中止服务子程序中调用OSTimeTick()完结的。时钟节拍中止服务子程序的暗示代码如下:
void OSTickISR(void) {
保存处理器寄存器的值;
调用OSIntEnter ()或是将OSIntNesting加1;
调用OSTimeTick ();
调用OSIntExit ();
康复处理器寄存器的值;
履行中止回来指令;
}
2 时钟办理体系
2.1 ucos ii时钟办理体系
ucos ii原有的时钟办理体系类似于Linux,可是比Linux简略得多。它仅向用户供给一个周期性的信号OSTime,时钟频率能够设置在 10~100 Hz,时钟硬件周期性地向CPU宣布时钟中止,体系周期性呼应时钟中止,每次时钟中止到来时,中止处理程序更新一个全局变量OSTime。ucos ii时钟中止服务程序的中心是调用OSTimeTick ()函数。OSTimeTick ()函数用来判别延时使命是否延时完毕然后将其置于安排妥当态。其程序伪代码如下:
void OSTimeTick(void) {
OSTimeTickHook();// 调用用户界说的时钟节拍外连函数
while { (除闲暇使命外的一切使命)
OS_ENTER_CRITICAL();//关中止
对一切使命的延时时刻递减;
扫描时刻到期的使命,而且唤醒该使命;
OS_EXIT_CRITICAL();//开中止
指针指向下一个使命;
}
OSTime++;//累计从开机以来的时刻
}
在ucos ii的时钟节拍函数中,需求履行用户界说的时钟节拍外连函数OSTimeTickHook (),以及对使命链表进行扫描而且递减使命的延时。这样就造成了时钟节拍函数OSTimeTick ()有两点不
足:
① 在时钟中止中处理额定的使命OSTimeIickHook (),这样增加了中止处理的担负,影响了守时服务的准确性; ② 在关中止情况下扫描使命链表,使命越多所需求时刻越长,而长时刻关中止对中止呼应有晦气影响,是中止处理应当防止的。
2.2 改善的时钟办理体系
针对上述OSTimeTick ()的缺乏之处,需加以改善来优化时钟节拍函数。在Linux中一般对中止的呼应分为两部分:当即中止服务和底半中止处理(bottom half)。当即中止服务只是做重要的而且能快速完结的作业,而把不太重要的需求较长时刻完结的作业放在底半处理部分来完结,这样就能够进步中止呼应速度。
ucos ii不支持底半处理,为了减轻时钟中止处理程序的作业量来进步ucos ii的时钟精确度,能够将一部分在每次时钟中止需处理的作业内容放在使命级来完结。这样就能够削减每次时钟中止处理的CPU耗费,然后进步中止呼应速度和 ucos ii的时钟精确度。为此,界说使命OSTimeTask (),由它来处理本来在OSTimeTick()中需求处理的操作。由于μC/OSII选用根据优先级的抢占式调度战略,而每次时钟中止处理程序完毕后需求首要调度该使命履行,因而让使命OSTimeTask()具有体系内最高优先级。由它履行用户界说的时钟节拍外连函数OSTimeTickHook (),以及对一切使命的延时时刻进行递减,并把到期的使命链入到链表OSTCBRList中,OSTCBRList办理一切到期使命。 OSTimeTask()函数伪代码如下:
void OSTimeTask() {
OSTimeTickHook()//用户界说的时刻处理函数
while { (除闲暇使命外的一切使命)
对一切使命的延时时刻进行递减;
把一切要到期的使命链入到OSTCBRList链表中;
}
使命状况改为睡觉,调用OSSched ()进行使命调度;
}
在使命OSTimeTask()中,履行本来在时钟中止处理的用户函数OSTimeIickHook (),并完结将延时到期的使命链入到OSTCBRList链表中,这样在时钟中止程序中就只需求扫描使命到期的链表而不需求扫描整个链表,削减了关中止的时刻。OSTCBRList为新建链表,它办理一切到期的使命。
一起,需求削减OSTimeTick ()的履行作业量,只对OSTCBRList链表扫描,这样也削减了关中止时刻。OSTimeTick ()伪代码如下:
void OSTimeTick(void) {
OSTime++;
OS_TCB* ptcb=OSTCBList;// OSTCBRList指向一切到期使命的链表
while(ptchb!=null){
关中止;
唤醒使命;
开中止;
指针指向下一个使命;
}
}
3 小结
本文以开源的嵌入式操作体系ucos ii为例,剖析了操作体系的中止机制和中止应满意的条件。介绍了ucos ii体系时钟节拍,探讨了时钟中止函数中存在的缺乏,而且给出了解决方案,然后有用进步了中止呼应速度和ucos ii的时钟精确度。