RTOS从零开始(1)从裸机转变成RTOS的思路与意义
如有错误烦请大家指出。
======专栏地址======
一、裸机的弊端与改进
- 轮询方式:弊端很明显,整个业务逻辑全在while中,只能顺序执行,而每个事件里都有或多或少的delay函数,导致MCU浪费很多时间空转,而且后面事件受到前面事件的运行时长影响,效率很低,实时性很差。
//程序只做大概参考
void main()
{
while(1){
event1();
event2();
...
}
}
- 初步改进:事件驱动方式(前后台):较轮询改善不少,受事件(中断)驱动,事件标志未触发则不会处理该事件函数,减少了很多不必要的执行时间,但是仍然不能彻底解决实时性的问题,因为某个事件标志被置位后,也不能立即就执行,还是必须等到当前事件执行结束,并且后面的事件没触发,才有机会获得执行。
//程序只做大概参考
void main()
{
while(1){
if(event1_flag){
event1();
}
if(event2_flag){
event2();
}
}
}
void event1_isr()
{
event1_flag = 1;
}
void event2_isr()
{
event2_flag = 1;
}
- 二次改进:假设event1和2都是执行时间很长的函数,那可以给它们设置一个执行周期,减少因中断结束而返回的地点在其他程序执行过程中而浪费的时间,但是哪怕这样也无法绕过长时间执行的程序。
//程序只做大概参考
void main()
{
while(1){
event1();
event2();
event3();
}
}
void event1_isr()
{
event1_flag = 1;
}
void event2_isr()
{
event2_flag = 1;
}
void event3_isr()
{
event3_flag = 1;
}
void event1()
{
static u16 cycleTime = 5; //例如定时器1ms中断一次,则5ms处理一次event1
if(cycleTime--)
{
return;
}
cycleTime = 5;
if(event1_flag){
...
}
}
void event2()
{
static u16 cycleTime = 10; //例如定时器1ms中断一次,则10ms处理一次event2
if(cycleTime--)
{
return;
}
cycleTime = 10;
if(event2_flag){
...
}
}
void event3()
{
static u16 cycleTime = 10;
if(cycleTime--)
{
return;
}
cycleTime = 10;
if(event3_flag){
...
}
}
- 再次改进:如果两个任务执行的时间很长,那可以用状态机思路(状态机思路在普通的嵌入式编程中尤为重要)将一个任务打散成很多段,然后切换着执行。
//程序只做大概参考
void main()
{
while(1){
if(event1_flag){ //1
event1();
}
if(event2_flag){ //1
event2();
}
}
}
void event1_isr()
{
event1_flag = 1;
}
void event2_isr()
{
event2_flag = 1;
}
void event1()
{
static u8 state = 0;
switch(state)
{
case(0):
{
state++;
break;
}
case(1):
{
state++;
break;
}
...
}
event1_flag = 0;
}
void event2()
{
static u8 state = 0;
switch(state)
{
case(0):
{
state++;
break;
}
case(1):
{
state++;
break;
}
...
}
event2_flag = 0;
}
二、RTOS思维初窥
上述方案的问题在于我们每次响应了中断后,都要返回到原来产生中断的位置继续往下执行,直到执行到该次响应中断的对应函数才执行该事件,哪怕人为的去打散任务也依旧受到前面函数的运行时间影响。
- 最终改进思路:
在每次进入中断前,保存MCU的当前状态和数据,然后进入中断进行处理,然后完成该中断后,改变程序的返回位置,让程序不返回到刚刚产生中断的位置,而从最新获得中断标志的对应事件地址开始执行,这样就可以达到彻底的实时性。
而这就是RTOS的作用,下面的event1/2就可以简单理解成“线程”,可以简单的把RTOS理解成,把event1和event2拆分成许多部分(时间片),通过RTOS来进行快速的切换执行。
注:单核单线程的MCU,就算用上RTOS还是无法改变芯片单线程,所谓实时系统,只是让其无限接近实时而已。
//程序只做大概参考
void main(){
//配置RTOS
XXRTOS_Init();
}
void event1_isr()
{
event1_flag = 1;
}
void event2_isr()
{
event2_flag = 1;
}
void event1()
{
while(1){
if(event1_flag){
...
}
}
}
void event2()
{
while(1){
if(event2_flag){
...
}
}
}