
《uCOS-II程序设计基础版本2—周立功》由会员分享,可在线阅读,更多相关《uCOS-II程序设计基础版本2—周立功(166页珍藏版)》请在文档大全上搜索。
1、第1章 C/OS-II微小内核分析 本章导读 为了方便初学者学习嵌入式实时操作系统的基本原理,作者将C/OS-II V2.52由小到大裁减为几个只具备基本功能的微小内核。 通过分析仅仅418行的操作系统最小内核,带领初学者尽快入门。 作者建议在学习或教授本章的过程中,初学者或教师要边阅读原码,边画图,深刻理解过程,因为“过程比结论更重要!”。目录概述最小内核临界区与中断管理任务的结束信号量删除信号量目录概述最小内核临界区与中断管理任务的结束信号量删除信号量1.1 概述 C/OS-II微小内核简介C/OS-II 体系结构C/OS-II与处理器无关的代码 OS_Q.COS_CORE.C OS_SE
2、M.COS_FLAG.C OS_TASK.COS_MBOX.C OS_TIME.COS_MEM.C uCOS_H.C OS_MUTEX.C uCOS_H.H CPU定时器硬 件软 件C/OS-II与处理器相关的代码 (移植时需要修改)OS_CPU.HOS_CPU_A_ASMOS_CPU_C.CC/OS-II与应用程序相关的代码OS_CFG.H INCLUDES.H用户应用程序C/OS-II C/OS-II 嵌入式实时操作系统的源代码可以分成三部分:与硬件无关的内核代码、与处理器有关的移植代码和用户配置文件。1.1 概述 C/OS-II微小内核简介内核代码 内核代码位于source目录下,提供了
3、4个微小内核。它们分别位于sourceSOURCE1(包含建立任务和延时功能)、sourceSOURCE2(增加删除任务功能)、sourceSOURCE3(增加信号量文件)和sourceSOURCE4(增加删除信号量功能)。它们的功能依次增强,代码也依次增大。 以上代码并没有完全裁减到最小,还包含了一些参数校验代码等非必需代码,C/OS-II的代码裁减功能也同时保留,这些代码大约50多行。 1.1 概述 C/OS-II微小内核简介移植代码 本书提供基于ARM的移植代码,位于arm目录下,分别为OS_CPU_C.C(移植代码C语言部分)、OS_CPU_a.S(移植代码汇编语言部分)、OS_CPU
4、.H(移植代码头文件)和IRQ.INC(移植代码与芯片无关的中断处理接口程序)4个文件。 1.1 概述 C/OS-II微小内核简介配置文件 配置文件是每个C/OS-II程序必备的文件,而且不同的程序一般不一样,但大小基本上相同。配置文件范例位于H目录下,分别为INCLUDES.H(内核需要的头文件,对于特定的移植,一般不需要改变)和OS_CFG.H(内核配置的头文件,一般需要根据程序的需求修改其常量的内容)文件。 一般来说,每个应用程序都有自己的配置文件拷贝,并很可能与范例不同。1.1 概述 函数说明 C/OS-II 微小内核SOURCE4提供OSInit函数。 函数名称函数名称OSInit
5、所属文件所属文件OS_CORE.C函数原型函数原型void OSInit(void) 功能描述功能描述初始化C/OS-,无函数参数和返回值 特殊说明特殊说明必须在调用OSStart()函数之前调用OSInit(),而只有在调用OSStart()函数之后,C/OS-才真正开始运行多任务1.1 概述 函数说明 C/OS-II 微小内核SOURCE4提供OSStart函数。 函数名称函数名称OSStart 所属文件所属文件OS_CORE.C函数原型函数原型void OSStart(void)功能描述功能描述启动C/OS-II的多任务环境,无函数参数和返回值特殊说明特殊说明在调用OSStart( )之
6、前必须先调用OSInit ( )。在用户程序中OSStart( )只能被调用一次,第二次调用OSStart( )将不执行任何操作1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSTaskCreate函数。 函数名称函数名称OSTaskCreate 所属文件所属文件OS_TASK.C函数原型函数原型INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)功能描述功能描述建立一个新任务。既可以在多任务环境启动之前,也可以在正在运行的任务中创建任务函数参数函数参数task:指
7、向任务代码的指针(函数指针) pdata:传递给任务的参数(一个变量指针)ptos :指向任务堆栈栈顶的指针 prio :任务的优先级 特殊说明特殊说明任务堆栈必须声明为OS_STK类型。注意:在中断处理程序中不能建立任务。在任务中必须调用C/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待信号量,消息邮箱、消息队列),以便其它任务也能获得CPU的使用权 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSTimeDly函数。 函数名称函数名称OSTimeDly 所属文件所属文件OS_TIME.C函数原型函数原型void OSTimeDly (INT16U tic
8、ks)功能描述功能描述将一个任务延时若干个时钟节拍,无函数返回值。延时时间的长度可从0到65535个时钟节拍,延时时间0表示不进行延时,函数将立即返回调用者,延时的具体时间依赖于系统每秒钟有多少时钟节拍(由文件OS_CFG.H中的常量OS_TICKS_PER _SEC设定) 函数参数函数参数 ticks:要延时的时钟节拍数 特殊说明特殊说明延时时间0表示不进行延时操作,而立即返回调用者。为了确保设定的延时时间,建议用户设定的时钟节拍数加1。例如,希望延时10个时钟节拍,可设定参数为11 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSTimeTick函数。 函数名称函数名称
9、OSTimeTick 所属文件所属文件OS_CORE.C函数原型函数原型void OSTimeTick(void)功能描述功能描述在每次时钟节拍中断服务程序中被调用,无函数参数和返回值。OSTimeTick()检查处于延时状态的任务是否达到延时时间,或正在等待事件的任务是否超时特殊说明特殊说明OSTimeTick()的运行时间和系统中的任务数直接相关,在任务或中断中都可以调用。如果在任务中调用,任务的优先级应该很高(优先级数字很小),这是因为OSTimeTick()负责所有任务的延时操作 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSTaskDel函数。 函数名称函数名称
10、OSTaskDel 所属文件所属文件OS_TASK.C函数原型函数原型INT8U OSTaskDel (INT8U prio)功能描述功能描述删除一个指定优先级的任务。被删除的任务将回到休眠状态,任务被删除后可以用函数OSTaskCreate()重新建立函数参数函数参数prio :指定要删除任务的优先级,如果为OS_PRIO_SELF则删除自身 函数返回值函数返回值OS_NO_ERR:函数调用成功OS_TASK_DEL_IDLE:错误,试图删除空闲任务(Idle task)OS_TASK_DEL_ ERR:错误,指定要删除的任务不存在OS_PRIO_INVALID:参数指定的优先级大于OS_L
11、OWEST_PRIOOS_TASK_DEL_ISR:错误,试图在中断处理程序中删除任务 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSIntEnter函数。 函数名称函数名称OSIntEnter 所属文件所属文件OS_CORE.C函数原型函数原型void OSIntEnter (void)功能描述功能描述通知C/OS-一个中断服务已开始执行,这有助于C/OS-掌握中断嵌套的情况。通常OSIntExit()和OSIntEnter()联合使用,无函数参数和返回值 特殊说明特殊说明在中断服务程序中,如果保证直接递增OSIntNesting“原子操原子操作作”,中断服务程序使用直
12、接递增OSIntNesting的方法而不调用OSIntEnter()函数何为原子操作?在一个任务的执行过程中,如果有某些操作何为原子操作?在一个任务的执行过程中,如果有某些操作不希望在执行过程中被别的任务或中断打断,那么这些不希不希望在执行过程中被别的任务或中断打断,那么这些不希望被打断的操作就是原子操作望被打断的操作就是原子操作1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSIntExit函数。 函数名称函数名称OSIntExit 所属文件所属文件OS_CORE.C函数原型函数原型void OSIntExit(void)功能描述功能描述通知C/OS-一个中断服务已执行完毕
13、,这有助于C/OS-掌握中断嵌套的情况。通常OSIntExit()和OSIntEnter()联合使用。当最后一层嵌套的中断执行完毕后,如果有更高优先级的任务准备就绪,C/OS-会调用任务调度函数,在这种情况下,中断返回到更高优先级的任务而不是被中断了的任务。无函数参数和返回值 特殊说明特殊说明在任务级不能调用该函数。即使中断服务程序使用直接递增OSIntNesting的方法(没有调用OSIntEnter()),也必须调用OSIntExit()函数 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供禁止/允许中断函数。 函数名称函数名称OS_ENTER_CRITICAL()和OS_
14、EXIT_CRITICAL() 所属文件所属文件移植代码函数原型函数原型由移植代码决定 功能描述功能描述一般来说,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()为定义的宏,用来禁止、打开CPU的中断,无函数参数和返回值 特殊说明特殊说明OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()必须成对使用 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSSemCreate函数。 函数名称函数名称OSSemCreate 所属文件所属文件OS_SEM.C函数原型函数原型OS_EVENT *OSSemCreate (INT16U c
15、nt)功能描述功能描述建立并初始化一个信号量函数参数函数参数cnt :建立的信号量的初始值,可以取0到65535之间的任何值函数返回值函数返回值正常 : 指向分配给所建立的信号量的事件控制块的指针NULL :没有可用的事件控制块 特殊说明特殊说明必须先建立信号量,然后使用 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSSemPend函数。 函数名称函数名称OSSemPend 所属文件所属文件OS_SEM.C函数原型函数原型void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)功能描述功能描述等待信号量:当
16、任务调用OSSemPend()函数时,如果信号量的值大于零,那么OSSemPend()函数对该值减一并返回:如果调用时信号量等于零,那么OSSemPend()函数将任务加入该信号量的等待列表,任务将等待直到获得信号量或超时 函数参数函数参数cnt :建立的信号量的初始值,可以取0到65535之间的任何值特殊说明特殊说明必须先建立信号量,然后使用,不允许在中断中调用该函数,因为中断不能被挂起 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSSemPost函数。 函数名称函数名称OSSemPost 所属文件所属文件OS_SEM.C函数原型函数原型INT8U OSSemPost
17、(OS_EVENT *pevent)功能描述功能描述发送信号量:如果指定的信号量是零或大于零,OSSemPost()函数递增该信号量并返回。如果有任务在等待信号量,则最高优先级的任务将得到信号量并进入就绪状态。然后进行任务调度,决定当前运行的任务是否仍然为处于最高优先级的就绪态的任务函数参数函数参数pevent :指向信号量的指针,OSSemCreate()的返回值函数返回值函数返回值OS_NO_ERR :发送信号量成功OS_SEM_OVF :信号量的值溢出OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针OS_ERR_PEVENT_NULL :错误,pevent为NUL
18、L 特殊说明特殊说明必须先建立信号量,然后使用 1.1 概述 函数说明C/OS-II 微小内核SOURCE4提供OSSemDel函数。 函数名称函数名称OSSemDel 所属文件所属文件OS_SEM.C函数原型函数原型OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)功能描述功能描述删除信号量:在删除信号量之前,应当删除可能会使用这个信号量的任务函数参数函数参数pevent:指向信号量的指针,OSSemCreate()的返回值opt:定义信号量删除条件 OS_DEL_NO_PEND:没有任何任务等待信号量才删除 OS_DEL
19、_ALWAYS:立即删除err:用于返回错误码特殊说明特殊说明(1)使用这个函数调用时,必须特别小心,因为其它任务可能还要用这个信号量(2)当挂起任务就绪时,中断关闭时间与挂起任务数目有关(3)其它任务并不知道信号量被删除,除非检查pevent是否指向NULL 目录概述最小内核临界区与中断管理任务的结束信号量删除信号量1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪
20、算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核 基本概念什么是任务 在实时多任务系统下运行的应用软件程序就是任务。在没有使用OS的前后台系统中,我们可以认为main函数以及通过main函数调用的全体函数为一个任务。 通常将“并行程序执行的基本逻辑单位”称之为“任务”,也就是说任务是可以被分割为独立的且可并行执行的基本逻辑单位程序。一个任务的程序是顺序执行的,而不同任务的程序却是并行执行的。任务必须包括相互“独立”和“并行”执行两个方面。1.2 最小内核 基本概念
21、独立 独立具体指任务不能彼此直接调用,也不能直接进行数据交换。 void task0 (void) task1( );void task1 (void) void task0 (void) task1( );void task1 (void) 内核通过调用调用执行任务,因此可以看成整体整体。void task0 (void) 系统调用中断内核任务任务任务通过内核内核进行任务调度和数据交换。1.2 最小内核 基本概念独立 独立具体指任务不能彼此直接调用,也不能直接进行数据交换。 void task0 (void) task1( );void task1 (void) void task0 (vo
22、id) 系统调用void task1 (void) 内核1.2 最小内核 基本概念并行执行 想象相互独立的任务各自拥有一个CPU,每个CPU各自执行各自的任务,此即任务的并行执行。但实际上CPU只有一个,我们认为操作系统为每个任务虚拟了一个CPU。void task0 (void) 可并列执行void task1 (void) 可并列执行CPUCPUvoid task0 (void) void task1 (void) C/OS-II CPU1.2 最小内核 基本概念任务的状态 在C/OS-中,任务有5种状态,分别为睡眠状态、就绪状态、运行状态、等待状态和被中断状态。 睡眠状态等待状态就绪状态
23、被中断状态运行状态任务驻留在内存中尚未创建任务已经准备好但尚未运行任务掌握CPU的控制权任务等待事件的而尚未发生中断服务程序执行打断任务1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核 案例分析P0.10P0.9LPC2000VCCLED1LED2R1R2T/s10Task10.51CPUTask0Task1TaskIdleT/s10Task00.51P0.9P0.10 在前后台系统中,一个“模块”可以调用
24、另一个“模块”,因此各模块在执行时间上相互错开,且信息传递“同步”。1.2 最小内核 案例分析 在操作系统中,程序设计就象记流水帐一样简单。主程序开始uC/OS-II初始化建立任务启动多任务环境(让任务开始执行)结束(永远不可能执行到这里)任务0初始化目标板初始化GPIO点亮LED1等待1/4秒熄灭LED1等待1/4秒任务1初始化GPIO点亮LED2等待1/3秒熄灭LED2等待1/3秒1.2 最小内核 案例分析 注意:在进入首个运行的任务之前要禁止产生任何受操作系统管理的中断,包括节拍定时器的中断。因为这类中断产生后操作系统会对任务进行扫描,并尝试进行任务切换,这将会导致程序出错,甚至引起系统
25、崩溃。所以通常将硬件初始化函数放在首个运行任务开始的地方执行。 void Task0(void *pdata) pdata = pdata; TargetInit( ); while (1) 1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核 任务控制块 C/OS-是通过任务控制块来管理任务的。任务控制块是一个基于链表的数据结构,任务控制块主要用于记录任务的堆栈栈顶指针、指向下一个任务控制块的指针、任务等待的
26、延迟时间、任务的当前状态标志与任务的优先级别等一些与任务管理有关的属性。 当任务的CPU使用权被剥夺时,C/OS-用任务控制块来保存该任务的状态,从而保证任务重新获得CPU使用权时从断点处执行。1.2 最小内核 任务控制块typedef struct os_tcb OS_STK *OSTCBStkPtr; struct os_tcb *OSTCBNext; INT16U OSTCBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; OS_TCB;
27、任务控制块定义任务控制块成员示意图OSTCBTblOSTCBStkPtrOSTCBNextOSTCBDlyOSTCBStatOSTCBPrioOSTCBXOSTCBYOSTCBBitXOSTCBBitY指向当前任务栈栈顶的指针。C/OS-允许每个任务有自己的栈,尤为重要的是,每个任务的堆栈的容量可以是任意的。指向下一个任务控制块的指针。用于任务控制块OS_TCB的链接。任务等待的延时时间变量。用于将任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。 任务的当前状态标志变量。其为0时,任务进入就绪态 。宏名定义值说明OS_STAT_RDY 0 x00 运行准备就绪 OS_STAT_SE
28、M 0 x01在信号量时挂起 OS_STAT_MBOX 0 x02在邮箱时挂起 OS_STAT_Q 0 x04在队列时挂起 OS_STAT_SUSPEND 0 x08任务被暂停 OS_STAT_MUTEX 0 x10在互斥信号量时挂起 OS_STAT_FLAG 0 x20在事件标志组时挂起 任务优先级变量。变量值越小,任务的优先级越高。 1.2 最小内核 任务控制块 C/OS-最小内核定义了4个指针、 1个数组和1个指针数组 。OSTCBCur指向“当前任务控制块”的指针;OSTCBFreeList“空任务控制块”链表的表头指针;OSTCBHighRdy 指向“将要运行最高优先级任务控制块”的
29、指针;OSTCBList“已使用任务控制块”链表的表头指针;1.2 最小内核 任务控制块OSTCBPrioTbl任务控制块优先级表,专门用来存放指向各任务控制块的指针,并按任务的优先级别将这些指针存放在数组的各个元素里。 NULLNULLNULLNULL&OSTCBTbl1&OSTCBTbl2NULLOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIO&OSTCBTbl0OSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0
30、OSTCBNextOSTCBListNULLTask0Task1OS_TaskIdleOSTCBPrioTbl指向各任务控制块的起始地址,即OSTCBStkPtr地址。 1.2 最小内核 任务控制块OSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBFreeListNULLOSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。 任务控制块
31、初始状态建立“单向空任务块链表” 链表头指针存放“节点”地址存放下一个节点地址用户数据表尾存放“空指针”1.2 最小内核 任务控制块OSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。 建立一个用户任务后的状态OSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBListNULLOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextNULLOSTCBFreeList系统空闲任务用户任务 初始
32、化空OS_TCB链表OSTCBListOSTCBNext OSTCBTbl OS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBFreeListOSTCBNextOSTCBTbl0OSTCBNextOSTCBTbl1NULLOSTCBNextOSTCBTbl2OSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIONULLNULLptcb2ptcb1 OS_TCB *ptcb1; OS_TCB *ptcb2;OSTCBList = (OS_TCB *)0; for(i=0;i(OS_LOWEST_PRIO+1);i+) OSTCBPri
33、oTbli = (OS_TCB *)0; ptcb1 = &OSTCBTbl0; ptcb2 = &OSTCBTbl1;for (i = 0; i OSTCBNext = ptcb2; ptcb1+; ptcb2+; ptcb1-OSTCBNext = (OS_TCB *)0; OSTCBFreeList = &OSTCBTbl0;NULLNULLNULLNULLNULLNULLNULLNULL1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调
34、度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核 任务就绪算法 所谓就绪状态是指任务准备运行但CPU没空,任务等待运行的状态。 任务就绪算法涉及“任务就绪表OSRdyTbl、映射表OSMapTbl、优先级判定表OSUnMapTbl以及变量OSRdyGrp和相关的任务优先级prio”,其中映射表OSMapTbl和优先级判定表OSUnMapTbl是2个常数表,用于查表算法。 优先级19的任务放入就绪表0 0 0 1 0 0 1 1任务优先级Prio0 0 0 0 0 0 0 10 0 0 0 0 0 1 00 0 0 0 0 1 0 00 0 0 0 1 0 0 00 0 0 1 0
35、0 0 00 0 1 0 0 0 0 00 1 0 0 0 0 0 01 0 0 0 0 0 0 0OSMapTbl 0123456700000000OSRdyGrpXY0000000000000000000000000000000000000000000000000000000000000000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit063626160595857565554535251504948474645444342414039383736353433323130292827262524232221201918171
36、61514131211109876543210OSRdyGrp|= OSMapTblPrio 3;OSRdyTblPrio 3 |= OSMapTblPrio & 0 x07;0000010000001000就绪的任务在任务就绪表相应位置置11映射表变量任务就绪表 优先级19的任务脱离就绪表0 0 0 1 0 0 1 1任务优先级Prio0 0 0 0 0 0 0 10 0 0 0 0 0 1 00 0 0 0 0 1 0 00 0 0 0 1 0 0 00 0 0 1 0 0 0 00 0 1 0 0 0 0 00 1 0 0 0 0 0 01 0 0 0 0 0 0 0OSMapT
37、bl 0123456700000100OSRdyGrpXY0000000000000000000000000000000000000000000010000000000000000000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210If (OSRdyTblPrio 3 &= OSMapTb
38、lPrio & 0 x07) = 0) OSRdyGrp &= OSMapTblPrio3;1111101111110111&0000100000000000=000000100&=000000000该优先级任务脱离就绪表 优先级判定表XY00000000000002n1xxxxxxx100004n2xxxxxx1000118n4xxxxx100010216n8xxxx1000011332n16xxx10000100464n32xx1000001015128n64x100000011061281000000011178线3线优先编码表INT8U const OS
39、UnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */*0 x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x40*/
40、6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x90*/ 4, 0, 1, 0,
41、2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3,
42、 0, 1, 0, 2, 0, 1, 0, /*0 xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ;优先级判定表计算48在表中的对应值?321 16 4848O 30H01101001OSRdyGrpINT8U const OSUnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */*0 x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3,
43、0, 1, 0, 2, 0, 1, 0,/*0 x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0
44、, 1, 0,/*0 x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xC0
45、*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ; 所在任务的Y值越小优先级越高,所在任务的X值越小优先级越高,由此可见最小的Y、X值所对应的任务就是进入就绪态优先级最高的的任务。 查找就绪态优先级最高
46、的任务y= OSUnMapTblOSRdyGrp;x= OSUnMapTblOSRdyTbly;Prio= (y 3) + x;XY0000000000001000000010100000000011100100000000000000000000110000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0636261605958575655545352515049484746454443424140393837363534333231302928272625242322212019181716151413121110987654
47、321001101001B 69H00110000B 30HY = 0X = 4Prio = 404Y3 就绪表初始化OSRdyGrpXYOSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210 OSRdyGrp = 0 x00; 00000000prdytbl = &OSRdyTbl0;for (
48、i=0; i1表示发生嵌套。1.2 最小内核 OS初始化 OS_InitTaskIdle()创建空闲任务函数比较重要,当所有用户任务都可能未处于就绪状态的时候,此时CPU将运行空闲任务,以防程序跑飞。 #define OS_IDLE_PRIO (OS_LOWEST_PRIO)#define OS_STK_GROWTH 1#define OS_TASK_IDLE_STK_SIZE 512 空闲任务优先级堆栈由高地址往低地址生长空闲任务堆栈大小1.2 最小内核 OS初始化void OS_TaskIdle (void *pdata) pdata = pdata; for (;) static voi
49、d OS_InitTaskIdle (void) #if OS_STK_GROWTH = 1 (void)OSTaskCreate(OS_TaskIdle, (void *)0, &OSTaskIdleStkOS_TASK_IDLE_STK_SIZE - 1, OS_IDLE_PRIO); #else (void)OSTaskCreate(OS_TaskIdle, (void *)0, &OSTaskIdleStk0, OS_IDLE_PRIO); #endif创建空闲任务空闲任务 OS初始化后状态OSTCBFreeListXYOSRdyTbl 01Bit7Bit6Bit5Bi
50、t4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl3OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBListNULL0 0 0 0
51、0 0 1 00 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 00OSIntNestingFALSEOSRunningOSTCBHighRdyNULL任务堆栈1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核 任务管理 C/OS-通过任务控制块对任务进行管理,创建任务实际上就是给任务代码分配一个任务控制
52、块,通过调用函数OSTaskCreate()实现。 任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中建立。在开始多任务调度之前,用户必须至少创建一个任务,但任务不能在中断服务程序(ISR)中建立。任务创建函数OSTaskCreate()需要4个参数:l tasktask:指向任务代码的指针,即任务函数名,指向任务的代码地址;l pdatapdata:当任务开始执行时传递给任务的参数的指针;l ptosptos:分配给任务的堆栈的栈顶指针;l prioprio:分配给任务的优先级。 1.2 最小内核 任务管理 任务管理开始同优先级任务存在标明“任务正在创建”初始化任务堆栈设置任务控制
53、块设置成功标明这个优先级的任务不存在返回错误代码返回“同优先级任务存在”已启动多任务环境调度任务返回“成功”YNYNYN创建任务流程图INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) OS_STK *psp; INT8U err; OS_ENTER_CRITICAL(); if (OSTCBPrioTblprio = (OS_TCB *)0); OSTCBPrioTblprio = (OS_TCB *)1; OS_EXIT_CRITICAL(); psp = (OS_STK *)
54、OSTaskStkInit(task, pdata, ptos, 0); err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); if (err = OS_NO_ERR) if (OSRunning = TRUE); OS_Sched(); else OS_ENTER_CRITICAL(); OSTCBPrioTblprio = (OS_TCB *)0; OS_EXIT_CRITICAL(); return (err); return (OS_PRIO_EXIST); 任务管理创建任务函数进入临界区判断优先级没占用并保留退出临
55、界区初始化任务堆栈获取任务控制块并初始化初始化成功并判断系统启动任务调度初始化不成功并清除优先级占用任务控制块初始化结果返回判断任务优先级存在返回OSTaskStkInit()OSInit()OSTaskCreate()OSStart()return 0OS_TCBInit()建立任务的堆栈,最后返回栈顶指针stk如果系统调用成功,则返回OS_NO_ERR,否则返回OS_NO_MORE_TCB,说明系统中没有OS_TCB可以分配给其它任务了main ()OSTaskCreat() 任务管理 通过分析创建任务OSTaskCreate()函数得知,OSTaskCreate()调用了OSTaskSt
56、kInit()任务堆栈初始化函数和OS_TCBInit()函数获得并初始化一个OS_TCB。 1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结 栈是限定仅在表尾进行插入与删除操作的线性表,表头端称为栈底,表尾端称为栈顶。 栈的修改是按照后进先出的原则,因此称为后进先出的线性表(简称LIFO结构)。插入元素的操作称为入栈,删除栈顶元素的操作称为出栈。1.2 最小内核 任务堆栈初始化1.2 最小内核 任务堆栈初始化 C/OS-
57、使用结构常量OS_STK_GROWTH指定堆栈的生长方式:OS_STK_GROWTH 1OS_STK_GROWTH 0ADS只支持“向下生长”的方式,且必须“满递减堆栈”内存高端内存低端堆栈增长方向栈顶栈底内存高端内存低端堆栈增长方向栈底栈顶1.2 最小内核 任务堆栈初始化堆栈初始化OSTaskStkInit()需要4个参数:l task:任务开始执行的地址,在C语言中就是任务函数名;l pdata:当任务开始执行时传递给任务的参数的指针,它应当保存到R0中;l ptos:分配给任务的堆栈栈顶指针;l otp:保留参数,目前没有使用。函数 任务堆栈初始化函数内存高端内存低端堆栈增长方向Task
58、Entrytask0000000000000 x1fpdata0PCLRR12R11R10R9R8R7R6R5R4R3R2OsEnterSumCPSRR0R1stkptosstk = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17OS_STK *OSTaskStkInit(void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) OS_STK *stk; extern void TaskEntry(void); opt = opt; stk = ptos; *stk = (OS_S
59、TK) TaskEntry; *-stk = (OS_STK) task; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = (unsigned int) pdata; *-stk = 0 x1f; *-stk = 0; return (stk);ptos = &OSTaskIdleStkOS_TASK_IDLE_STK_SIZE-11.2 最小内核q基本概念
60、q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结 任务控制块函数OS_TCBInit()用于从任务控制块链表获取并初始化一个任务控制块,再将这个任务控制块链接到任务控制块链表的头部。 当建立任务时,系统就会将空任务控制块指针OSTCBFreeList指向的任务控制块分配给该任务,然后OSTCBFreeList的值便调整为指向链表中下一个空的任务块,OSTCBList总是指向最后建立的任务控制块。1.2 最小内核 获取并初始化TCB 函数OS_TCB
61、Init()虽然具有7个参数,但只有2个参数有效,其它参数预留以后升级使用:l prio:任务的优先级;l ptos:指向任务堆栈的栈顶指针,OSTaskStkPtr()任务堆栈初始化之后,最后返回栈顶指针psp。1.2 最小内核 获取并初始化TCB 获取并初始化TCB开始有空闲TCB获得空闲TCB从空闲TCB链表删除获得的TCB初始化TCB成员将TCB加入任务就绪表中返回“成功”返回“无TCB”NY创建任务流程图 获取并初始化TCBTCB初始化OSTCBFreeListNULLOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_
62、PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl3OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBList任务堆栈1ptcbNULLptos = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17ptcb = OSTCBFreeList;OSTCBFreeList = ptcb-OSTCBNext;ptcb-OSTC
63、BStkPtr = ptos;OSTCBPrioTblprio = ptcb;ptcb-OSTCBNext = OSTCBList;OSTCBList = ptcb;假设建立一个最低优先级任务OSTCBFreeListXY0 0 0 0 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOST
64、CBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 00 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 00OSIntNestingFALSEOSRunningOSTCBHighRdyNULL任务堆栈 创建空闲任务后状态NULL#define OS_LOWEST_PRIO 9OSTCBFreeListXY0 0 0 1 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit
65、2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 10 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 0OSTCBHigh
66、RdyNULL任务堆栈 创建任务0后的状态NULLPrio 4任务堆栈OSTCBFreeListXY0 0 1 1 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 10 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 0OSTCBHighRdyNULL任务堆栈 创建任务1后的状态NULLPrio 5任务堆栈任务堆栈1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核 启动OS 多任务的启动是通过