二、什么是抢占式调度?
调度的概念,通俗的说就是系统在多个任务中选择合适的任务执行。系统如何知道何时该执行哪个任务?可以为每个任务安排一个唯一的优先级别,当同时有多个任务就绪时,优先运行优先级较高的任务。
同时,任务的优先级也作为任务的唯一标识号。代码中都是对标识号来完成对任务的操作的。如如OSDelPrioRdy(prio),OSSetPrioRdy(prio)等。
不同的优先级对应就绪表中的每一位。。低位对应高优先级。。优先级级0的优先权最高,,优先级级31的优先权最低
在程序中要为每一个任务分配一个唯一的优先级
1. Main.c
2. ///************** 定 义 任务 优 先 级*************///
3. #define PrioTask0 0
4. #define PrioTask1 1
5. #define PrioTask2 2
6. #define PrioTask3 3
所谓“抢占式调度”是指:一旦就绪状态中出现优先权更高的任务,便立即剥夺当前任务的运行权,把把CPU分配给更高优先级的任务。样这样CPU总是执行处于就绪条件下优先级最高的任务。
在程序中查找最高优先级的任务代码如下:
1. RTOS.h
2. /* 在就 绪表 中 查 找 更 高级 的 就 绪 任务 */
3. #define OSGetHighRdy() \
4. { \
5. for( OSNextTaskPrio = 0; \
6. (OSNextTaskPrio < OS_TASKS) && (!(OSRdyTbl & (0x01<<OSNextTaskPrio))); \
7. OSNextTaskPrio ++ ); \
8. OSPrioHighRdy = OSNextTaskPrio; \
9. }
注意:使用这种算法来查找最高优先级的系统严格来说不能称为实时系统。实时系统的特征是延时可预测,能够在一个规定的时间内(通常是是ms级别的)对某些信号做出反应。这种算法的延时随任务的数量的改变而不同,但却是最简便的。
三、多任务系统的时间管理
与人一样,多任务系统也需要一个“心跳”来维持其正常运行,这个心跳叫做时钟节拍,通常由定时器产生一个固定周期的中断来充当,频率一般为为50-100Hz。在TargetInit.c文件中有下面的定时器0初始,化函数,T0用作系统心跳计,时,产生时钟节拍。
1. RTOS.h
2. #define OS_TICKS_PER_SEC 100 /* 设置 一 秒 内 的时 钟节拍 数*/
3. TargetInit.c
4. void StartTicker(INT32U TicksPerSec)
5. {
6. rTCFG0 = 99; //Prescaler0 = 99
7. rTCFG1 = 0x03; //Select MUX input for PWM Timer0:divider=16
8. rTCNTB0 = 31250 / TicksPerSec; // 设置中断频 率
9. rTCON |= (1<<1); //Timer 0 manual update
10. rTCON = 0x09; //Timer 0 auto reload on
11. //Timer 0 output inverter off
12. // 清"Timer 0 manual update"
13. //Timer 0 start */
14. BIT_CLR(rINTMSK, BIT_TIMER0); // Enable WatchDog interrupts
15. }
OSTimeDly函数就是以时钟节拍为基准来延时的。这个函数完成功能很简单,就是先挂起当起当前任务,设定其延时节拍数,然后进行任务切换,在指定的时钟节拍数到来之后,将当前任务恢复为就绪状态。任务必须通过过OSTimeDly或或OSTaskSuspend让出出CPU的使用权,使更低优先级任务有机会运行。
1. RTOS.c
2. void OSTimeDly(INT32U ticks)
3. {
4. if( ticks > 0 ) /* 当 延时有 效 */
5. {
6. OS_ENTER_CRITICAL();
7. OSDelPrioRdy(OSPrioCur); /* 把 任务 从 就 绪表 中 删 去 */
8. TCB[OSPrioCur].OSTCBDly = ticks; /* 设置 任务延时 节拍 数 */
9. OS_EXIT_CRITICAL();
10. OSSched(); /* 重 新 调度 */
11. }
12. }
在T0的中断服务函数中,,依次对各个延时任务的延时节拍数减减1。若发现某个任务的延时节拍数变为为0,则把它从挂起态置为就绪态。
1. RTOS.c
2. void TickInterrupt(void)
3. {
4. static INT8U i;
5. OSTime ++;
6. //Uart_SendByte('I');
7. for(i = 0; i < OS_TASKS; i++) /* 刷新 各 任务时 钟 */
8. {
9. if(TCB[i].OSTCBDly )
10. {
11. TCB[i].OSTCBDly --;
12. if(TCB[i].OSTCBDly == 0) /* 当 任务时 钟 到时, 必 须 是 由 定 时
13. 器 减 时的 才 行*/
14. {
15. OSSetPrioRdy(i); /* 使 任务 可 以 重 新 运行 */
16. }
17. }
18. }
19. rSRCPND |= BIT_TIMER0;
20. rINTPND |= BIT_TIMER0;
21. }
系统自身创建了一个空闲任务,并设它为最低优先级,当系统没有任何任务就绪时,则运行这个任务,让让CPU“有事可干””。用户程序可以在这个任务中加入一些些“无关紧要”的功能,如统计计CPU使用率等。
1. RTOS.c
2. void IdleTask(void)
3. {
4. IdleCount = 0;
5. while(1)
6. {
7. IdleCount++;
8. //Uart_Printf("IdleCount %d\n",IdleCount);
9. }
10. }
注意:不要在空闲任务中运行有可能使任务挂起的函数。空闲任务应该一直处于就绪状态。