简易多任务抢占式调度器设计(二)
经典丶
|
2019.12.31
|
15615
+关注

二、什么是抢占式调度?

调度的概念,通俗的说就是系统在多个任务中选择合适的任务执行。系统如何知道何时该执行哪个任务?可以为每个任务安排一个唯一的优先级别,当同时有多个任务就绪时,优先运行优先级较高的任务。

同时,任务的优先级也作为任务的唯一标识号。代码中都是对标识号来完成对任务的操作的。如如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. }

注意:不要在空闲任务中运行有可能使任务挂起的函数。空闲任务应该一直处于就绪状态。

精选留言
延伸阅读
2020.10.02
13886阅读
更多报告干货
写留言
3816
阅读
收藏
回到顶部