第一个Python程序

动态路由协议-链路状态协议(LS)-持续更新(20210821)

  返回  

UCOSIII任务简介(二)

2021/8/21 19:28:39 浏览:

文章目录

  • 前言:继前文的任务简介
  • 一、任务控制块结构:
  • 二、UCOSIII任务就绪表
    • 1.优先级
    • 2.UCOSIII任务就绪表:
  • 三、UCOSIII任务调度
    • 1.可剥夺型任务调度
    • 2.任务调度点
    • 3.调度器上锁和解锁
    • 4.时间片轮转调度
  • 四、UCOSIII任务切换
    • 什么是任务切换?
  • 总结


前言:继前文的任务简介

一、任务控制块结构:

任务控制块是用来记录与任务相关的信息的数据结构,每个任务都要有自己的任务控制块。任务控制块由用户自行创建,如下代码为创建一个任务控制块:

OS_TCB StartTaskTCB;  //创建一个任务控制块

OS_TCB为一个结构体,描述了任务控制块,任务控制块中的成员变量用户不能直接访问,更不可能改变他们。所以我们写代码的时候一般都不会去改变它。

二、UCOSIII任务就绪表

1.优先级

UCOSIII中任务优先级数由宏OS_CFG_PRIO_MAX来配置,UCOSIII中数值越小,优先级越高,最低可用优先级就是OS_CFG_PRIO_MAX-1。

2.UCOSIII任务就绪表:

  • 优先级位映射表OSPrioTbl[ ]:用来记录哪个优先级下有任务就绪。
  • 就绪任务列表OSRdyList[ ]:用来记录每一个优先级下所有就绪的任务。
    我们可以看一下优先级任务的链表:
    在这里插入图片描述
    为了我们需要的任务实现,我们可以使用OS_PrioGetHighest()这个函数原型去寻找已准备就绪的最高优先级任务,代码如下:
OS_PRIO  OS_PrioGetHighest (void)
{
    CPU_DATA  *p_tbl;
    OS_PRIO    prio;

    prio  = (OS_PRIO)0;
    p_tbl = &OSPrioTbl[0];
    while (*p_tbl == (CPU_DATA)0) {
	prio += DEF_INT_CPU_NBR_BITS; 
	p_tbl++;
    }
    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); 
    return (prio);
}

该函数功能便是寻找已就绪任务前面有多少个0,来算出已就绪任务的优先级,例如:0 0 0 0 0 1;
第五个优先级前面有五个0,说明该优先级下有准备就绪的任务。且该实现为硬件实现,可以很快的找到已就绪的任务。
通过上一步我们已经知道了哪个优先级的任务已经就绪了,但是UCOSIII支持时间片轮转调度,同一个优先级下可以有多个任务,因此我们还需要在确定是优先级下的哪个任务就绪了。

struct  os_rdy_list {
    OS_TCB           *HeadPtr	 //用于创建链表,指向链表头
    OS_TCB           *TailPtr;   //用于创建链表,指向链表尾
    OS_OBJ_QTY       NbrEntries; //此优先级下的任务数量
};

这个便是我们所需要的寻找同一优先级下各任务的代码块。它是这样的:
在这里插入图片描述
同一优先级下如果有多个任务的话最先运行的永远是HeadPtr所指向的任务!

三、UCOSIII任务调度

1.可剥夺型任务调度

任务调度就是中止当前正在运行的任务转而去执行其他的任务。
UCOSIII是可剥夺型内核,因此当一个高优先级的任务准备就绪,并且此时发生了任务调度,那么这个高优先级的任务就会获得CPU的使用权!
UCOSIII中的任务调度是由任务调度器来完成的,而任务调度器有2种:任务级调度器和中断级调度器。
任务级调度器为函数OSSched()。
中断级调度器为函数OSIntExit(),当退出外部中断服务函数的时候使用中断级任务调度。

2.任务调度点

说到调度,那我们就不得不去知道怎么样才能产生调度,下面是UCOSIII中的任务调度点,还挺多的,简单有个概念就好。

  • 释放信号量或者发送消息,也可通过配置相应的参数不发生任务调度。
  • 使用延时函数OSTimeDly()或者OSTimeDlyHMSM()。
  • 任务等待的事情还没发生(等待信号量,消息队列等)。
  • 任务取消等待。
  • 创建任务。
  • 删除任务。
  • 删除一个内核对象。
  • 任务改变自身的优先级或者其他任务的优先级。
  • 任务通过调用OSTaskSuspend()将自身挂起。
  • 任务解挂某个挂起的任务。
  • 退出所有的嵌套中断。
  • 通过OSSchedUnlock()给调度器解锁。
  • 任务调用OSSchedRoundRobinYield()放弃其执行时间片。
  • 用户调用OSSched()。

3.调度器上锁和解锁

有时候我们并不希望发生任务调度,因为始终有一些代码的执行过程是不能被打断的。
此时我们就可以使用函数OSSchedLock()对调度器加锁。
恢复任务调度的时候就可以使用函数OSSchedUnlock()给已经上锁的任务调度器解锁。

4.时间片轮转调度

UCOSIII允许一个优先级下有多个任务,每个任务可以执行指定的时间(时间片),然后轮到下一个任务,这个过程就是时间片轮转调度,当一个任务不想在运行的时候就可以放弃其时间片。 时间片轮转调度器为:OS_SchedRoundRobin()。

  • 时间片轮转调度示例:
    在这里插入图片描述
    在这里插入图片描述

四、UCOSIII任务切换

什么是任务切换?

当UCOSIII需要切换到另外一个任务时,它将保存当前任务的现场到当前任务的堆栈中,主要是CPU寄存器值,然后恢复新的现场并且执行新的任务,这个过程就是任务切换。任务的调度其实也是一种任务切换。

  • 任务切换分为两种:任务级切换和中断级切换。
    • 任务级切换函数为:OSCtxSw()。
    • 中断级切换函数为:OSIntCtxSw()。

总结

UCOSIII的函数还是很多的,理论不懂没关系,我们先跟它混个眼熟,学会怎么去用,再去深入的学习怎么去用好它。下一篇将对UCOSIII进行一个移植。

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号