ucos-ii复习

uCOS-II基础知识点归纳

TCB内容

ucosii.h中,对TCB定义如下 (截取重要的):

typedef struct os_tcb {
    OS_STK        *OSTCBStkPtr;   // 堆栈栈顶指针
    ...
    struct os_tcb *OSTCBNext;     // 指向下一个TCB的指针
    struct os_tcb *OSTCBPrev; 	  // 指向上一个TCB的指针
    ...
    INT16U         OSTCBDly;      // 任务延迟的时间
    INT8U          OSTCBStat;     // 任务的状态:就绪、阻塞、运行、等待、睡眠、ISR
    INT8U          OSTCBPrio;     // 任务的优先级
    // 优先级位图法用到的结构
    INT8U          OSTCBX; 
    INT8U          OSTCBY; 
    INT8U          OSTCBBitX; 
    INT8U          OSTCBBitY; 
    ...
}OS_TCB;

优先级位图法代码分析—原理不讲

OS_TCBInit 函数(优先级位图法部分):

{
    ...
    //从OSTCBFreeList上取下一个空闲的,已经初始化过的TCB
    ptcb = OSTCBFreeList;
    ...
    //初始化OSTCBX/OSTCBY/OSTCBBitX/OSTCBBitY,ptcb为指向TCB的指针
	ptcb->OSTCBY = (INT8U)(prio>>3);	   //prio>>3为取3~5位,及优先级的十位
    OSTCBBitY = OSMapTbl[ptcb->OSTCBY];    //将其转化为one-hot编码(类似掩码)
    ptcb->OSTCBX = (INT8U)(prio & 0X07);
    OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
    ...
    //将TCB连接到OSTCBList上
    OSTCBList = ptcb;  //OSTCBList将就绪状态的Task的TCB全串联在一起,用于OSTimeDly()函数对每个TASK的OSTCBDly进行修改
    				   //当OSTCBDly减为0时,则可能会触发调度(取决于优先级)
    
    //以下作用类似于把就绪的Task放入就绪队列中,但uCOS-II本质上无就绪队列
    OSRdyGrp |= ptcb->OSTCBBitY;	//将十位的掩码与OSRdyGrp相与,更新OSRdyGrp
    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;	
    ...
}

附表:OSMapTbl

000000000
100000001
200000010
300000100
400001000
500010000
600100000
701000000
810000000

OS_SchedNew 函数(优先级位图法部分):

OS_SchedNew 函数在 OS_Sched 函数中被调用,用来找到当前最高优先级:

{
    ...
    //仅讨论 OS_LOWEST_PRIO <= 63的情况(优先级数字约大优先级越低)
    INT8U y;
    y = OSUnMapTbl[OSRdyGrp];	//y存放的值为OSRdyGrp数组中,获取十位第一个出现1的位数(0~7位),也是OSRdyTbl的第y行
    OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);  //同理,OSUnMapTbl[OSRdyTbl[y]]获取个位第一个															       //出现1的位数
    // (y << 3) + OSUnMapTbl[OSRdyTbl[y]]即为优先级Prio,然后将其放入OSPrioHighRdy中去
    // 即更新 优先级最高 的 就绪任务 的 优先级
    ...
}

因此,出现有优先级位图法的函数即为OS_TCBInit -> OS_SchedNew,一个是初始化,一个是调度

几个重要参数的意义

ucos_ii.h的部分宏定义代码如下

OS_EXT  INT8U     OSPrioCur;       /* Priority of current task               */
OS_EXT  INT8U     OSPrioHighRdy;   /* Priority of highest priority task      */
OS_EXT  OS_TCB   *OSTCBCur;        /* Pointer to currently running TCB       */
OS_EXT  OS_TCB   *OSTCBHighRdy;    /* Pointer to highest priority TCB R-to-R */

参数归纳表

OSTCBCur指向正在运行的任务的TCB——指针
OSPrioHighRdy优先级最高的 “就绪任务” 的优先级
OSTCBPrioTbl一个数组,数组下标大小对应任务优先级的大小,存放指向任务TCB的指针——数组
OSPrioCur当前任务的优先级
OSTCBHighRdy指向最高优先级的TCB——指针

上下文切换步骤

OSCtxSw代码如下:

;----------------------------------------------------------------------------------
; 	   保护现场,将原Task的R0~012,LR,PC,CPSR压回OSTCBStkPtr指向的栈区
;----------------------------------------------------------------------------------	
	STMFD	 SP!, {LR}               ;保存返回地址,也就是PC
	STMFD	 SP!, {R0-R12, LR}       ;R0-R12 LR,从右往左压                                 
	MRS	     R0,  CPSR               ;通过R0来压入CPSR,为了防止在压栈过程中改变CPSR的值                           
	STMFD	 SP!, {R0}	          

;----------------------------------------------------------------------------------
; 	   OSTCBCur->OSTCBStkPtr = SP, 以便返回的时候找到现场的数据;
;----------------------------------------------------------------------------------		
	LDR		R0, =OSTCBCur
	LDR		R0, [R0]
	STR		SP, [R0]
	
	BL 		OSTaskSwHook 	
	
;---------------------------------------------------------------------------------
; 	   OSTCBCur = OSTCBHighRdy, 让OSTCBCur指向就绪队列中最高优先级的任务;
;----------------------------------------------------------------------------------
	LDR		R0, =OSTCBHighRdy
	LDR		R1, =OSTCBCur
	LDR		R0, [R0]
	STR		R0, [R1]
	
;---------------------------------------------------------------------------------
; 	   OSPrioCur = OSPrioHighRdy, 更新当前的最高优先级;
;---------------------------------------------------------------------------------
	LDR	    R0, =OSPrioHighRdy
	LDR	    R1, =OSPrioCur
	LDRB	R0, [R0]
	STRB	R0, [R1]
	
;----------------------------------------------------------------------------------
;  	   SP = OSTCBHighRdy->OSTCBStkPtr, 读取存放有现场的堆栈地址;
;----------------------------------------------------------------------------------
	LDR		R0, =OSTCBHighRdy                                            
	LDR		R0, [R0]
	LDR		SP, [R0]
	
;----------------------------------------------------------------------------------
;	   Restore New task context
;----------------------------------------------------------------------------------
	LDMFD 	SP!, {R0}	   ;把CPSR出栈到R0中       
	MSR 	SPSR_cxsf, R0  ;将CPSR的值写入到SPSR                                               
	LDMFD 	SP!, {R0-R12, LR, PC}^	 ;出栈,^代表用SPSR拷贝到CPSR中,等效于压栈CPSR

几个重要函数的执行流程

OSTaskCreate:

  1. 在OSTCBPrioTbl中占位

  2. 堆栈初始化 (调用OSTaskStkInit) ——> 要先堆栈初始化以后才能把堆栈的地址放入OSTCBStkPtr中

  3. TCB初始化 (调用OS_TCBInit)

  4. 若符合条件,则调度 (调用OS_Sched);否则将OSTCBPrioTbl对应位清0

OSTaskStkInit:

  1. *(stk) = (OS_STK)task 使第一个单元指向函数

  2. *(–stk) = (INT32U)0 初始化LR,R12~R1

  3. *(–stk) = (INT32U)p_arg 将任务参数放入R0

  4. *(–stk) = (INT32U)0x013L 设置CPSR为SVC模式,打开IRQ与FIQ

OS_TCBInit:

  1. 从FreeList中摘取一空闲TCB
  2. 为TCB中的几个参数赋值
  3. 为优先级位图法的几个参数赋值
  4. 将TCB链接到OSTCBPrioTbl中
  5. 把TCB放到OSTCBList链表的开头

OS_Sched:

  1. 判断是否有中断嵌套,调度是否打开
  2. 调用OS_SchedNew来获取最高优先级的任务
  3. 执行任务上下文切换

OSCtxSw:

  1. 压栈保存当前任务的现场
  2. 将TCB的堆栈地址(压栈完后为SP)放入OSTCBStkPtr中
  3. 让OSTCBCur指向当前最高优先级任务的TCB
  4. 更新当前的最高优先级
  5. 读出最高优先级任务的TCB地址存入SP
  6. 出栈

拷贝代码段到RAM

把ResetHandler代码段(Norflash) 存放到Text_start段(RAM):

低地址到高地址为:ResetHandler —— Text_start —— BSS_start

		ADR     r1, ResetHandler   /* ADR为小范围的装入,装入的是当前状态下实时的位置 */
        LDR     r2, =text_start    /* LDR为大范围的装入,装入的是链接文件中规定的绝对地址 */
        LDR     r3, =bss_start
       
copyloop:     
        LDR     r0, [r1], #4
        STR     r0, [r2], #4
        CMP     r2, r3           
        BNECC     copyloop
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1.嵌入式实时操作系统的特点与常用的几种嵌入式操作系统。 实时性,可裁剪性。 ucos-Ⅱ RTLinux ARM-Linux KURT TimeSys Linux Mach 商业常见 VxWorks QNX pSOS Windows CE 2.掌握uC/OS-Ⅱ操作系统中的任务的存储结构与任务控制块主要成员变量的作用、任务的程序结构、任务的调度过程、任务状态的转换过程、任务的创建过程。任务级的切换与中断级的切换。 一.任务的存储结构P74 前一个任务控制块的Ptr 后一个任务控制块的Ptr 指向任务的Ptr 指向堆栈的Ptr 任务的优先级别 ............................ 任务的代码: void mytask(void * ) {......... For( ; ; ) {......} } 任务的堆栈: ....................... 系统在运行一个任务是,先按优先级找到任务控制块,在任务堆栈中找到任务代码的指针。 任务控制块是系统管理任务的依据。 任务控制块-------保存任务的属性 任务的代码-------任务的执行部分 任务的堆栈-------保存任务的工作环境 二.任务控制块主要成员变量的作用P78 不同任务 TCB成员变量个数不是固定的。 其中 OSTCBStat 用来存放任务当前状态。 其中 OSTCBDly 用来存放任务等待时限(节拍数)。 其中 OSTCBPrio 用来存放任务的优先级。 所有任务控制块分为2条链表:空闲任务块链表和任务块链表。 空闲任务块是uC/OS-Ⅱ的全局数据结构 OSInit()创建空闲任务控制块链表的步骤:1先在RAM中建立一个OS_TCB结构类型的OSTCBTb1[]使数组每个元素都是一个任务控制块,然后利用OS_TCB结构中的OSTCBTNext和OSTCBPrev连起来构成一个链表。 为了加快对任务控制块的访问速度:除了任务控制块链表创建成双向链表外在uC/OS-Ⅱ的uCOS-Ⅱ.H中还定义了一个OS_TCB*类型的数组OSTCBTb1[]专门用来存放指向各任务控制块的指针。 删除一个任务的实质:把任务的控制块从任务控制块链表中删除,并把它归还给任务控制块链表。但是任务的代码还在内存中没被删除。 任务的程序结构 任务的调度过程 在就绪任务表中寻找优先级最高的就绪任务置为运行态,然后中止当前正在运行的任务,从而运行刚刚那个置为运行态的任务 若 OSLockNesting当前的值不为0则 禁止调度 任务状态的转换过程 任务的创建过程 先检测任务的优先级是否合法 然后检测该优先级是否被占用 然后保留该优先级 然后初始化任务堆栈 然后获得任务控制块并初始化 然后任务计数器+1 最后调度 否则放弃任务 任务级的切换与中断级的切换 OSIntCtxSw() -- 中断级任务切换函数与OSCtxSw() -- 任务级切换函数的区别: OSIntCtxSw()与OSCtxSw()的后半部分相同,而OSIntCtxSw()缺少的断点保护,则在中断子程序中完成。但是两者都完成两任务的切换: OSCtxSw() 完成两个不同任务间的切换; OSIntCtxSw()则是在一定条件下,在中断结束后,原被中断的程序与更高优先级的任务之间的切换。 掌握五种任务的通信与同步的方法。对应的事件控制块与信号量集标志组的结构。并比较这五种任务的通信与同步的方法在请求、发送过程中的各自特点。 C/OS-Ⅱ操作系统初始化所须完成的的五件事:初始化几个重要的全局变量、数组OSTCBPrioTbl[ ]、就绪表、五个链表(空任务控制块、空事件控制块、空队列控制块、空信号量集标志组、空内存控制块)、创建空闲任务。或有条件创建统计任务。 中断及中断服务程序。定时中断服务及时钟节拍服务函数OSTimTick()的作用 CPU相应中断的条件:1至少有一个中断源向CPU 发出信号 2系统允许信号且未对此信号屏蔽。 钟节拍服务函数OSTimTick()的作用:1把用来记录时间进程的计数器OSTime+1 2遍历任务控制块链表中所有任务控制块,吧各个任务控制块中用来存放任务延时的OSTCBDly-1,并使该项为0,同时又不是被挂起的任务进入就绪状态。 6.掌握创建、请求与发送一个信号量与消息邮箱的程序流程。 7.熟练应用信号量与消息邮箱实现任务的通信与同步的程序设计。一个应用程序的基本框架。 8.了解C/OS-Ⅱ移植的一般原则。 C/OS-Ⅱ移植的条件:1在程序中可以开关中断2处理器支持中断并能产生定时中断3处理器支持中断且容纳一定数据的硬件堆栈4处理器有将堆栈指针和其他CPU存储器存储读取到堆栈的指令。 9.了解一个完整的基于C/OS-Ⅱ内核的操作系统的组成。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值