UCOSIII学习笔记

1.概念:

        UCOS是Micrium公司出品的RTOS类实时操作系统,UCOS目前有两个版本:UCOSII和UCOSIII。 UCOSIII是一个可裁剪、可剥夺型的多任务内核,而且没有任务数限制。UCOSIII提供了实时操作系统所需的所有功能,包括资源管理、同步、任务通信等。

2.任务管理:

2.1滴答定时器

     定时器来产生“滴答”中断来作为系统时基,SysTick有4个控制寄存器;

UCOSIII学习笔记_第1张图片

2.2任务

   在UCOSIII中任务就是程序实体,UCOSIII能够管理和调度这些小任务(程序)。    

   UCOSIII中的任务由三部分组成:任务堆栈、任务控制块和任务函数。    

    任务堆栈:上下文切换的时候用来保存任务的工作环境,就是STM32的内部寄存器值。    

    任务控制块:任务控制块用来记录任务的各个属性。    

   任务函数:由用户编写的任务处理代码,是实实在在干活的。一般写法如下

void XXX_task(void *p_arg)
   {
       while(1)
       {
        。。。。。//任务处理过程
        }
    }

任务的参数是一个void类型的,这么做的目的是可以可以传递不同类型的数据甚至是函数。任务函数其实就是一个C语言的函数,但是在使用UCOIII的情况下这个函数不能有用户自行调用,任务函数何时执行执行,何时停止完全有操作系统来控制。

2.3UCOSIII系统任务

UCOSIII默认有5个系统任务:    

1、空闲任务:UCOSIII创建的第一个任务,UCOSIII必须创建的任务,此任务有UCOSIII自动创建,不需要用户手动创建。    

2、时钟节拍任务:此任务也是必须创建的任务。    

3、统计任务:可选任务,用来统计CPU使用率和各个任务的堆栈使用量。此任务是可选任务,由宏OS_CFG_STAT_TASK_EN控制是否使用此任务。    

4、定时任务:用来向用户提供定时服务,也是可选任务,由宏OS_CFG_TMR_EN控制是否使用此任务。    

5、中断服务管理任务:可选任务,由宏OS_CFG_ISR_POST_DEFERRED_EN控制是否使用此任务。

任务状态:

从用户的角度看,UCOSIII的任务一共有5种状态:    

1、休眠态:任务已经在CPU的flash中了,但是还不受UCOSIII管理。    

2、就绪态:系统为任务分配了任务控制块,并且任务已经在就绪表中登记,这时这个任务就具有了运行的条件,此时任务的状态就是就绪态。    

3、运行态:任务获得CPU的使用权,正在运行。    

4、等待态:正在运行的任务需要等待一段时间,或者等待某个事件,这个任务就进入了等待态,此时系统就会把CPU使用权转交给别的任务。    

5、中断服务态:当发送中断,当前正在运行的任务会被挂起,CPU转而去执行中断服务函数,此时任务的任务状态叫做中断服务态。

3.UCOSIII任务堆栈

任务堆栈用来切换任务和调用其他函数时保存现场(现场就是CPU的内部各个寄存器),因此每个任务都应该有自己的堆栈。

任务堆栈的创建:

#define START_STK_SIZE 		512	//堆栈大小
CPU_STK START_TASK_STK[START_STK_SIZE];	//定义一个数组来作为任务堆栈

 CPU_STK为CPU_INT32U类型,也就是unsigned int类型,为4字节的,那么任务堆栈START_TASK_STK的大小就为:512 X 4=2048字节!

UCOSIII任务控制块:

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

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

OS_TCB为一个结构体,描述了任务控制块,任务控制块中的成员变量用户不能直接访问,更不可能改变他们。

UCOSIII任务就绪表:存放UCOSIII中已经就绪的任务。

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

函数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);
}

就绪表: UCOSIII中就绪表由2部分组成:    

1、优先级位映射表OSPrioTbl[]:用来记录哪个优先级下有任务就绪。    

2、就绪任务列表OSRdyList[]:用来记录每一个优先级下所有就绪的任务。

 同一优先级下如果有多个 任务的话最先运行的永远是 HeadPtr所指向的任务!

UCOSIII学习笔记_第2张图片

先执行1,后来1到最尾端,顺序变为2、3、1,开始执行2; 轮流执行。

4.

4.1UCOSIII任务调度:任务调度就是中止当前正在运行的任务转而去执行其他的任务。

UCOSIII是可剥夺型内核,因此当一个高优先级的任务准备就绪,并且此时发生了任务调度,那么这个高优先级的任务就会获得CPU的使用权!        

UCOSIII中的任务调度是由任务调度器来完成的,任务调度器有2种:任务级调度器和中断级调度器。    

任务级调度器为函数OSSched()。    

中断级调度器为函数OSIntExit(),当退出外部中断服务函数的时候使用中断级任务调度。

4.2UCOSIII任务切换

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

任务切换分为两种:任务级切换和中断级切换。

任务级切换函数为:OSCtxSw()。

中断级切换函数为:OSIntCtxSw()。

5.任务相关API函数(应用程序编程接口)

5.1任务创建和删除:UCOSIII是多任务系统,创建任务就是将任务堆栈、任务控制块、任务函数等联系在一起,并初始化任务控制块相应字段。

OSTaskCreate()函数创建任务;OSTaskDel()删除任务;

void  OSTaskDel (OS_TCB  *p_tcb, OS_ERR  *p_err)

OSTaskDel((OS_TCB*)0,&err),当传递给函数OSTaskDel()的参数p_tcb的值为0时,表示删除掉任务自身

5.2任务挂起和恢复

        当我们想暂停某个任务,但是又不想删除掉这个任务的时候就可以使用函数OSTaskSuspend()来将这个任务挂起,函数原型如下:void   OSTaskSuspend ( OS_TCB  *p_tcb,//*p_tcb指向需要挂起任务的的OS_TCB

                                               OS_ERR  *p_err)//指向一个变量,用来保存该函数的错误码

  恢复:     OSTaskResume

( OS_TCB  *p_tcb,//*p_tcb指向需要挂起任务的的OS_TCB

                                               OS_ERR  *p_err)//指向一个变量,用来保存该函数的错误码

5.3UCOSIII时间片轮转调度

处于同一优先级的多个任务,采用时间片轮转调度来轮流执行;

OSSchedRoundRobinCfg()(CPU_BOOLEAN   en,//打开/关闭时间片轮转调度机制,

                                    OS_TICK       dflt_time_quanta, //设置默认时间片长度,n=dflt_time_quanta;n*5ms;若n=0,默认为100ms. 

                                       OS_ERR       *p_err)调用本函数后返回的错误码

 

OSSchedRoundRobinYield (OS_ERR  *p_err)放弃本次时间片函数

 6.UCOSIII中断和时间管理

stm32支持中断,中断是一个硬件机制,主要用来通知CPU一个异步事件发生,这样CPU就会将当前CPU寄存器的值存入栈,进而去处理中断服务函数。

6.1

 OSIntEnter();  OSIntExit();进入和退出中断服务函数。

OSIntNestingCtr来记录中断嵌套次数,UCOSIII最多支持250级的中断嵌套。退出中断服务函数时要调用函数OSIntExit()。

6.2UCOSIII临界段代码保护

 临界段代码也叫做临界区,是指那些必须完整连续运行,不可被打断的代码段。当访问这些临界段代码的时候需要对这些临界段代码进行保护。    

当宏OS_CFG_ISR_POST_DEFERRED_EN为0时,UCOSIII使用关中断的方式来保护临界段代码,当设置为1的时候就会采用给调度器上锁的方式来保护临界段代码。

UCOSIII定义了一个进入临界段代码的宏:OS_CRITICAL_ENTER(),定义了两个退出临界段代码的宏:OS_CRITICAL_EXIT和OS_CRITICAL_EXIT_NO_SCHED()。

6.3任务延时

延时:

延时函数有两种,OSTimeDly()和OSTimeDlyHMSM()。

取消:

延时任务任务可通过在其他任务中调用函数OSTimeDlyResume()取消延时而进入就绪状态,此函数最后会引发一次任务调度。

获取和设置系统时间:

UCOSIII定义了一个CPU_INT32U类型的全局变量OSTickCtr来记录系统时钟节拍数,在调用OSInit()时被初始化为0,以后每发生1个时钟节拍,OSTickCtr加1。  

OSTimeSet()允许用户改变当前时钟节拍计数器的值,慎用!!!!!  

OSTimeGet()用来获取动迁时钟节拍计数器的值。

7.UCOSIII软件定时器

       单片机中使用定时器来进行定时任务属于硬件定时。

模式:单词定时器、无初始延时周期模式、有初始延时周期模式

8.UCOSIII信号量和互斥信号量

8.1.UCOSIII信号量

信号量像是一种上锁机制,代码必须获得对应的钥匙才能继续执行,一旦获得了钥匙,也就意味着该任务具有进入被锁部分代码的权限。一旦执行至被锁代码段,则任务一直等待,直到对应被锁部分代码的钥匙被再次释放才能继续执行。

信号量用于控制对共享资源的保护,但是现在基本用来做任务同步用。

UCOSIII学习笔记_第3张图片

 8.2互斥信号量:

为了避免优先级反转这个问题,UCOSIII支持一种特殊的二进制信号量:互斥信号量, 用它可以解决优先级反转问题。

UCOSIII学习笔记_第4张图片

8.3UCOSIII任务内嵌信号量 

在UCOSIII中每个任务都有自己的内嵌的信号量,这种功能不仅能够简化代码,而且比使用独立的信号量更有效。任务信号量是直接内嵌在UCOSIII中的,任务信号量相关代码在os_task.c中。

UCOSIII学习笔记_第5张图片

9.UCOSIII消息传递

    信号量用于多个任务同时访问同一公共资源,即任务与资源之间的通道;

    消息用于任务互相之间的通信和交流;任务间的消息传递可以通过2种途径:一是通过全局变量,二是通过发布消息。        

使用全局变量的时候每 个任务或者中断服务程序都必须保证其对全局变量的独占访问。

    消息包含一下几个部分:指向数据的指针,数据的长度和记录消息发布时刻的 时间戳,指针指向的可以是一块数据区域或者甚至是一个函数。

消息队列中有一个列表,记录了所有正在等待消息的任务队列;

 

 

 

你可能感兴趣的:(UCOSIII学习笔记)