ucos 内核成员分析

2024-03-31 06:38
文章标签 分析 成员 内核 ucos

本文主要是介绍ucos 内核成员分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

优先级

ucos3使用64个优先级,每个优先级中可以有多个不同的任务(除了0和末尾优先级)
优先级表初始化过程

void  OS_PrioInit (void)
{CPU_DATA  i;				//无符号整形32for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) {				OSPrioTbl[i] = (CPU_DATA)0;//清空任务表中的任务OS_PRIO_TBL_SIZE=2,相当于只有64个优先级,可以使用cpu函数CPU_CntLeadZeros()快速获取对应的优先级										}
}

系统可以在OSPrioTbl数组中快速获取最高的优先级,通过使用cpu函数CPU_CntLeadZeros()即可快速实现。该函数实现返回数据从左起0的数量,例如对于0x00F01234(32位),则返回8,对于0xFF001234,则返回0,对于32位处理器,优化后的代码为

OS_PRIO OS_PrioGetHightest(void)
{OS_PRIO prio;if(OSPrioTbl[0]!=(OS_PRIO_BIMAP)0){prio=OS_CntLeadZeros(OSPrioTbl[0]);}else{prio=OS_CntLeadZeros(OSPrioTb1[1])+32;}return(prio);
}

在源码中则使用没有优化的函数

//返回高优先级的任务
OS_PRIO  OS_PrioGetHighest (void)
{CPU_DATA  *p_tbl;//32uOS_PRIO    prio;//8uprio  = (OS_PRIO)0;p_tbl = &OSPrioTbl[0];//获取优先级表的位置指针//Os PrioGetHighest()从osPrioTbl[o]开始扫描表,直到找到一个非零的表项为止。循环将总是终止,因为由于空闲任务,表中总是有一个非零的条目。while (*p_tbl == (CPU_DATA)0) {  //循环判断当前优先级状态/* Search the bitmap table for the highest priority       */prio += DEF_INT_CPU_NBR_BITS;//每一等级占32位,判断后一32递增  /* Compute the step of each CPU_DATA entry                */p_tbl++;}//CPU CntLeadzeros()函数只是简单地计算一个CPU数据条目从左开始有多少个零(即最有效位)。例如,假设是32位,OxF0001234会得到0个前导0,Ox0OF01234会得到8个前导0。prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl);              /* Find the position of the first bit set at the entry    */return (prio);//返回当前闲置的最高优先级
}

就绪列表由两个数据结构组成:一个位图表,用来跟踪哪个优先级已经就绪,另一个表包含每个优先级上所有就绪任务的列表

  • OSPrioTbl[] 存放优先级数组,当某优先级置1,则为闲置优先级
  • OSRdyList[] 准备运行的任务,该数组的每一个位置代表一个优先级,即OSRdyList[0]代表优先级为0的任务,其他的以此类推,而每个数组成员则指向包含(NbrEntries,HeadPtr,TailPtr)参数的地址,NbrEntries代表该优先级中的任务总数,HeadPtr和TailPtr形成一个任务链,该任务链是当前优先级下的所有任务,易得前者指向首部,后者指向尾部。对于OSRdyList[0],将永远只有一个ISR Handler Task,对于OSRdyList[末尾],将永远只用于存放闲置任务。

任务堆栈

先前我们讨论过,ucos的任务堆栈是作为sram前段内存储存在sram中的,之后是设备堆栈,对于任务堆栈,其特性如下图
在这里插入图片描述

会发现作为任务堆栈,其增长方式和栈是一样的(高地址到低地址),堆栈的最下方(最高地址)储存着处理器cpu当前的寄存器值,我们知道ucos是一个抢占式系统,当任务切换时,任务会保存当前的cpu寄存器(CPU Registers)值并进入"休眠",然后切换到另一个优先级高的任务,执行结束后再返回,然后取出休眠前的cpu寄存器值(这些值记录了执行到代码的哪一行,各种临时变量的值和对应的指针),然后把值推回cpu就又能够从先前停下的地方继续运行。存储完这部份数据后的数据就是任务执行需要的其他堆栈数据的位置,没有用的内存值都为0,任务堆栈从高地址到低地址增长,其栈顶由任务的控制块TCB(Task Control Base)的SP指针指定,即标明栈顶。对于TCB,每个TCB都保存着任务初始化时的数据(eg:任务优先级,任务名称,任务状态,内部信息队列等等)。

中断处理

在任务运行过程中,如果遇到了ISR这样中断,系统将停下当前任务去执行中断任务,该中断任务使用的堆栈是MSP(stm32的栈),因此不会破坏原任务的数据结构,在执行结束后返回原任务时,读写任务堆栈中保存的CPU寄存器值就可以继续执行任务。
对于为什么不在ISR中进行任务的切换,网络上的解释是这将可能导致原有的context无法恢复,且如果有多种不同的信息恰好在ISR中释放时,很可能将导致关键信号的接收失败。为此在出现中断嵌套时停止任务切换等操作是更加省时的方式。对于不在ISR中使用任务调度还有的理解如下为什么不能在ISR中进行任务切换;
为了避免在ISR时系统的context被破坏,在ucos中,编写中断服务函数格式如下

void EXTI15_10_IRQHandler(void)
{OSIntEnter();/**裸机时候的中断服务函数**/OSIntExit();
}

其中OSIntEnter()和OSIntExit()代码如下

void  OSIntEnter (void)
{if (OSRunning != OS_STATE_OS_RUNNING) {                 /* Is OS running?                                         */return;                                             /* No                                                     */}if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) {          /* Have we nested past 250 levels?                        */return;                                             /* Yes                                                    */}OSIntNestingCtr++;                                      /* Increment ISR nesting level                            */
}
void  OSIntExit (void)
{CPU_SR_ALLOC();if (OSRunning != OS_STATE_OS_RUNNING) {                 /* Has the OS started?                                    */return;                                             /* No                                                     */}CPU_INT_DIS();if (OSIntNestingCtr == (OS_NESTING_CTR)0) {             /* Prevent OSIntNestingCtr from wrapping                  */CPU_INT_EN();return;}OSIntNestingCtr--;if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* ISRs still nested?                                     */CPU_INT_EN();                                       /* Yes                                                    */return;}if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        /* Scheduler still locked?                                */CPU_INT_EN();                                       /* Yes                                                    */return;}OSPrioHighRdy   = OS_PrioGetHighest();                  /* Find highest priority                                  */OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;     /* Get highest priority task ready-to-run                 */if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* Current task still the highest priority?               */CPU_INT_EN();                                       /* Yes                                                    */return;}#if OS_CFG_TASK_PROFILE_EN > 0uOSTCBHighRdyPtr->CtxSwCtr++;                            /* Inc. # of context switches for this new task           */
#endifOSTaskCtxSwCtr++;                                       /* Keep track of the total number of ctx switches         */#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)OS_TLS_TaskSw();
#endifOSIntCtxSw();                                           /* Perform interrupt level ctx switch                     */CPU_INT_EN();
}

可以看到,在进出中断服务函数时,会判断当前中断的嵌套层数if (OSIntNestingCtr == (OS_NESTING_CTR)0),一直到中断嵌套层数为0时才会开始执行任务调度,这意味着在出现ISR嵌套时,系统的所有精力都在ISR上,直到所有ISR都完成。如图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-438vfR0b-1616903544917)(/pic\嵌入式\系统\UCOS\ISR_SW.png)]

参考
ucos在M3中的中断嵌套机制
关于STM32-M3/M4的MSP和PSP

任务控制块(TCB)

这是相当多字段的一个结构,结构源码如下

struct os_tcb {CPU_STK             *StkPtr;                            /* Pointer to current top of stack,指向当前已用的栈底     */void                *ExtPtr;                            /* Pointer to user definable data for TCB extension,扩展储存FPU的数据(如果有FPU)*/CPU_STK             *StkLimitPtr;                       /* Pointer used to set stack 'watermark' limit            */OS_TCB              *NextPtr;                           /* Pointer to next     TCB in the TCB list                */OS_TCB              *PrevPtr;                           /* Pointer to previous TCB in the TCB list                */OS_TCB              *TickNextPtr;	OS_TCB              *TickPrevPtr;	/*TickNextPtr,TickPrevPtr这些指针用于在等待时间到期或等待pend调用超时的任务列表中双向链接os tcb。同样,双链表允许从列表中快速插入和删除Os tcb。*/OS_TICK_SPOKE       *TickSpokePtr;                      /* Pointer to tick spoke if task is in the tick list 该指针用于知道任务链接到滴答列表中的哪一项*/CPU_CHAR            *NamePtr;                           /* Pointer to task name                                   */CPU_STK             *StkBasePtr;                        /* Pointer to base address of stack  栈底(任务栈是由高地址到低地址)*/#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)OS_TLS               TLS_Tbl[OS_CFG_TLS_TBL_SIZE];
#endifOS_TASK_PTR          TaskEntryAddr;                     /* Pointer to task entry point address任务函数代码的位置*/void                *TaskEntryArg;                      /* Argument passed to task when it was created任务函数代码使用的参数*/OS_PEND_DATA        *PendDataTblPtr;                    /* Pointer to list containing objects pended on           */OS_STATE             PendOn;                            /* Indicates what task is pending on 表明等待的对象类型(标志,信号量,互斥锁...)                     */OS_STATUS            PendStatus;                        /* Pend status 表明等待的结果(ok,del,timeout,about)				*/OS_STATE             TaskState;                         /* See OS_TASK_STATE_xxx 当前任务状态(挂起,运行,删除....)*/OS_PRIO              Prio;                              /* Task priority (0 == highest)                           */CPU_STK_SIZE         StkSize;                           /* Size of task stack (in number of stack elements) 整个任务堆栈的大小*/OS_OPT               Opt;                               /* Task options as passed by OSTaskCreate()               */OS_OBJ_QTY           PendDataTblEntries;                /* Size of array of objects to pend on任务正在等待的对象数量*/CPU_TS               TS;                                /* Timestamp                                              */OS_SEM_CTR           SemCtr;                            /* Task specific semaphore counter 任务收到的信号量的数量 *//* DELAY / TIMEOUT                                        */OS_TICK              TickCtrPrev;                       /* Previous time when task was            ready           */OS_TICK              TickCtrMatch;                      /* Absolute time when task is going to be ready           */OS_TICK              TickRemain;                        /* Number of ticks remaining for a match (updated at ...  *//* ... run-time by OS_StatTask() 剩余的等待时间           */OS_TICK              TimeQuanta;	OS_TICK              TimeQuantaCtr;												/*这些字段用于时间切片。当多个任务以相同优先级准备运行时,. timequanta决定任务将执行多少时间(以ticks为单位),直到它被uC/OS-III抢占,以便下一个具有相同优先级的任务有机会执行。.TimeQuantactr将跟踪此任务发生的剩余滴答数,并在任务的时间片开始时由.TimeQuanta加载*/
#if OS_MSG_EN > 0uvoid                *MsgPtr;                            /* Message received                                       */OS_MSG_SIZE          MsgSize;
#endif#if OS_CFG_TASK_Q_EN > 0uOS_MSG_Q             MsgQ;                              /* Message queue associated with task                     */
#if OS_CFG_TASK_PROFILE_EN > 0uCPU_TS               MsgQPendTime;                      /* Time it took for signal to be received 收到信息等待的时间*/CPU_TS               MsgQPendTimeMax;                   /* Max amount of time it took for signal to be received   */
#endif
#endif#if OS_CFG_TASK_REG_TBL_SIZE > 0uOS_REG               RegTbl[OS_CFG_TASK_REG_TBL_SIZE];  /* Task specific registers(可以用来储存任务相关的信息)    */
#endif#if OS_CFG_FLAG_EN > 0uOS_FLAGS             FlagsPend;                         /* Event flag(s) to wait on 任务挂起的事件标志		        */OS_FLAGS             FlagsRdy;                          /* Event flags that made task ready to run                */OS_OPT               FlagsOpt;                          /* Options (See OS_OPT_FLAG_xxx)当任务挂起事件标志时,此字段包含pend的类型*/
#endif#if OS_CFG_TASK_SUSPEND_EN > 0uOS_NESTING_CTR       SuspendCtr;                        /* Nesting counter for OSTaskSuspend()记录任务被挂起的时间(可以嵌套)*/
#endif#if OS_CFG_TASK_PROFILE_EN > 0uOS_CPU_USAGE         CPUUsage;                          /* CPU Usage of task (0.00-100.00%)CPUUsage包含任务的CPU使用率百分比(0到100%)。*/OS_CPU_USAGE         CPUUsageMax;                       /* CPU Usage of task (0.00-100.00%) - Peak                */OS_CTX_SW_CTR        CtxSwCtr;                          /* Number of time the task was switched in记录任务运行的次数*/CPU_TS               CyclesDelta;                       /* value of OS_TS_GET() - .CyclesStart记录当前的时间戳    */CPU_TS               CyclesStart;                       /* Snapshot of cycle counter at start of task resumption切换到当前任务时的时间戳*/OS_CYCLES            CyclesTotal;                       /* Total number of # of cycles the task has been running任务总运行时间*/OS_CYCLES            CyclesTotalPrev;                   /* Snapshot of previous # of cycles上一次运行的时间?     */CPU_TS               SemPendTime;                       /* Time it took for signal to be received 接收到信号量的时间*/CPU_TS               SemPendTimeMax;                    /* Max amount of time it took for signal to be received   */
#endif#if OS_CFG_STAT_TASK_STK_CHK_EN > 0uCPU_STK_SIZE         StkUsed;                           /* Number of stack elements used from the stack已用应用堆栈           */CPU_STK_SIZE         StkFree;                           /* Number of stack elements free on   the stack空闲应用堆栈           */
#endif#ifdef CPU_CFG_INT_DIS_MEAS_ENCPU_TS               IntDisTimeMax;                     /* Maximum interrupt disable time                         */
#endif
#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0uCPU_TS               SchedLockTimeMax;                  /* Maximum scheduler lock time该字段跟踪任务的最大调度程序锁定时间。  */
#endif#if OS_CFG_DBG_EN > 0uOS_TCB              *DbgPrevPtr;OS_TCB              *DbgNextPtr;CPU_CHAR            *DbgNamePtr;									//包含导致任务挂起的对象类型(信号量,互斥锁,消息队列...)
#endif
};

这篇关于ucos 内核成员分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/863668

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师,爱吃土豆。如有需要技术交流或者需要方案帮助、需求:以下为联系方式—V 方案1:通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通过IO+EXIT中断的方式进行霍尔传感器数据的读取。将IO口配置为上升沿+下降沿中断触发的方式。当霍尔传感器信号发生发生信号的变化就会触发中断在中断