UCOS源码阅读笔记

UCOS

​ 本笔记较为详细地记录了UCOSII操作系统实现的大体流程,因为为笔者的学习笔记,故不推荐直接零基础看。推荐对操作系统有大体了解后,并希望更加深入了解时,再翻阅本笔记。

​ 使用操作系统可以更好地实现任务间的协调,虽然运行之会消耗一部分CPU资源,但可以带来更高效的任务协调和同步,从另一层面减小了资源浪费。也可以提供更清晰的程序框架,方便协作交流。

​ 版本:UCOSII V2.91

  • II和III的部分区别

    • II中各种操作的参数与III有很多不同,III中要复杂很多。
    • II中任务优先级即为任务ID,同优先级只能存在一个任务;III中同优先级可设置多个任务,初始化每个任务时可为其分配时间片,支持时间片轮转调度同优先级任务。
    • II中分为消息邮箱和消息队列,而III中只有消息队列。
    • III中每个任务都有内嵌信号量和内嵌消息队列。
    • II中所有通讯都基于事件控制块ECB,创建和操作都是基于ECB;而III中取消了这一设计,信号量是信号量,消息队列是消息队列,创建和操作时都直接使用各自的数据结构,并没有进行统一管理。
  • UCOS中的任务堆栈

    • 任务堆栈是UCOS实现任务调度的关键,其本体是ram中栈区外静态分配的一块数组,实现与内存栈相似的功能。即像内存中的栈区一样存储运行时的局部变量,并在任务调度发生时将CPU寄存器值入栈,保存当前任务的现场,在重获执行权之后恢复现场。
    • 其大小应根据任务需要使用的局部变量,和函数的嵌套调用导致的所需栈空间大小进行分配。
  • UCOS任务调度

    • 任务调度通过任务级调度OS_Sched()和中断级调度OSIntExit()中调用OS_TASK_SW()实现的。
    • 任务调度过程的本质大概可以理解为:1.查询任务就绪表中最高优先级的任务。2.保存当前执行任务的现场,恢复目标任务的现场至CPU。 3.若为UCOS-III则再多一个时间片轮转的逻辑。
    • 每次退出硬件中断时,ucos都会进行一次任务切换,其系统心跳节拍在stm32上是通过滴答计时器来实现的,周期由滴答定时器选择的时钟和滴答计时器的重装载值决定。在SysTick_Handler的硬件中断处理时会不断进行任务切换。

UCOS源码阅读笔记

下文代码源自ucosii-V2.91,根据个人理解进行了部分删减,适合用于理解其基本功能的运行逻辑。

头文件
/****************************************************************************************
*						ucos_ii.h头文件部分,仅记录了一些重要部分,并不完全 
****************************************************************************************/
宏定义部分
/***** 宏定义部分 *****/
// MISCELLANEOUS 杂毛宏定义
#define  OS_TASK_STAT_PRIO (OS_LOWEST_PRIO - 1u)  		/* 统计任务优先级,倒数第二 */
#define  OS_TASK_IDLE_PRIO (OS_LOWEST_PRIO)  	  		/* 空闲任务优先级,优先级最低 */
#define  OS_EVENT_TBL_SIZE ((OS_LOWEST_PRIO) / 8u + 1u) /* 事件表大小 */
#define  OS_RDY_TBL_SIZE   ((OS_LOWEST_PRIO) / 8u + 1u) /* 就绪任务表大小 */
#define  OS_TCB_RESERVED        ((OS_TCB *)1)           /* 用于表示某优先级任务已被留存 */

// TASK STATUS 任务状态宏定义
#define  OS_STAT_RDY       0x00u  /* 就绪 */
#define  OS_STAT_SEM       0x01u  /* 等待信号量 */
#define  OS_STAT_MBOX      0x02u  /* 等待消息邮箱 */
#define  OS_STAT_Q         0x04u  /* 等待消息队列 */
#define  OS_STAT_SUSPEND   0x08u  /* 任务挂起 */
#define  OS_STAT_MUTEX     0x10u  /* 等待互斥信号量 */
#define  OS_STAT_FLAG      0x20u  /* 等待事件标志组 */
#define  OS_STAT_MULTI     0x80u  /* Pending on multiple events             */
 
#define  OS_STAT_PEND_ANY  (OS_STAT_SEM | OS_STAT_MBOX | OS_STAT_Q | OS_STAT_MUTEX | OS_STAT_FLAG)

// TASK PEND STATUS 任务等待状态标志
#define  OS_STAT_PEND_OK                0u  /* 正常等待完成 */
#define  OS_STAT_PEND_TO                1u  /* 等待超时标志 */
#define  OS_STAT_PEND_ABORT             2u  /* 等待放弃标志 */

// OS_EVENT types 事件种类
#define  OS_EVENT_TYPE_UNUSED           0u  /* 未分配 */
#define  OS_EVENT_TYPE_MBOX             1u  /* 消息邮箱 */
#define  OS_EVENT_TYPE_Q                2u  /* 消息队列 */
#define  OS_EVENT_TYPE_SEM              3u  /* 信号量 */
#define  OS_EVENT_TYPE_MUTEX            4u  /* 互斥信号量 */
#define  OS_EVENT_TYPE_FLAG             5u  /* 事件标志组 */

// EVENT FLAGS 事件标志组宏定义
#define  OS_FLAG_WAIT_CLR_ALL           0u  /* 触发逻辑为标志组全为0 */
#define  OS_FLAG_WAIT_CLR_AND           0u

#define  OS_FLAG_WAIT_CLR_ANY           1u  /* 触发逻辑为标志组任意一个为0 */
#define  OS_FLAG_WAIT_CLR_OR            1u

#define  OS_FLAG_WAIT_SET_ALL           2u  /* 触发逻辑为标志组全为1 */
#define  OS_FLAG_WAIT_SET_AND           2u

#define  OS_FLAG_WAIT_SET_ANY           3u  /* 触发逻辑为标志组任意一个为1 */
#define  OS_FLAG_WAIT_SET_OR            3u

#define  OS_FLAG_CONSUME             0x80u  /* 满足条件后是否清除flag */

#define  OS_FLAG_CLR                    0u
#define  OS_FLAG_SET                    1u

// 事件删除函数可选项
#define  OS_DEL_NO_PEND                 0u
#define  OS_DEL_ALWAYS                  1u

// OSXXXPend() OPTIONS 等待函数可选项
#define  OS_PEND_OPT_NONE               0u  /* 使在等待该事件的最高优先级的任务放弃等待*/
#define  OS_PEND_OPT_BROADCAST          1u  /* Abort时使用,取消所有等待该事件的任务 */

// OSXXXPostOpt() OPTIONS 发送函数可选项
#define  OS_POST_OPT_NONE            0x00u  /* 默认 */
#define  OS_POST_OPT_BROADCAST       0x01u  /* 仅在邮箱和消息队列使用,同时向所有等待任务发送 */
#define  OS_POST_OPT_FRONT           0x02u  /* 仅在消息队列使用,发到消息队列最前 */
#define  OS_POST_OPT_NO_SCHED        0x04u  /* 仅在邮箱和消息队列使用,不触发任务调度 */

// TIMER OPTIONS (软件定时器相关可选项)
#define  OS_TMR_OPT_NONE                0u  /* 默认 */

#define  OS_TMR_OPT_ONE_SHOT            1u  /* 单次计时 */
#define  OS_TMR_OPT_PERIODIC            2u  /* 周期性重置 */
    
// TIMER STATES 软件定时器状态
#define  OS_TMR_STATE_UNUSED            0u  /* 未被分配 */
#define  OS_TMR_STATE_STOPPED           1u  /* 创建了但未被加入轮辐 */
#define  OS_TMR_STATE_COMPLETED         2u  /* 单次计时完成 */
#define  OS_TMR_STATE_RUNNING           3u  /* 计时中 */

// ERROR CODES 错误码
......
数据结构部分
/***** 数据结构部分 *****/
  // EVENT CONTROL BLOCK 事件控制块
  typedef struct os_event {
   
      INT8U    OSEventType;                    /* 事件种类 */
      /* 可以在各种地方使用,FreeList指向下个ECB、传消息时指向消息、在Mutex中指向占有信号量的TCB */
      void    *OSEventPtr;                     
      INT16U   OSEventCnt;                     /* 信号量计数(仅信号量有用) */
      /* 等待该事件的任务优先级组 OS_PRIO根据优先级总数选择为u8或u16*/
      OS_PRIO  OSEventGrp;                   
      OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];/* 等待该事件的任务优先级表 */
#if OS_EVENT_NAME_EN > 0u
      INT8U   *OSEventName;                    /* 事件名 */
  #endif
  } OS_EVENT;

  // EVENT FLAGS CONTROL BLOCK 事件标志组
  typedef struct os_flag_grp {
   
      INT8U         OSFlagType;    /* 等价OSEventType,只能为OS_EVENT_TYPE_FLAG */
      void         *OSFlagWaitList;/* 等待该事件标志组的事件标志组任务节点链表头 */
      OS_FLAGS      OSFlagFlags;   /* 根据OS_FLAGS_NBITS设置为8/16/32 */
#if OS_FLAG_NAME_EN > 0u
      INT8U        *OSFlagName;    /* 事件标志组名 */
  #endif
  } OS_FLAG_GRP;

  // 事件标志组等待任务节点
  typedef struct os_flag_node {
   
      void         *OSFlagNodeNext;           /* 指向下个节点 */
      void         *OSFlagNodePrev;           /* 指向前一个节点 */
      void         *OSFlagNodeTCB;            /* 指向当前节点对应的任务控制块 */
      void         *OSFlagNodeFlagGrp;        /* 指回OS_FLAG_GRP */
      OS_FLAGS      OSFlagNodeFlags;          /* 该任务实际要等待哪些标志位 */
      INT8U         OSFlagNodeWaitType;       /* 触发逻辑全0/任意0/全1/任意1 */
  } OS_FLAG_NODE;
  #endif

  // MESSAGE MAILBOX DATA 消息邮箱
  typedef struct os_mbox_data {
   
   	  void   *OSMsg;                         /* 指向对应消息 */
      OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* 等待该事件的任务优先级表 */
      OS_PRIO OSEventGrp;                    /* 等待该事件的任务优先级组 */
  } OS_MBOX_DATA;

  // MEMORY PARTITION DATA STRUCTURES 内存分配数据结构
  typedef struct os_mem {
                      /* 内存控制块 */
      void   *OSMemAddr;                    /* 对应内存区头地址 */
      void   *OSMemFreeList;                /* 空闲内存块链表头 */
      INT32U  OSMemBlkSize;                 /* 单个块内存大小(byte) */
      INT32U  OSMemNBlks;                   /* 该区中的内存块数目 */
      INT32U  OSMemNFree;                   /* 该区中空闲内存块数目 */
  #if OS_MEM_NAME_EN > 0u
      INT8U  *OSMemName;                    /* 内存区名 */
  #endif
  } OS_MEM;
  // 另有一个结构基本一致的 OS_MEM_DATA, 其作用为作为OSMemQuery函数的输入,之所以多此一举是尽量防止用户直接操作系统内核数据结构OS_MEM
  // UCOS提供的动态内存管理机制并不好用,创建内存区时所有内存块大小相同,取用时一次只能取用一个内存块。

  // MUTUAL EXCLUSION SEMAPHORE DATA 互斥信号量
  typedef struct os_mutex_data {
   
      OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待该事件的任务优先级表 */
      OS_PRIO OSEventGrp;                     /* 等待该事件的任务优先级组 */
      BOOLEAN OSValue;                        /* 互斥信号量值 */
      INT8U   OSOwnerPrio;                    /* 使用者优先级,无人使用则置为0xff */
      INT8U   OSMutexPIP;                     /* 优先级继承优先级,防止优先级反转 */
} OS_MUTEX_DATA;

  // MESSAGE QUEUE DATA 消息队列
  typedef struct os_q {
                      /* 消息队列控制块 */
      struct os_q   *OSQPtr;              /* 指向下一个消息队列控制块 */
      void         **OSQStart;            /* 循环队列起始地址 */
      void         **OSQEnd;              /* 循环队列结束地址 */
      void         **OSQIn;               /* 下个消息进入的地址 */
      void         **OSQOut;              /* 下个消息取出的地址 */
      INT16U         OSQSize;             /* 队列长度 */
      INT16U         OSQEntries;          /* 队列内消息总数 */
  } OS_Q;
  // 另有结构相近的 OS_Q_DATA, 其作用同OS_MEM_DATA
  
  // SEMAPHORE DATA 信号量DATA,作用同上
  typedef struct os_sem_data {
   
      INT16U  OSCnt;                          /* 信号量计数 */
      OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待该事件的任务优先级表 */
      OS_PRIO OSEventGrp;                     /* 等待该事件的任务优先级组 */
} OS_SEM_DATA;

  // TASK STACK DATA 任务堆栈
  typedef struct os_stk_data {
   
      INT32U  OSFree;                    /* 任务栈内空闲字节数 */
      INT32U  OSUsed;                    /* 任务栈内已使用字节数 */
} OS_STK_DATA;

  // TASK CONTROL BLOCK 任务控制块 只记录了部分基础成员
  typedef struct os_tcb {
   
      OS_STK          *OSTCBStkPtr;           /* 任务栈顶指针 */
      
      struct os_tcb   *OSTCBNext;             /* 双向链表下一个 */
      struct os_tcb   *OSTCBPrev;             /* 双向链表前一个 */
  
      OS_EVENT        *OSTCBEventPtr;	 	  /* 指向任务在等待的事件控制块 */
      void            *OSTCBMsg;			  /* 保存从邮箱或队列得到的消息 */  
      
      INT32U           OSTCBDly;              /* Delay的系统时钟次数,或等待事件的timeout */
      INT8U            OSTCBStat;             /* 任务状态 */
      INT8U            OSTCBStatPend;         /* 等待事件状态 */
      INT8U            OSTCBPrio;             /* 优先级 */
  
      INT8U            OSTCBX;                /* 就绪表中X轴实际数 */
      INT8U            OSTCBY;                /* 就绪表中Y轴实际数 */
      OS_PRIO          OSTCBBitX;             /* 就绪表中X轴字节表示 */
      OS_PRIO          OSTCBBitY;             /* 就绪表中Y轴字节表示 */
      /* 若prio=15=1111b, 则OSTCBY = prio>>3 = 1, OSTCBBitY = 1<<OSTCBY = 10b;
      OSTCBX = prio&0x07 = 7, OSTCBBitX = 1 << OSTCBX = 10000000b */
} OS_TCB;

  // TIMER DATA TYPES 软件定时器
  typedef  void (*OS_TMR_CALLBACK)(void *ptmr, void *parg);
  typedef  struct  os_tmr {
   
      INT8U            OSTmrType;        /* 仅可为OS_TMR_TYPE */
      OS_TMR_CALLBACK  OSTmrCallback;    /* 回调函数,宏定义如上 */
      void            *OSTmrCallbackArg; /* 回调函数传参 */
      void            *OSTmrNext;        /* 双向链表 */
      void            *OSTmrPrev;
      INT32U           OSTmrMatch;       /* OSTmrTime等于该值时认为计时结束 */
      INT32U           OSTmrDly;         /* 周期计时前的等待计数 */
      INT32U           OSTmrPeriod;      /* 计时周期 */
      INT8U            OSTmrOpt;         /* 定时器可选项,见OS_TMR_OPT_XXX */
      INT8U            OSTmrState;       /* 定时器状态:UNUSED/RUNNING/STOPPED */
  } OS_TMR;
  
  typedef  struct  os_tmr_wheel {
           /* 计时器轮,在大量计时器时可通过散列操作有效提高效率 */
      OS_TMR          *OSTmrFirst;       /* 该轮辐指向的第一个定时器OS_TMR */
      INT16U           OSTmrEntries;     /* 该轮辐上的计时器总数 */
} OS_TMR_WHEEL;
全局变量部分
/***** 全局变量部分,仅记录了部分重要变量 *****/
OS_EXT  INT8U   OSCPUUsage;    /* 统计任务计算的CPU占用率 */
OS_EXT  INT32U  OSIdleCtrMax;  /* 1s内空闲任务执行的最大次数 */
OS_EXT  INT32U  OSIdleCtrRun;  /* 当前1s内空闲任务执行的次数 */
OS_EXT  INT8U   OSIntNesting;  /* 中断嵌套层数 */
OS_EXT  INT8U   OSPrioCur;     /* 当前任务优先级 */
OS_EXT  INT8U   OSPrioHighRdy; /* 最高已就绪任务优先级 */
extern INT8U const OSUnMapTbl[256];         /* 用于优先级判断时的查表 */
OS_EXT  OS_PRIO OSRdyGrp;                   /* 任务就绪组,用于快速查找当前最高优先级任务 */
OS_EXT  OS_PRIO OSRdyTbl[OS_RDY_TBL_SIZE];  /* 任务就绪表,用于快速查找当前最高优先级任务 */
OS_EXT  BOOLEAN OSRunning;     /* 系统内核是否正常工作 */
OS_EXT  INT8U   OSTaskCtr;     /* 创建过的任务计数 */
OS_EXT  OS_TCB  *OSTCBCur;     /* 当前进行任务的TCB */
OS_EXT  OS_TCB  *OSTCBHighRdy; /* 当前就绪态最高优先级任务的TCB */
OS_EXT  OS_TCB  *OSTCBFreeList;/* 仍可使用的空闲TCB单向链表的链表头 */
OS_EXT  OS_TCB  *OSTCBList;    /* 已被使用的TCB双向链表的链表头,新任务向表头添加 */
OS_EXT  OS_TCB  *OSTCBPrioTbl[OS_LOWEST_PRIO + 1u]; /* 根据优先级存储的TCB指针数组,方便查找 */
OS_EXT  OS_TCB   OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];  /* 所有TCB本体实际存储的数据结构 */
// 其他诸如event,flag,Q,Tmr,Mem等都有类似*XXXFreeList和XXXTbl[MAX_SIZE]的全局变量

OS_EXT  INT32U    OSTmrTime;       /* 当前计时器计数,会不断溢出回0 */
OS_EXT  OS_EVENT *OSTmrSemSignal;  /* 定时器信号量,每次发送该信号量时会使OSTmrTime加一 */
OS_EXT  OS_STK    OSTmrTaskStk[OS_TASK_TMR_STK_SIZE];  /* 定时器管理任务所用栈 */
OS_EXT  OS_TMR_WHEEL OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE];  /* 定时器轮本体数组 */
函数实现部分
/***************************************************************************************  *		  	    	    函数部分,仅细读一些重要函数的实现,以便于方便理解流程 
* 		 	本部分整理的函数仅保留核心部分,对于一些条件编译和异常情况判断的代码会予以剔除
****************************************************************************************/
os_mem.c
/* ******************* os_mem.c (ucos为用户提供的内存管理,并不常用)  ***************** 
* 内存管理流程大致梳理:ucos全局变量OS_MEM OSMemTbl[]用于存储预定大小的OS_MEM内存区结构体,另有
* OS_MEM *OSMemFreeList作为空闲内存区结构体的链表头指针。创建内存区时即从Tbl中拿取一个内存区结构
* 体,并将结构体中的void *OSMemFreeList成员变量(与空闲内存区链表头指针重名-_-)按照函数输入的起始地
* 址,内存块大小,内存块数目此三个参数,从指定起始地址开始初始化一个内存块链表。之后的取用和释放都以目
* 标内存区结构体下的单个内存块为单位操作(所以不好用)
*********************************************************************************** */

/* **** 创建内存区函数 ****
 * 输入:  addr     起始地址
 *        nblks    内存区中内存块数目
 *        blksize  单个内存块大小
 *        perr     错误码
 * 返回:  OS_MEM * 内存控制块结构体指针
*/
OS_MEM  *OSMemCreate (void   *addr,
                    INT32U  nblks,
                    INT32U  blksize,
                    INT8U  *perr)
{
   
    OS_MEM    *pmem;
    INT8U     *pblk;
    void     **plink;
    INT32U     loops;
    INT32U     i;

    OS_ENTER_CRITICAL();
    pmem = OSMemFreeList;  /* 用内存区空闲链表OSMemFreeList从全局内存区OSMemTbl[]中拿取一块 */
    if (OSMemFreeList != (OS_MEM *)0) {
     /* 更新全局内存区空闲链表 */
        OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
    }
    OS_EXIT_CRITICAL();
    if (pmem == (OS_MEM *)0) {
     /* 判断拿到的内存区是否为空 */
        *perr = OS_ERR_MEM_INVALID_PART;
        return ((OS_MEM *)0);
    }
    /* 将内存区初始化成nklks个内存块的链表结构 */
    plink = (void **)addr;  /* 起始地址转换为二重指针 */
    pblk  = (INT8U *)addr;  /* 起始地址转换为字节指针,方便后面分配空间 */
    loops  = nblks - 1u;
    for (i = 0u; i < loops; i++) {
   
        pblk +=  blksize;  /* 字节指针向后一个块 */
       *plink = (void  *)pblk;  /* 二重指针解引用,即将addr下的第一个字存为上一行结果处的地址 */
        plink = (void **)pblk;  /* 二重指针向后移一个块 */ 
    }
    *plink              = (void *)0;  /* 内存最后一个块,链表指针指向空 */ 
    /* 初始化内存控制块结构体 */
    pmem->OSMemAddr     = addr; 
    pmem->OSMemFreeList = addr;  /* 此处可能会有疑问,该成员在描述中是指向下一个内存块的,但此处仅为一个不定型指针。解释:其被使用时形如*(void **)OSMemFreeList,强制转换加解引用表示直接取addr地址下第一个字代表的指针 */
    pmem->OSMemNFree    = nblks; 
    pmem->OSMemNBlks    = nblks;
    pmem->OSMemBlkSize  = blksize; 
    *perr               = OS_ERR_NONE;
    return (pmem);
}

/* **** 从内存区中拿取单个内存块函数 ****
 * 输入:  pmem     内存控制块结构体指针
 *        perr     错误码
 * 返回:  void  
*/
void  *OSMemGet (OS_MEM  *pmem,
                 INT8U   *perr)
{
   
  void      *pblk;
  OS_ENTER_CRITICAL();
  if (pmem->OSMemNFree > 0u) {
     
      pblk                = pmem->OSMemFreeList;    /* pblk置为当前空闲内存块的地址 */
      pmem->OSMemFreeList = *(void **)pblk;         /* 将内存控制块的空闲内存块链表指向下个块,具体实现原理见前面函数 */
      pmem->OSMemNFree--;                           /* 可用内存块数目减一 */
      OS_EXIT_CRITICAL();
      *perr = OS_ERR_NONE;                          
      return (pblk);                                /* 返回单个空闲内存块的地址 */
  }
  OS_EXIT_CRITICAL();
  *perr = OS_ERR_MEM_NO_FREE_BLKS;                  /* 无空闲内存块错误 */
  return ((void *)0);                               
}
os_time.c
/* ********************** os_time.c (时间管理,并不是软件计时器)  *********************** 
* 	系统延时:ucos中实现延时的方式是在任务就绪表中为当前运行任务清0,并在OSTCBDly中装载延时周期数,
* 然后执行一次任务调度让出CPU,该任务便停在delay处直到再次获得CPU。
*
* 	系统心跳时钟管理(本应在os_core.c中,跟系统时间管理关系比较大,故拿到此处):基本流程为:先对一些
* 表示全局系统时间的变量加一,然后遍历已使用任务控制块链表,对其中一般延时和等待事件的任务分别减Dly周
* 期,若减到零且该任务未被挂起则在就绪表中恢复。
*********************************************************************************** */

/* **** 从内存区中拿取单个内存块函数 ****
 * 输入:  ticks     延时周期数
*/
void  OSTimeDly (INT32U ticks)
{
   
    INT8U      y;
    if (OSIntNesting > 0u) {
                        /* 中断中不可调用 */
        return;
    }
    if (OSLockNesting > 0u) {
                       /* 调度器上锁时不可调用 */
        return;
    }
    if (ticks > 0u) {
                               
        OS_ENTER_CRITICAL();
        y            =  OSTCBCur->OSTCBY;        
        OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;  /* 更新任务就绪表和任务就绪组 */
        if (OSRdyTbl[y] == 0u) {
   
            OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBDly = ticks;              /* 装载延时计数 */
      OS_EXIT_CRITICAL();
        OS_Sched();                              /* 执行一次调度 */
    }
}

/* **** 系统心跳时间管理 ****
 * 无输入无输出
*/
void  OSTimeTick (void)
{
   
      OS_TCB    *ptcb;
  #if OS_TIME_GET_SET_EN > 0u  /* 可使用拿取系统时间功能 */
      OS_ENTER_CRITICAL();                                   
      OSTime++;
      OS_EXIT_CRITICAL();
  #endif
      if (OSRunning == OS_TRUE) {
   
          ptcb = OSTCBList;                              /* 取已使用的任务控制块链表头 */
          while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {
    /* 遍历直到链表尾的空闲任务 */
              OS_ENTER_CRITICAL();
              if (ptcb->OSTCBDly != 0u) {
                   /* 操作每一个处于延时状态的任务 */
                  ptcb->OSTCBDly--;                          
                  if (ptcb->OSTCBDly == 0u) {
               /* 若减到零 */
                      /* 若在等待某个事件,并非一般延时 */
                      if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
          
                          /* 清除等待事件状态 */
                          ptcb->OSTCBStat  &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;         
                          /* 等待状态置为超时 */
                          ptcb->OSTCBStatPend = OS_STAT_PEND_TO;
                      } else {
    	/* 不在等待事件,则为一般延时,等待状态清0 */
                          ptcb->OSTCBStatPend = OS_STAT_PEND_OK; 
                      }
                      /* 未在挂起状态 */
                      if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {
     
                          /* 就绪表和就绪组更新 */
                          OSRdyGrp               
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32H750是意法半导体(STMicroelectronics)推出的一款高性能微控制器系列,它采用了Cortex-M7内核,主频高达480MHz,配备了丰富的外设和功能,适用于各种应用场景。UCOS(μC/OS)是一款开源的实时操作系统(RTOS),它提供了一种可靠和高效的多任务处理方式,可用于嵌入式系统中。 STM32H750的UCOS源码指的就是针对STM32H750系列微控制器的UCOS操作系统的源代码。由于UCOS是开源的,因此可以通过一些渠道获取到UCOS的源代码。通过研究UCOS源码,我们可以了解UCOS操作系统的内部实现和工作原理,以及如何在STM32H750上进行移植和使用。 UCOS源码包含了各个组件和模块的实现,比如任务管理、时间管理、内存管理、中断管理等,同时还包括了一些设备驱动和通信协议的支持。我们可以通过查看源代码来了解UCOS的任务调度算法、任务间的通信机制、内存管理策略等。 使用STM32H750的UCOS源码,我们可以基于UCOS构建自己的嵌入式系统,或者根据需求进行定制和优化。同时也可以通过阅读UCOS源码,学习和理解实时操作系统的设计和实现原理,提高自己在嵌入式系统开发领域的能力。 总之,STM32H750的UCOS源码提供了我们研究和应用UCOS操作系统的基础,通过深入学习和理解源码,我们可以更好地使用和定制UCOS,应用在我们的嵌入式系统开发中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值