首页 uc/os,嵌入式系统,arm

uc/os,嵌入式系统,arm

举报
开通vip

uc/os,嵌入式系统,armnull第1章 μC/OS-II微小内核分析 第1章 μC/OS-II微小内核分析 本章导读本章导读为了方便初学者学习嵌入式实时操作系统的基本原理,作者将μC/OS-II V2.52由小到大裁减为几个只具备基本功能的微小内核。 通过分析仅仅418行的操作系统最小内核,带领初学者尽快入门。 作者建议在学习或教授本章的过程中,初学者或教师要边阅读原码,边画图,深刻理解过程,因为“过程比结论更重要!”。目录目录概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量目录目录概述 最小内核 临界区与中断管理 任...

uc/os,嵌入式系统,arm
null第1章 μC/OS-II微小内核 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 第1章 μC/OS-II微小内核分析 本章导读本章导读为了方便初学者学习嵌入式实时操作系统的基本原理,作者将μC/OS-II V2.52由小到大裁减为几个只具备基本功能的微小内核。 通过分析仅仅418行的操作系统最小内核,带领初学者尽快入门。 作者建议在学习或教授本章的过程中,初学者或教师要边阅读原码,边画图,深刻理解过程,因为“过程比结论更重要!”。目录目录概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量目录目录概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量1.1 概述1.1 概述μC/OS-II微小内核简介 μC/OS-II 嵌入式实时操作系统的源代码可以分成三部分:与硬件无关的内核代码、与处理器有关的移植代码和用户配置文件。1.1 概述1.1 概述μC/OS-II微小内核简介-内核代码 内核代码位于source目录下,提供了4个微小内核。它们分别位于source\SOURCE1(包含建立任务和延时功能)、source\SOURCE2(增加删除任务功能)、source\SOURCE3(增加信号量文件)和source\SOURCE4(增加删除信号量功能)。它们的功能依次增强,代码也依次增大。 以上代码并没有完全裁减到最小,还包含了一些参数校验代码等非必需代码,μC/OS-II的代码裁减功能也同时保留,这些代码大约50多行。 1.1 概述1.1 概述μC/OS-II微小内核简介-移植代码 本书提供基于ARM的移植代码,位于arm目录下,分别为OS_CPU_C.C(移植代码C语言部分)、OS_CPU_a.S(移植代码汇编语言部分)、OS_CPU.H(移植代码头文件)和IRQ.INC(移植代码与芯片无关的中断处理接口程序)4个文件。 1.1 概述1.1 概述μC/OS-II微小内核简介-配置文件 配置文件是每个μC/OS-II程序必备的文件,而且不同的程序一般不一样,但大小基本上相同。配置文件范例位于H目录下,分别为INCLUDES.H(内核需要的头文件,对于特定的移植,一般不需要改变)和OS_CFG.H(内核配置的头文件,一般需要根据程序的需求修改其常量的内容)文件。 一般来说,每个应用程序都有自己的配置文件拷贝,并很可能与范例不同。1.1 概述1.1 概述函数说明 μC/OS-II 微小内核SOURCE4提供OSInit函数。 1.1 概述1.1 概述函数说明 μC/OS-II 微小内核SOURCE4提供OSStart函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSTaskCreate函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSTimeDly函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSTimeTick函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSTaskDel函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSIntEnter函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSIntExit函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供禁止/允许中断函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSSemCreate函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSSemPend函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSSemPost函数。 1.1 概述1.1 概述函数说明μC/OS-II 微小内核SOURCE4提供OSSemDel函数。 目录目录概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核基本概念-什么是任务 在实时多任务系统下运行的应用软件程序就是任务。在没有使用OS的前后台系统中,我们可以认为main函数以及通过main函数调用的全体函数为一个任务。 通常将“并行程序执行的基本逻辑单位”称之为“任务”,也就是说任务是可以被分割为独立的且可并行执行的基本逻辑单位程序。一个任务的程序是顺序执行的,而不同任务的程序却是并行执行的。任务必须包括相互“独立”和“并行”执行两个方面。1.2 最小内核1.2 最小内核基本概念-独立 独立具体指任务不能彼此直接调用,也不能直接进行数据交换。 void task0 (void) { task1( ); }void task1 (void) { }内核通过调用执行任务,因此可以看成整体。void task0 (void) { 系统调用 }通过内核进行任务调度和数据交换。1.2 最小内核1.2 最小内核基本概念-独立 独立具体指任务不能彼此直接调用,也不能直接进行数据交换。 ×√1.2 最小内核1.2 最小内核基本概念-并行执行 想象相互独立的任务各自拥有一个CPU,每个CPU各自执行各自的任务,此即任务的并行执行。但实际上CPU只有一个,我们认为操作系统为每个任务虚拟了一个CPU。1.2 最小内核1.2 最小内核基本概念-任务的状态 在μC/OS-Ⅱ中,任务有5种状态,分别为睡眠状态、就绪状态、运行状态、等待状态和被中断状态。 睡眠 状态等待 状态就绪 状态被中断 状态运行 状态任务驻留在内存中尚未创建任务已经准备好但尚未运行任务掌握CPU的控制权任务等待事件的而尚未发生中断服务程序执行打断任务1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核案例分析CPU Task0Task1TaskIdleP0.9P0.101.2 最小内核1.2 最小内核案例分析 在前后台系统中,一个“模块”可以调用另一个“模块”,因此各模块在执行时间上相互错开,且信息传递“同步”。 在操作系统中,程序 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 就象记流水帐一样简单。1.2 最小内核1.2 最小内核案例分析 注意:在进入首个运行的任务之前要禁止产生任何受操作系统管理的中断,包括节拍定时器的中断。因为这类中断产生后操作系统会对任务进行扫描,并尝试进行任务切换,这将会导致程序出错,甚至引起系统崩溃。所以通常将硬件初始化函数放在首个运行任务开始的地方执行。 void Task0(void *pdata) { pdata = pdata; TargetInit( ); while (1) { } }1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核任务控制块 μC/OS-Ⅱ是通过任务控制块来管理任务的。任务控制块是一个基于链表的数据结构,任务控制块主要用于记录任务的堆栈栈顶指针、指向下一个任务控制块的指针、任务等待的延迟时间、任务的当前状态 标志 禁止坐卧标志下载饮用水保护区标志下载桥隧标志图下载上坡路安全标志下载地理标志专用标志下载 与任务的优先级别等一些与任务管理有关的属性。 当任务的CPU使用权被剥夺时,μC/OS-Ⅱ用任务控制块来保存该任务的状态,从而保证任务重新获得CPU使用权时从断点处执行。1.2 最小内核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;任务控制块定义任务控制块成员示意图OSTCBStkPtrOSTCBNextOSTCBDlyOSTCBStatOSTCBPrioOSTCBXOSTCBYOSTCBBitXOSTCBBitY指向当前任务栈栈顶的指针。μC/OS-Ⅱ允许每个任务有自己的栈,尤为重要的是,每个任务的堆栈的容量可以是任意的。指向下一个任务控制块的指针。用于任务控制块OS_TCB的链接。任务等待的延时时间变量。用于将任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。 任务的当前状态标志变量。其为0时,任务进入就绪态 。任务优先级变量。变量值越小,任务的优先级越高。 1.2 最小内核1.2 最小内核任务控制块 μC/OS-Ⅱ最小内核定义了4个指针、 1个数组和1个指针数组 。OSTCBCur-指向“当前任务控制块”的指针; OSTCBFreeList-“空任务控制块”链表的表头指针; OSTCBHighRdy -指向“将要运行最高优先级任务控制块”的指针; OSTCBList-“已使用任务控制块”链表的表头指针;1.2 最小内核1.2 最小内核任务控制块OSTCBPrioTbl[]-任务控制块优先级表,专门用来存放指向各任务控制块的指针,并按任务的优先级别将这些指针存放在数组的各个元素里。 OSTCBPrioTbl[]指向各任务控制块的起始地址,即OSTCBStkPtr地址。 1.2 最小内核1.2 最小内核任务控制块OSTCBTbl[]-任务控制块数组,所有的任务控制块都保存在这个数组中。 任务控制块初始状态建立“单向空任务块链表” 链表头指针存放“节点”地址存放下一个节点地址用户数据表尾存放“空指针”1.2 最小内核1.2 最小内核任务控制块OSTCBTbl[]-任务控制块数组,所有的任务控制块都保存在这个数组中。 建立一个用户任务后的状态系统空闲任务用户任务null初始化空OS_TCB链表 OS_TCB *ptcb1; OS_TCB *ptcb2;OSTCBList = (OS_TCB *)0; for(i=0;i<(OS_LOWEST_PRIO+1);i++) { OSTCBPrioTbl[i] = (OS_TCB *)0; } ptcb1 = &OSTCBTbl[0]; ptcb2 = &OSTCBTbl[1];for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) { ptcb1 -> OSTCBNext = ptcb2; ptcb1++; ptcb2++; } ptcb1->OSTCBNext = (OS_TCB *)0; OSTCBFreeList = &OSTCBTbl[0];……1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核任务就绪算法 所谓就绪状态是指任务准备运行但CPU没空,任务等待运行的状态。 任务就绪算法涉及“任务就绪表OSRdyTbl、映射表OSMapTbl、优先级判定表OSUnMapTbl以及变量OSRdyGrp和相关的任务优先级prio”,其中映射表OSMapTbl和优先级判定表OSUnMapTbl是2个常数表,用于查表算法。null优先级19的任务放入就绪表OSRdyGrp |= OSMapTbl[Prio >> 3]; OSRdyTbl[Prio >> 3] |= OSMapTbl[Prio & 0x07];就绪的任务在任务就绪表相应位置置11null优先级19的任务脱离就绪表If ((OSRdyTbl[Prio >> 3] &= ~OSMapTbl[Prio & 0x07]) == 0) OSRdyGrp &= ~OSMapTbl[Prio>>3];&=0&=0该优先级任务脱离就绪表null优先级判定表8线-3线优先编码表INT8U const OSUnMapTbl[] = { /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ /*0x00*/ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };优先级判定表计算48在表中的对应值?32×1 + 16 = 4848O = 30HnullINT8U const OSUnMapTbl[] = { /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ /*0x00*/ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; 所在任务的Y值越小优先级越高,所在任务的X值越小优先级越高,由此可见最小的Y、X值所对应的任务就是进入就绪态优先级最高的的任务。 查找就绪态优先级最高的任务y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; Prio = (y << 3) + x;01101001B = 69H00110000B = 30HY = 0X = 4Prio = 4+→04Y<<3null就绪表初始化 OSRdyGrp = 0x00; prdytbl = &OSRdyTbl[0]; for (i=0; i1表示发生嵌套。1.2 最小内核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 最小内核1.2 最小内核OS初始化void OS_TaskIdle (void *pdata) { pdata = pdata; for (;;) { } }static void OS_InitTaskIdle (void) { #if OS_STK_GROWTH == 1 (void)OSTaskCreate(OS_TaskIdle, (void *)0, &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], OS_IDLE_PRIO); #else (void)OSTaskCreate(OS_TaskIdle, (void *)0, &OSTaskIdleStk[0], OS_IDLE_PRIO); #endif }创建空闲任务空闲任务nullOS初始化后状态1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核任务管理 μC/OS-Ⅱ通过任务控制块对任务进行管理,创建任务实际上就是给任务代码分配一个任务控制块,通过调用函数OSTaskCreate()实现。 任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中建立。在开始多任务调度之前,用户必须至少创建一个任务,但任务不能在中断服务程序(ISR)中建立。1.2 最小内核任务创建函数OSTaskCreate()需要4个参数: task:指向任务代码的指针,即任务函数名,指向任务的代码地址; pdata:当任务开始执行时传递给任务的参数的指针; ptos:分配给任务的堆栈的栈顶指针; prio:分配给任务的优先级。 1.2 最小内核任务管理null任务管理-创建任务 流程 快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计 图nullINT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) { OS_STK *psp; INT8U err; OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] == (OS_TCB *)0);{ OSTCBPrioTbl[prio] = (OS_TCB *)1; OS_EXIT_CRITICAL(); psp = (OS_STK *)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(); OSTCBPrioTbl[prio] = (OS_TCB *)0; OS_EXIT_CRITICAL(); } return (err); } return (OS_PRIO_EXIST); }任务管理-创建任务函数null任务管理 通过分析创建任务OSTaskCreate()函数得知,OSTaskCreate()调用了OSTaskStkInit()任务堆栈初始化函数和OS_TCBInit()函数获得并初始化一个OS_TCB。 1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核 栈是限定仅在表尾进行插入与删除操作的线性表,表头端称为栈底,表尾端称为栈顶。 栈的修改是按照后进先出的原则,因此称为后进先出的线性表(简称LIFO结构)。插入元素的操作称为入栈,删除栈顶元素的操作称为出栈。1.2 最小内核任务堆栈初始化1.2 最小内核1.2 最小内核任务堆栈初始化 μC/OS-Ⅱ使用结构常量OS_STK_GROWTH指定堆栈的生长方式:OS_STK_GROWTH = 1OS_STK_GROWTH = 0ADS只支持“向下生长”的方式,且必须“满递减堆栈”1.2 最小内核1.2 最小内核任务堆栈初始化堆栈初始化OSTaskStkInit()需要4个参数: task:任务开始执行的地址,在C语言中就是任务函数名; pdata:当任务开始执行时传递给任务的参数的指针,它应当保存到R0中; ptos:分配给任务的堆栈栈顶指针; otp:保留参数,目前没有使用。-函数null任务堆栈初始化-函数TaskEntrytask0000000000000x1fpdata0PCLRR12R11R10R9R8R7R6R5R4R3R2OsEnterSumCPSRR0R1stk = &OSTaskIdleStk [(OS_TASK_IDLE_STK_SIZE-1)-17]OS_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_STK) 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 = 0x1f; *--stk = 0; return (stk); }ptos = &OSTaskIdleStk [OS_TASK_IDLE_STK_SIZE-1]1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核 任务控制块函数OS_TCBInit()用于从任务控制块链表获取并初始化一个任务控制块,再将这个任务控制块链接到任务控制块链表的头部。 当建立任务时,系统就会将空任务控制块指针OSTCBFreeList指向的任务控制块分配给该任务,然后OSTCBFreeList的值便调整为指向链表中下一个空的任务块,OSTCBList总是指向最后建立的任务控制块。1.2 最小内核获取并初始化TCB1.2 最小内核 函数OS_TCBInit()虽然具有7个参数,但只有2个参数有效,其它参数预留以后升级使用: prio:任务的优先级; ptos:指向任务堆栈的栈顶指针,OSTaskStkPtr()任务堆栈初始化之后,最后返回栈顶指针psp。1.2 最小内核获取并初始化TCBnull获取并初始化TCB-创建任务流程图null获取并初始化TCB-TCB初始化ptos = &OSTaskIdleStk [(OS_TASK_IDLE_STK_SIZE-1)-17]ptcb = OSTCBFreeList; OSTCBFreeList = ptcb->OSTCBNext; ptcb->OSTCBStkPtr = ptos; OSTCBPrioTbl[prio] = ptcb; ptcb->OSTCBNext = OSTCBList; OSTCBList = ptcb;假设建立一个最低优先级任务null创建空闲任务后状态#define OS_LOWEST_PRIO 9null创建任务0后的状态Prio = 4null创建任务1后的状态Prio = 51.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核启动OS 多任务的启动是通过调用OSStart()函数实现的,启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务。void OSStart (void) { INT8U y; INT8U x; if (OSRunning == FALSE) { y = OSUnMapTbl[OSRdyGrp]; x = OSUnMapTbl[OSRdyTbl[y]]; OSPrioHighRdy = (INT8U)((y << 3) + x); OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OSTCBCur = OSTCBHighRdy; OSStartHighRdy(); } }OSStartHighRdy()永远将不会返回,它只执行一次。1.2 最小内核EXPORT __OSStartHighRdy void OSStartHighRdy(void) { _OSStartHighRdy(); }1.2 最小内核启动OS OSStartHighRdy()函数位于OS_CPU_C文件中,其实际是通过调用_OSStartHighRdy()函数实现功能。由于C语言不能直接调用汇编代码,必须经过“SWI软中断异常”实现。1.2 最小内核__OSStartHighRdy MSR CPSR_c, #(NoInt | SYS32Mode) LDR R4, =OSRunning MOV R5, #1 STRB R5, [R4] LDR R6, =OSTCBHighRdy LDR R6, [R6]1.2 最小内核启动OS&OSTCBTbl[1]&OSTCBTbl[1]44TRUEFALSE假设已建立空闲任务、Task1和 Task0,优先级分别为9、5、4 R6=&OSTCBTbl[1]1.2 最小内核1.2 最小内核启动OS&OSTCBTbl[1]&OSTCBTbl[1]44TRUER6=&OSTCBTbl[1]OSIntCtxSw_1 LDR R4, [R6] ADD SP, R4, #68 LDR LR, [SP, #-8] MSR CPSR_c, #(NoInt | SVC32Mode) MOV SP, R4 LDMFD SP!, {R4, R5} LDR R3, =OsEnterSum STR R4, [R3] MSR SPSR_cxsf, R5 LDMFD SP!, {R0-R12, LR, PC }^R4=OSTCBStkPtr栈 顶OSTCBStkPtr指向栈顶位置0x04Task00x48R4=OSEnterSum R5=CPSR0x04CPSR0x0CTaskEntry0000CPSR再通过执行 EXPORT TaskEntry TaskEntry BX R14 程序跳到Task0运行null启动OS 在调用OSStart()之后首先启动新任务Task0,然后执行目标板初始化函数TargetInit(),接着初始化VIC中断向量控制器和Timer0定时器并产生周期性的中断。1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核TargetInit 初始化 μC/OS-Ⅱ要求在多任务环境启动之前不允许产生中断,所以通常会在第一个执行的任务中调用函数TargetInit()初始化中断系统和能够产生中断的外设。 因为这些代码都与中断有关,所以必须禁止中断以保证程序执行正确。 void TargetInit(void) { OS_ENTER_CRITICAL(); VICInit(); Timer0Init(); OS_EXIT_CRITICAL(); }1.2 最小内核1.2 最小内核TargetInit 初始化 TargetInit()目标板初始化包括其它初始化代码、VICInit()初始化、Timer0Init()初始化与其它外设初始化。 1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核时间管理 任务可以通过调用系统服务函数OSTimeDly()申请一段时间(即等待时间事件)。 调用该函数会使操作系统进行一次任务调度,并且执行下一个处于就绪态优先级最高的任务。 函数OSTimeDly()仅有一个参数ticks表明任务需要延时的时间,以系统时钟节拍为单位。1.2 最小内核void OSTimeDly (INT16U ticks) { if (ticks > 0) { OS_ENTER_CRITICAL(); if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBDly = ticks; OS_EXIT_CRITICAL(); OS_Sched(); } }1.2 最小内核时间管理1.2 最小内核1.2 最小内核时间管理 如果ticks为0,则表明用户不想延时任务,函数会立即返回到调用者;如果ticks非0,则将当前任务从就绪表中删除。与此同时将ticks延时节拍数保存到当前任务的OS_TCB中,然后进行一次任务调度,并且执行下一个优先级最高的处于就绪态的任务。 1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核任务调度 μC/OS-Ⅱ内核采用了“可剥夺型”任务调度算法,μC/OS-Ⅱ总是运行处于就绪态中优先级最高的任务,具体是通过调度器(Scheduler)实现。 任务级的任务调度由OS_Sched()函数完成,而中断级的任务调度由OSIntExt()函数完成。1.2 最小内核1.2 最小内核任务调度void OS_Sched (void) { INT8U y; OS_ENTER_CRITICAL(); if (OSIntNesting == 0) { y = OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); if (OSPrioHighRdy != OSPrioCur) { OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OS_TASK_SW(); } } OS_EXIT_CRITICAL(); }nullTask0从就绪表删除后的任务调度1054&OSTCBTbl[1]&OSTCBTbl[2]5&OSTCBTbl[2]当前还是运行Task0&OSTCBTbl[2]&OSTCBTbl[1]&OSTCBTbl[0]1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核SWI软件中断异常 由于C语言程序不能直接调用汇编程序,因此必须制定一个调用接口 规范 编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载 。为了使底层接口函数与处理器状态无关,同时在任务调用相应的函数时也不需要知道该函数的确切位置,那么解决上述问题的方法之一就是使用ARM7的软中断SWI作为底层接口,使用不同的功能号区分不同的函数。1.2 最小内核1.2 最小内核SWI软件中断异常 ADS编译器规定,用户可以使用关键字__swi作为前缀来声明一个利用软件中断的调用,那么就在调用这个函数的地方插入一条SWI指令,并且可以指定功能号。 关键字__swi后面的括号中的字段叫作软件中断功能编号,即汇编指令swi中的立即数,系统可以根据这个编号在软件中断管理程序中确定应该执行的程序段。_swi(功能号) 返回值 名称(列表)1.2 最小内核1.2 最小内核SWI软件中断异常 为了进一步提高效率,最小内核没有使用功能编号,而是使用第一个参数的数值(保存在R0中)来区分不同的功能。__swi(0x00) void OsSwiHandle1(int Handle); #define OS_TASK_SW() OsSwiHandle1(0) #define _OSStartHighRdy() OsSwiHandle1(3) #define OS_ENTER_CRITICAL() OsSwiHandle1(1) #define OS_EXIT_CRITICAL() OsSwiHandle1(2)MOV R0, #0 SWI 0 编译器编译成汇编指令null&OSTCBTbl[2]&OSTCBTbl[1]54TRUE假设优先级为4的Task0挂起,那么 当前最高优先级5的Task1将运行, 此间将进行任务切换。 任务级的任务调度TASK_SW MRS R3, SPSR MOV R2, LR MSR CPSR_c, #(NoInt | SYS32Mode) STMFD SP!, {R2} STMFD SP!, {R0-R12, LR} B OSIntCtxSw_0&OSTCBTbl[2]CPSRPC+4SoftwareInterrupt TASK_SW +0x48R3=SPSR_svcR2=PC+4PC+4+0x44LRR12R11…R1R0+0x0Cnull&OSTCBTbl[2]&OSTCBTbl[1]54TRUE假设优先级为4的Task0挂起,那么 当前最高优先级5的Task1将运行, 此间将进行任务切换。 任务级的任务调度&OSTCBTbl[2]CPSRPC+4PC+4LRR12R11…R1R0OSIntCtxSw_0 LDR R1, =OsEnterSum LDR R2, [R1] STMFD SP!, {R2, R3} LDR R1, =OSTCBCur LDR R1, [R1] STR SP, [R1]R3=SPSR_svcCPSROsEnterSum+0x0C+0x045 LDR R4, =OSPrioCur LDR R5, =OSPrioHighRdy LDRB R6, [R5] STRB R6, [R4] LDR R6, =OSTCBHighRdy LDR R6, [R6] LDR R4, =OSTCBCur STR R6, [R4]OS已经切换到Task1,启动过程见“OS启动”1.2 最小内核1.2 最小内核基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结1.2 最小内核1.2 最小内核任务级的任务调度小结Task0()IO2SET |= LED1OSTimeDly()IO2SET |= LED2OSTimeDly()启动OS后,执行Task0目标板初始化执行延时函数执行就绪优先级最高的Task1调用任务级任务调度函数将当前任务从就绪表删除调用任务级任务调度函数将当前任务从就绪表删除执行延时函数执行空闲任务,等待Task0和Task1就绪目录目录概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量1.3 临界区与中断管理1.3 临界区与中断管理可重入性 案例分析 允许/禁止中断 时钟节拍中断服务程序 中断管理 中断级的任务调度小结1.3 临界区与中断管理1.3 临界区与中断管理可重入性 案例分析 允许/禁止中断 时钟节拍中断服务程序 中断管理 中断级的任务调度小结1.3 临界区与中断管理1.3 临界区与中断管理可重入性 可重入的代码指的是一段代码可以被多个任务同时调用,而不必担心数据被破坏。即就是说,可重入型函数在任何时候都可以被打断,一段时间以后又可以继续运行,而相应数据却不会丢失。可重入型函数或者只使用局部变量,即变量保存在CPU寄存器或堆栈中。如果使用全局变量,则要对全局变量予以保护。由此可见,代码的可重入性是保证完成多任务的基础。1.3 临界区与中断管理1.3 临界区与中断管理可重入性 案例分析 允许/禁止中断 时钟节拍中断服务程序 中断管理 中断级的任务调度小结1.3 临界区与中断管理1.3 临界区与中断管理案例分析void Task0(void *pdata) { …… while (1) { OS_ENTER_CRITICAL(); if (sum1 != sum2) { if ((i % 2) == 0) IO2CLR = LED2; else IO2SET = LED2; i++; } OS_EXIT_CRITICAL(); OSTimeDly(OS_TICKS_PER_SEC / 8); } }void Task1(void *pdata) { …… while (1) { OS_ENTER_CRITICAL(); sum1++; sum2++; OS_EXIT_CRITICAL(); } }删除红色部分代码,LED2闪烁,为什么? μC/OS-Ⅱ至少有一个周期性的中断用于调用时钟节拍函数OSTimeTick()。它的抢占特性使这个中断返回时有可能进行任务切换,让运行让高优先级任务运行。 红色部分
本文档为【uc/os,嵌入式系统,arm】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_624411
暂无简介~
格式:ppt
大小:7MB
软件:PowerPoint
页数:0
分类:互联网
上传时间:2009-04-05
浏览量:33