打印

ucosII的非占先化的改造。

[复制链接]
1470|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tianhongwei|  楼主 | 2010-5-1 12:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


ucosII
的另一种用法

网上看到的帖子,用ucosII都是直接移植到某种CPU上运行。但是自从我比较深入学习ucosII的时候开始,我就一直不把ucosII当做一个占先式操作系统,而是把他进行改造成非占先的系统。今天我把我做法帖出来,大家讨论一下这种做法是否妥当。
       很简单,做过单片机编程的人都知道,开始实现要求的功能时,都会对所实现的功能进行分解成多个任务,然后采用某种调度方式进行循环作业。
       在这里,ucosII就是我上面提到的“某种”调度方式。
       因此,实际上我的做法是,将ucosII中的调度算法,从整套系统剥离出来,运用在实际的应用系统。
       仔细阅读ucosII的源码,可以知道,其调度算法涉及到一下几个指令(函数)和数据结构。
1.
使任务进入就绪态:
OSRdyGrp
|= OSMapTbl[prio >> 3 ];

OSRdyTbl[prio >> 3 ] |= OSMapTbl[prio & 0x07 ];
2.
使任务脱离就绪态:

If( (OSRdyGrp[prio >> 3 ] &= ~OSMapTbl[prio & 0x07 ]
) == 0 )

{

OSRdyGrp &= ~OSMapTbl[prio >> 3 ];

}
//Else
//{
//}

3.找出进入就绪态的优先级最高的任务,可以封装成一个函数,命名为ucosII中的
Uchar OS_Sched(void )
{
Uchar x;
Uchar y;
Uchar prio;
y = OSUnMapTbl[OSRdyGrp ];
x = OSUnMapTbl[OSRdyTbl[y ] ];
prio = y<<3 + x;
return(prio );
}
上述是讲ucosII中最重要的函数进行了删减,仅仅保留其核心部分。当然采用如下方式调用:
EA = 0;
HighPrio = OS_Sched();
EA = 1;

3.
从上述几条指令或函数可以看出,实现这些指令至少需要构建如下几个数据结构:
Uchar OSRdyGrp;
Uchar OSRdyTbl[8 ] = { };//初始化为0
Uchar OSMapTbl[8 ] = {};
Uchar OSUnMapTbl[ ] = {};
上述四个数组中,后两个是常量表,其值可以参考ucosII的源代码,因此为了节省ram,可以将他们放入romflash中,在51中,直接用code进行声明。

有了上述的指令和数据结构,就算完成了内核构建。怎么用呢?
首先一个前提是,系统被分解为多个功能任务,每一个任务都一个不同优先级,安排为0~63。然后采用下面的方式进行调度。
    在我的系统中,采用循环调度策略。但一次循环只用两个函数被调用,一个就是上面提到的OS_Sched;另一个就是实际的功能函数,如Task_Function1/Task_Function2…….
       实际上一次大循环中,通过OS_Sched找出当前优先级最高的任务的优先级(0~63 ),接下来通过这个优先级调用功能函数。有很多种方法进行调用如

While(1 )


{


EA = 0;


HighPrio = OS_Sched();


EA = 1;


Switch(HighPrio )


{


Case 0:


Task_Function1();


Break;


…………….


Default


…..


Break;

}
}

上述方法有一个缺点,很多编译器对switch语句优化得并不好,如keil,因此一次大循环将浪费很多调度时间。怎么办呢?几个热心的网友,教我一招,用函数指针数组解决。
因此先建立一个函数指针数组如
void (*pFun[ 64])(void ) =
{

Task_Funciton0,


Null_Deal;


………..

}
当然任务在该数组中的位置,要和其任务优先级高度一致,否则就出错。该数组一旦建立,实际上也是一个常数表,可以放在flash中,便于节约Ram区。
因此一次大循环采用如下方式:
While(1 )
{

EA = 0;


HighPrio = OS_Sched();


EA = 1;


*pFun[HighPrio ];

}

注意事项:
对于最低优先级的任务,任务优先级为63,处理方式与别的任务稍有不同,一般的任务在任务的结尾或开始需要调用“使任务脱离就绪态”的指令将本身的就绪状态清除,否则该任务一直处于就绪状态,优先级比他低的任务永远都得不到执行。但最低优先级任务,本身优先级最低,因此不需要调用“使任务脱离就绪态“的指令。也就是它一直就绪,随时都可以再执行。

该方案要充分体现优越性,还有很多方面需要考虑。
1该系统是非占先,因为一个任务在没有执行完之前,即便是有更高优先级的任务因为某些原因处于就绪状态,也得不到任务,也需要这个任务执行完后通过调度的方式才能执行。因此我们的任务函数不能太大,或者执行的时间不能太长,否则实时性就很差。但有时候一个功能不能细分,或几个功能确实需要按部就班地执行,不能分割,怎么办呢?
这时候,我们可以强行将一个功能分解成一连串的动作,封装成几个任务,几个任务优先级靠近,如45,6,7,任务就绪时,可以首先就绪优先级为7的任务,在该任务结束前,将任务6就绪,重新进行调度,直到4。这样,4个动作连贯执行,同时,如果在几个动作执行的中间有其他任务,如优先级为2的任务就绪,同样可以满足其实时性。
2。最低优先级任务的处理,除了前面提到的不能解除其就绪状态,和初始化为就绪外,还需要一些考虑。系统中,个人认为,除非系统设计得相当好,其实大多数时间,CPU都是在最低优先级任务中跑,因此可以将一些需要一直刷新,但是实时性要求又不是太高的任务封装成最低优先级。当然如果系统中有很多功能都具有该特性,则可以按照1的方法,将最低优先级进行分解为63,62,61,。。。。由63就绪62。。。。


ucosii这样用的好处,免除移植的工作,虽然ucosII的移植并不困难。另外一个方面,这样做的好处,对系统的开销,如ram,flash缩减到了最小。在很多很低端的CPU中,都可以使用,虽然ucosii本身已经很小。还有一个显而易见的好处是,这种方法,使得ucosII彻底与CPU的架构无关,可以用于任意一种CPU架构中,只要该架构的Cpu支持C编程。

对于我的这种用法,很多人一致褒贬不一,希望各位前辈高人多提宝贵意见,不甚感激。

欢迎转载。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

9

帖子

1

粉丝