[转]一些别人学习ucosii的笔记作为参考

2024-01-24 19:58

本文主要是介绍[转]一些别人学习ucosii的笔记作为参考,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、uC/OSii 内核结构:任务管理,时间管理,中断处理,任务之间的通信与同步!

二、代码的临界区分析:

代码的临界区也称为临界区,指该代码在被处理时不能被分割,因此不能被中断打入!所以在进入该代码(临界区)时应该关中断,而执行完后再打开中断!而uC/OSii 用OS_ENTER_CRITICAL和OS_EXIT_CRITICAL这两个宏来开/关中断。而针对不同的处理器,这两个宏定义是不同的,分为三种,由OS_CRITICAL_METHOD的值来区分。一般ARM的OS_CRITICAL_METHOD=3(第三种宏定义)

三、uC/Osii的TASK(任务)

uC/Osii的任何工作都是由任务来完成的。

任务是一种无限循环的结构,每一个任务对应着一个任务级,uC/Osii有64个任务优先级,每一个优先级不能重复存在,也就是每一个优先级对应一个任务。因此可以把优先级看成一个任务的标志,事实上uC/Osii的确是这样做的。

TASK最主要的部分就是任务控制快(TCB), uC/Osii控制任务其实本质就是对任务的TCB进行控制

TCB是一种数据结构,那什么是数据结构?就是一些信息的集合体。TCB里面包含了哪些信息呢?以下进行分析:

(1)OSTCBStkPtr,它是指向该任务堆栈栈顶的指针,也就是指向堆栈起始地址。

 

(2)OSTCBStkBottom,是指向该任务堆栈栈底的指针,这个主要是检测堆栈剩余空间用的。

 

(3)OSTCBStkSize,堆栈容量。

 

(4)OSTCBOpt,没有搞清楚 ,只知道是OSTaskCreateExt(),才有用。

 

(5)OSTCBNext和OSTCBPrev,用语任务控制块OS_TCB双向链表的前后任务块连接,在调用OSTimeTick()时会使用这个前后连接的双向链表,来刷新各个任务的任务延迟变量OSTCBDly(马上对它说明)。每一个任务TCB建立时,会连接到该连表中,在删除任务时也会从中删除。(除了睡眠状态,任务的控制块始终连接在这个链表)

 

(6)OSTCBDly,当需要把某任务延迟若干时钟接拍时,或者因为等待某个事件发生而挂起任务时,都需要这个变量。其实任务时延函数OSTimeDly()的作用就是 将任务从就绪列表移除(移除方法后面会讲)并且对这个变量赋值(要延迟的节拍数)。OSTimeTick()会每隔一个节拍就通过OS_TCB双向列表(第5条讲过的)对每一个TCB的OSTCBDly进行查看,如果OSTCBDly为0不做操作继续检查下一个TCB。

当OSTCBDly非0,那么OSTimeTick()对OSTCBDly得值减一,如果做完减一后OSTCBDly值为0则表明该任务延时结束,将该任务添加到就绪队列。然后继续下一个TCB。

 

重要(7)OSTCBPrio、该任务的优先级。个人感觉uC/Osii就是通过这个来区别不同的TCB,也就是OSTCBPrio就是这个任务的标志或者说是名字。

 

(8)OSTCBX  OSTCBY  OSTCBBitX   OSTCBBitY、  长得很像啊,容易搞混,其实这四个给一个作用那就是分解Prio这个值,从而加速任务进入就绪的过程或者进入等待事件发生状态的过程。那肯定有人就要疑惑为什么能加速呢,我们来慢慢分析下:

首先让任务进入就绪具体的操作就是将该任务的OSTCBPrio写入就绪表中OSRdyGrp和OSRdyTbl[ ]。仅此而已,所以这也印证了在第7条中我说过OSTCBPrio就是这个任务的标志。而将OSTCBPrio写入就绪表OSRdyGrp和OSRdyTbl[ ]并不是把这个值直接写入就完了,而是要通过  OSRdyGrp         |=OSMapTbl[prio>>3];
     OSRdyTbl[prio>>3]  |=OSMapTbl[prio & 0x07];这个计算式。那么为了让任务能更快的进入就绪状态

我们就事先将OSMapTbl[prio>>3]  OSMapTbl[prio & 0x07]算出来,而OSTCBX  OSTCBY  OSTCBBitX   OSTCBBitY就是存储这个些值的变量。

进入进入等待事件发生状态的过程与之类似,就不讲了(累死了。。)

(10)OSTCBEventPtr、指向时间控制快,是TCB和ECB联系在一起。

四、任务的五种状态:

(只有休眠状态,没有TCB}

休眠态(dormant):指任务驻留在程序空间中,还没有交给内核管理,也就是任务没有分配TCB 。把任务交给内核管理是通过调用OSTaskCreate( )或OSTaskCreatExt( )实现的,为其分配TCB

就绪(Ready):当任务一旦建立,这个任务就处于就绪态准备运行。任务可以动态的被另一个程序建立,也可以在系统运行开始之前建立。通过调用OSTaskDel( )使任务返回到休眠态。就绪态的任务都放在就绪列表中。在任务调度时,指针OSTCBHighRdy指向优先级最高的就绪任务,也就是立刻就要运行的任务。
任务处于就绪队列两个条件:首现要该任务被分配了TCB。其次是要将该任务的优先级(prio)写进绪表中OSRdyGrp和OSRdyTbl[ ],具体办法如下:
                                        OSRdyGrp         |=OSMapTbl[prio>>3];
                                        OSRdyTbl[prio>>3]  |=OSMapTbl[prio & 0x07];

运行态:优先级最高的任务获得CUP,该任务就处于运行状态,指针OSTCBCur指向正在运行的任务。
。 一旦有比这个任务优先级更高的任务出现,uC/OSii 就会通过OSSched()进行任务调度,将现在处于就绪状态且优先级最高的任务交给CPU处理。

等待或挂起(Pending):正在运行的任务由于调用延时函数OSTimeDly( )、OSTimeDlyHMSM( )(将自身延迟)或等待某一事件的发生时,调用以下几个函数:OSFlagPend()、OSSemPend(),OSMutexPend()、OSMboxPend(),如果该事件发生了,那么该任务继续执行,如果该事件没有发生,那么将自身挂起,因而处于等待或挂起态。

      等待某事件而被挂起的任务,系统将会从OSRdyGrp和 OSRdyTbl[  ]中把该任务的优先级去掉(也就是相应位清0,因此在事件还没发生时,这个任务将不会再被调度),转而将该任务(优先级)添加在在该事件的等待列表中。

     事件分为:信号量、互斥信号量,消息邮箱、队列消息。每一个信号量、互斥信号量,消息邮箱、消息队列都会分配到一个事件控制块ECB.

    每个ECB都会有 事件的等待列表OSEvenGrp和 OSEvenTbl[  ]   ,它与就绪表中OSRdyGrp和OSRdyTbl[ ]极为相似。等待某事件而被挂起的任务,系统会将该任务优先级写入事件的等待列表OSEvenGrp和 OSEvenTbl[  ]。

    当某一事件发生了,那么该事件的ECB会从事件的等待列表选取优先级最高的任务获得事件,离开等待状态,从而进入就绪状态。

中断态(Interrupt):正在运行的任务可以被中断,除非是该任务将中断关闭。被中断的任务进入中断服务程序(ISR)。如果中断服务程序使一个更高优先级的任务准备就绪,这中断服务程序结束后,则更高优先级的任务开始运行程序。

我觉得uC/Osii工作,其实根本上就是控制多个任务在这5钟状态下转换,并且任务之间互相通信。所以一下从一个状态到另一个状态分析。

 

五、从睡眠态到就绪态

睡眠态到就绪态调用OSTaskCreate()或者OSTaskCreateEXt()建立一个任务,在多任务调度前 (也就是调用OSStart()) 必须要创建一个应用任务(除去空闲任务和统计任务)。

任务建立过程:

(1)首先对OSTaskCreate((void(*task))(void *pd),void *pdate,OS_STK *ptos,INT8U prio)参数赋值!

*Task(指向任务代码起始地址的指针)

*pdate(给task(*pdata)传递的参数的指针)

*ptos(起始栈顶位置,如果堆栈属于从高地址向低地址方向增长的,那么*ptos应该等于&taskstack[TASK_STACK_SIZE-1].如果是从低地址向高地址方向增长,那么*ptos的值等于&taskstack[0].)

Prio(该任务的优先级)

(2)判断设置的优先级是否已经存在。

       OSTCBPrioTbl[prio]= =(OS_TCB*)0 :这就表明该优先级的任务还不存在

解释:OSTCBPrioTbl[]是一个指针数组,作用例如OSTCBPrioTbl[2],他代表的是指向任务优先级为2的任务的任务控制块,而OSTCBPrioTbl[prio]= =(OS_TCB*)0代表的是指向优先级prio的指针为空,没有指向任务快,这就表明该优先级的任务还不存在。

(3)为任务分配任务堆栈并初始化,调用函数OSTaskInit(task,pdata,ptos,0)

Ptos初始栈顶位置,这样就知道该任务堆栈在内存的位置。然后将Task(指向任务代码起始地址 )  pdate(给task(*pdata)传递的参数值)压入堆栈,还有R14—R0也要入堆栈。然后将现在的堆栈栈顶指针返回给变量psp。

(4)为任务分配TCB并初始化。调用函数OS_TCBInit( prio,psp,(void*)0,0,0,(void*)0,0)

将优先级和(psp)栈顶位置传给OS_TCBInit,用来建立TCB..

(5)然后调用OS_Sched()。  注:我认为只要某个函数里面有对优先级改变的,都要用到OS_Sched(),因为uC/Osii属于抢占式操作系统,因此CPU总是为优先级最高的任务服务,那么当每次改变任务优先级后,都要OS_Sched()用检查有没有新的最高优先级任务出现,如果有的话就将CPU分配给该任务。

 

OSTaskCreateEXt()与上面类似。

 

六、从就绪态到运行状态 以及从运行态都就绪态。

就绪态到运行状态调用到的  函数OS_Sched(void)相当于一个任务调度器。

OS_Sched(void)操作就两大块,

第一是从就绪表中OSRdyGrp和OSRdyTbl[ ]找到最高优先级的任务。所以通过

y=OSUNMapTbl[OSRdyGrp]

x= OSUNMapTbl[OSRdyTbl[y]]

最大Prio=INT((y<<3)+X)

第二步就是将CPU分配给该任务。

OSTCBHighRdy= OSTCBPrioTbl[prio]//OSTCBHighRdy指向高优先级的任务。

然后调用OS_TASK_SW( )函数将CPU的寄存器状态压入低优先级任务,并将OSTCBCur= OSTCBHighRdy  也就是将OSTCBCur指向高优先级的任务(OSTCBCur总是指向正在运行的任务),然后将高优先级任务的堆栈内容赋给CPU的寄存器,然后该任务运行。

 

从运行态都就绪态

同样是是是函数OS_Sched(void),当有一个新最高级的任务出现在就绪队列中,那么正在运行的任务将会被取代,转而进人就绪态。

 

七、从运行态到等待状态

从运行态到等待状态,分为三种:

第一种是挂起函数,OSTASKSupend(),任务挂起是一个附加功能,把任务从就绪表中移除,进入等待状态。

第二种是OsTimeDly()函数,它是将任务本身延时一定时间,这个函数其实就是对TCB中的OSTCBDly变量进行赋值且把任务从就绪表中移除,进入等待状态。然后通过用OSTimeTick()对每个TCB的OSTCBDly(非0值的)每过隔一个接拍就减一,直至为0,表明延时结束,然后将该任务恢复到就绪态。

 

第三种是等待某一事件的发生时,调用以下几个函数:OSFlagPend()、OSSemPend(),OSMutexPend()、OSMboxPend(),如果该事件发生了,那么该任务继续执行,如果该事件没有发生,那么将自身挂起,因而处于等待或挂起态。

与上面不同,不仅要从就绪表中移除该任务,还要将任务添加到相应事件ECB的等待列表OSEvenGrp和 OSEvenTbl[  ]中(就像就绪表一样,等待列表允许多个任务,也就是可能有多个任务同时等待一个事件发生)。

    所有的通信信号都被看成一个事件。

 事件分为:信号量、互斥信号量,消息邮箱、队列消息。每一个信号量、互斥信号量,消息邮箱、消息队列都会分配到一个事件控制块ECB.

ECB的结构如下

Typedef struct{

Void *OSEventPtr     //指向信号的指针

INT8U OSEventCnt   //计数器,用于事件是信号量。

INT8U OSEventType   //事件的类型(如信号量,互斥信号量,队列消息等)

INT8U OSEventGrp    //等待任务组

INT8U OSEventTbl[ ]   //等待任务列表

    每个ECB都会有 事件的等待列表OSEvenGrp和 OSEvenTbl[  ]   ,它与就绪表中OSRdyGrp和OSRdyTbl[ ]极为相似。

这篇关于[转]一些别人学习ucosii的笔记作为参考的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件