ucos-ii 的任务调度原理和实现

2023-05-16

ucosii 任务调度和原理

1、ucos-ii 任务创建与任务调度

1.1、任务的创建

当你调用 OSTaskCreate( ) 进行任务的创建的时候,会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块(OS_TCB)等的操作;

if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority  */
        OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ...  */
                                             /* ... the same thing until task is created.              */
        OS_EXIT_CRITICAL();
        psp = OSTaskStkInit(task, p_arg, ptos, 0u);             /* Initialize the task's stack         */
        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);
        if (err == OS_ERR_NONE) {
            if (OSRunning == OS_TRUE) {      /* Find highest priority task if multitasking has started */
                OS_Sched();
            }
        } else {
            OS_ENTER_CRITICAL();
            OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others                 */
            OS_EXIT_CRITICAL();
        }
        return (err);
    }
注意:ucosii不支持两个及以上相同的任务优先级的任务,ucosiii支持时间片轮转。

ucosii 的任务控制块是任务中很重要,它记录了任务的信息,包括优先级、延时时间、状态等信息。控制块定义如下:

typedef struct os_tcb {
    OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack                         */

#if OS_TASK_CREATE_EXT_EN > 0u
    void            *OSTCBExtPtr;           /* Pointer to user definable data for TCB extension        */
    OS_STK          *OSTCBStkBottom;        /* Pointer to bottom of stack                              */
    INT32U           OSTCBStkSize;          /* Size of task stack (in number of stack elements)        */
    INT16U           OSTCBOpt;              /* Task options as passed by OSTaskCreateExt()             */
    INT16U           OSTCBId;               /* Task ID (0..65535)                                      */
#endif

    struct os_tcb   *OSTCBNext;             /* Pointer to next     TCB in the TCB list                 */
    struct os_tcb   *OSTCBPrev;             /* Pointer to previous TCB in the TCB list                 */

#if (OS_EVENT_EN)
    OS_EVENT        *OSTCBEventPtr;         /* Pointer to          event control block                 */
#endif

#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)
    OS_EVENT       **OSTCBEventMultiPtr;    /* Pointer to multiple event control blocks                */
#endif

#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
    void            *OSTCBMsg;              /* Message received from OSMboxPost() or OSQPost()         */
#endif

#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
#if OS_TASK_DEL_EN > 0u
    OS_FLAG_NODE    *OSTCBFlagNode;         /* Pointer to event flag node                              */
#endif
    OS_FLAGS         OSTCBFlagsRdy;         /* Event flags that made task ready to run                 */
#endif

    INT32U           OSTCBDly;              /* Nbr ticks to delay task or, timeout waiting for event   */
    INT8U            OSTCBStat;             /* Task      status                                        */
    INT8U            OSTCBStatPend;         /* Task PEND status                                        */
    INT8U            OSTCBPrio;             /* Task priority (0 == highest)                            */

    INT8U            OSTCBX;                /* Bit position in group  corresponding to task priority   */
    INT8U            OSTCBY;                /* Index into ready table corresponding to task priority   */
    OS_PRIO          OSTCBBitX;             /* Bit mask to access bit position in ready table          */
    OS_PRIO          OSTCBBitY;             /* Bit mask to access bit position in ready group          */

#if OS_TASK_DEL_EN > 0u
    INT8U            OSTCBDelReq;           /* Indicates whether a task needs to delete itself         */
#endif

#if OS_TASK_PROFILE_EN > 0u
    INT32U           OSTCBCtxSwCtr;         /* Number of time the task was switched in                 */
    INT32U           OSTCBCyclesTot;        /* Total number of clock cycles the task has been running  */
    INT32U           OSTCBCyclesStart;      /* Snapshot of cycle counter at start of task resumption   */
    OS_STK          *OSTCBStkBase;          /* Pointer to the beginning of the task stack              */
    INT32U           OSTCBStkUsed;          /* Number of bytes used from the stack                     */
#endif

#if OS_TASK_NAME_EN > 0u
    INT8U           *OSTCBTaskName;
#endif

#if OS_TASK_REG_TBL_SIZE > 0u
    INT32U           OSTCBRegTbl[OS_TASK_REG_TBL_SIZE];
#endif
} OS_TCB;

2、任务调度实现

2.1、将任务优先级进行分组

因为ucosii最大优先级数量为64个,所以可以分成8组,每组8个优先级。

当一个任务被创建成功之后,它的组号由优先级的高三位决定(bit5 bit4 bit3),它在组内的编号由优先级的低三位决定(bit2 bit1 bit0),如下:

#if OS_LOWEST_PRIO <= 63u                                         /* Pre-compute X, Y                  */
        ptcb->OSTCBY             = (INT8U)(prio >> 3u);    // 组
        ptcb->OSTCBX             = (INT8U)(prio & 0x07u);  // 组内编号
#else          

2.2、任务就绪表

ucosii对任务优先级的调度管理是通过查询任务就绪表进行的。任务就绪表里面保存着当前所有任务的就绪状态,如下:

OSRdyTbl[8]

说明:
1)它是uint8的数据类型。它的长度是8,每一个元素代表一个组,
比如 OSRdyTbl[0]代表第0组, OSRdyTbl[1]代表第1组,OSRdyTbl[2]代表第2组……以此类推。

2)每一个元素中的每一个位(bit)代表组内的任务的就绪状态(1为就绪,0为未就绪)。

打个比方:

1)当优先级为12 的任务就绪时,那么对应的OSRdyTbl[1]的第4位bit,绝对等于1
当整个系统中,当只有优先级为12的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[1] 绝对等于0x10

2)当优先级为01的任务就绪时,那么对应的OSRdyTbl[0]的第0位bit以及第1位bit,都绝对等于1
当整个系统中,当只有优先级为01的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[0] 绝对等于0x03

2.3、任务释放CPU使用权

当任务中调用 OSTimeDly( ) 时,会让任务进入休眠的状态,交出CPU的执行权给到其他就绪任务去执行,这个过程就发生了任务的切换。

简单而言就是会把任务就绪表 OSRdyTbl 中对应的任务优先级在组内的编号状态改变,从而使任务自身进入休眠状态。代码如下:

if (ticks > 0u) {                            /* 0 means no delay!                                  */
        OS_ENTER_CRITICAL();
        y            =  OSTCBCur->OSTCBY;        /* Delay current task                                 */
        OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
        if (OSRdyTbl[y] == 0u) {
            OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBDly = ticks;              /* Load ticks in TCB                                  */
        OS_EXIT_CRITICAL();
        OS_Sched();                              /* Find next task to run!                             */
    }

在上面的代码中发现了一个东西:OSRdyGrp。这个有什么用呢?

OSRdyGrp:管理任务就绪组的

OSRdyGrp是INT8U类型的,它每一个bit代表一个组,只要这个组内有任何一个任务就绪了,那对应的这个bit就会被设置为1,表示这个组内目前有就绪的任务。否者对应的位为0

举个例子,如下:

1)系统中只有任务0就绪了,那么OSRdyGrp 便等于 0x01(二进制00000001)。
2)系统中有任务0和任务63都就绪了,那么OSRdyGrp 便等于 0x81(二进制10000001)

2.4、任务实现调度切换操作

发生一次任务调度是通过 OS_Sched() 进行的。源码如下:

void  OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0u;
#endif

    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0u) {                          /* Schedule only if all ISRs done and ...       */
        if (OSLockNesting == 0u) {                     /* ... scheduler is not locked                  */
            OS_SchedNew();
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
#if OS_TASK_PROFILE_EN > 0u
                OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
#endif
                OSCtxSwCtr++;                          /* Increment context switch counter             */
                OS_TASK_SW();                          /* Perform a context switch                     */
            }
        }
    }
    OS_EXIT_CRITICAL();
}

这里的过程如下:

(1)先通过 OS_SchedNew() 找到当前处于就绪状态的最高优先级的任务,如下:

y             = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);

(2)然后通过 OS_TASK_SW() 进行任务切换,它的过程如下:

1)OS_TASK_SW 只是一个宏,它实际替换的是 OSCtxSw()
#define  OS_TASK_SW()         OSCtxSw()

2OSCtxSw()是由汇编实现的
OSCtxSw
		PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL  	;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
		POP     {R4, R5}
        BX      LR

就这样,上下文就完成了一次切换。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ucos-ii 的任务调度原理和实现 的相关文章

  • 我发现ucos里面也是任务,任务控制块,消息队列,信号量,事件 。这些概念感觉和freertos一模一样啊

    我发现ucos里面也是任务 xff0c 任务控制块 xff0c 消息队列 xff0c 信号量 xff0c 事件 这些概念感觉和freertos一模一样啊 xff0c 感觉大家就是抄来抄去 xff1f 应该这些操作系统原理都差不多 xff0c
  • UCOS的事件有:信号量,消息邮箱,消息队列,信号量集

  • ucos-ii 的任务调度原理和实现

    ucosii 任务调度和原理 1 ucos ii 任务创建与任务调度 1 1 任务的创建 当你调用 OSTaskCreate 进行任务的创建的时候 xff0c 会初始化任务的堆栈 保存cpu的寄存器 创建任务的控制块 xff08 OS TC
  • UCOSⅢ简介

    UCOS 简介 简述一 裸机系统与多任务系统二 UCOS 的重要特性三 UCOS 的组成 简述 UCOS xff08 UCOS的第三代内核 xff09 是一个可裁剪 可固化 可剥夺的多任务系统 xff0c 具有高度可移植性 xff0c 没有
  • uCOS上下文切换,PendSV中断函数

    摘自 xff1a http www stmcu org module forum thread 384142 1 1 html 介绍一 xff1a 移植详解1和2中主要讲了移植需要用到的基础知识 xff0c 本文则对具体的移植过程进行介绍
  • 白话----之UCOS 信号量和邮箱

    总体理解 xff1a 两个任务需要共同访问一个共同的资源 xff0c 来切换或跳到不同的动作执行 这就产生信号量 两个任务 需要根据不同的按键选择 xff0c 来执行不同的动作 xff0c 产生邮箱 信号量和邮箱 我通过一个例子来学习的 希
  • 推荐ucos-II 3本参考书 经典

    在这里给大家推荐三本学习ucos的必看书籍 1 xff08 比较难买 xff09 嵌入式实时操作系统uc os II教程 西安电子科技大学出版 这本书对UCOS的源代码分析的非常清楚 比作者原著 在某种程度上要好 xff0c 这本书对关键的
  • 一步一步教你使用uCOS-II

    第一篇 UCOS介绍 第一篇 UCOS介绍 这个大家都知道 呵呵 考虑到咱们学习的完整性还是在这里唠叨一下 让大家再熟悉一下 高手们忍耐一下吧 xff01 uC OS II Micro Control Operation System Tw
  • STM32之RTOS:uCOS和FreeRTOS

    RTOS全称是 Real Time Operating System xff0c 中文就是实时操作系统 RTOS是指一类系统 xff0c 如 uC OS xff0c FreeRTOS xff0c RTX xff0c RT Thread 等
  • freeRTOS与ucos II区别

    freeRTOS比uCOS II优胜的地方 1 内核ROM和耗费RAM都比uCOS 小 xff0c 特别是RAM 这在单片机里面是稀缺资源 xff0c UCOS至少要5K以上 xff0c 而freeOS用2 3K也可以跑的很好 xff1b
  • ucos源码阅读3——信号量,互斥信号量(未完待续)

    ucos源码阅读3 信号量 xff0c 互斥信号量 事件控制块ECBInitEventList xff08 xff09 EventWaitListInit xff08 xff09 EventTaskRdy xff08 xff09 Event
  • UCOS II 中信号量的使用

    UCOS II 中信号量的使用 UCOS II 中信号量的使用1 声明信号量2 创建信号量3 请求信号量4 发送信号量5 删除信号量 UCOS II 中信号量的使用 1 声明信号量 例如 xff1a OS EVENT Fun semp 声明
  • UCOS学习(七)——信号量详解

    信号量 信号量简介信号量保护共享资源举个栗子 xff1a 如果不使用信号量信号量解决公共资源问题创建信号量 xff1a 信号量实现任务同步总结 信号量简介 信号量像是一种上锁机制 xff0c 代码必须获得对应的钥匙才能继续执行 xff0c
  • UCOS消息队列的使用【转】

    UCOS消息队列的使用 转 收藏 消息队列的使用 1 需在以下文件中配置如下内容 OS CFG H OS MAX QS N 你需要的值 根据需要自己配置 define OS Q EN 1 Enable 1 or Disable 0 code
  • 【STM32】入门(十一):初识uCOS-III

    STM32 STM32单片机总目录 1 轮询 中断 多任务对比 2 什么是任务 如果您学过linux xff0c 那么任务可以理解为线程 在代码中的体现就是线程函数 xff0c 一个函数中有个无限循环函数 xff0c 并且永不返回 例如 x
  • (转)ucos的事件 任务的通讯和同步 信号量 互斥量 消息邮箱 消息队列

    这会想了想 xff0c 在复习资料后 xff0c 最后再做个核心代码分析 ucos中使用信号量 消息邮箱 消息队列 xff0c 这些数据结构来作为通信中间媒介 这些数据结构会影响任务的程序流程 xff0c 因此也叫做事件 一 信号量 是进行
  • UCOS II两个任务的模板

    芯片lm3s9b92 include lt includes h gt include 34 utils uartstdio h 34 Application tasks 优先级 define TASK2 PRIO 11 define ta
  • cpu.h-栈的宏定义-满减栈

    常常两两相对的东西 整一起后有点记不住 就写下来 cpu h中有宏定义使用哪种栈 define OS STK GROWTH 1 Stack grows from HIGH to LOW memory on ARM 栈的四种 满栈 满 字表示
  • UCOS2的文件目录

    想着闲着也是闲着 把之前学习ucos2源码的笔记整理一下 复盘一次 总结内容将其写为博客作为学习的输出 一 为什么要学RTOS或者IOTOS 我在大一时 开始进入实验室接触单片机 摸爬滚打的参加了几次比赛 也因此入了嵌入式的坑 大三时开始思
  • ucos-ii嵌入式操作系统任务调度(一)----任务调度的过程及实现原理

    先给自己打个广告 本人的微信公众号正式上线了 搜索 张笑生的地盘 主要关注嵌入式软件开发 股票基金定投 足球等等 希望大家多多关注 有问题可以直接留言给我 一定尽心尽力回答大家的问题 二维码如下 一 概念 在单片机裸机程序中 我们以函数为最

随机推荐