嵌入式系统开发与应.ppt
嵌入式系统开发与应用,重庆交通大学信息科学与工程学院许强,主要内容,1.从芯片到系统硬件环境设计;要求:熟悉芯片的工作特点,CAD设计;目标:搭建应用硬件系统。2.内嵌uC/OS-II操作系统的嵌入式系统设计;要求:熟悉uC/OS-II操作系统内部运行特点;目标:设计嵌入式的软件系统。3.内嵌Linux(uClinux)操作系统的嵌入式系统设计。要求:了解Linux(uClinux)操作系统内部运行原理;熟悉开 发平台的搭建过程。目标:开发嵌入Linux(uClinux)的嵌入式应用系统。,学习要求,课前预习教材按时上课,认真听讲研读参考书和参考网站整理笔记,认真思考,积极讨论,善于发现问题、提出问题并努力寻求问题的答案。结合嵌入式系统专题学习网站丰富的教学资源,努力寻求问题的答案,掌握基本原理,拓展知识,延伸视野,提高分析问题和解决问题的能力。,考核方式,平时考勤占20%,作业占10%,实验占20%考试占50%考勤有6次上,参考书,Labrosse Jean J.嵌入式实时操作系统uC/OS-II(第2版),邵贝贝等译.北京:北京航空航天大学出版社,2003.汤子瀛等,计算机操作系统,西安电子科技大学南京大学孙钟秀院士,操作系统教程第三版,高等教育出版社Silberschatz,操作系统概念(中、英文)第六版,高等教育出版社,题外之言,态度决定一切-前国家足球队教练米卢考试只是手段,掌握知识才是关键。本课的重点在于宏观理解计算机系统,扩大知识面。交流、合作是成功的关键向他人公开你的见解和问题,勇于提出问题。通过报纸、杂志、书籍和网络查阅相关文献。对本专业来讲:活到老、学到老,时时更新自己的知识。,不要将自己置于尴尬境地,一.从芯片到系统硬件环境设计;,最小系统外存储芯片的组织网络芯片的组织与应用USB芯片的组织与应用LCD显示器的组织应用触摸屏的应用。,二.内嵌uC/OS-II操作系统的嵌入式系统设计;,uC/OS-II操作系统的原理uC/OS-II操作系统的应用设计,嵌入式实时操作系统uC/OS-II原理及应用,基本内容:基本概念、uC/OS-II的任务构架、任务的实现特点;uC/OS-II的移植操作;具体uC/OS-II操作系统的裁剪;,重点:基本概念、uC/OS-II的任务构架、任务的实现特点及具体应用编程;,为什么要学习操作系统,设计操作系统或者修改现有的系统存在们意识不到的大量“操作系统”,嵌入式系统(Embedded OS)加深对使用的OS的理解,有利于深入编程用户为了开发应用程序必须与操作系统打交道编程时借鉴操作系统的设计思想和算法选择购实操作系统我并不总使用Win95/NT/2000/XP操作系统中所用的许多概念和技巧可以推广应用到其它领域,第1章嵌入式实时操作系统的基本概念,什么是计算机操作系统?什么是批处理操作系统?什么是分时操作系统?什么是实时操作系统?监控程序与实时操作系统?什么是嵌入式操作系统?嵌入式系统与嵌入式操作系统?,计算机操作系统,系统软件、计算机硬件、软件资源的管理者。管理对象包括:CPU、存储器、外部设备、信息(数据和软件);管理的内容:资源的当前状态(数量和使用情况)、资源的分配、回收和访问操作,相应管理策略(包括用户权限)。用户使用系统硬件、软件的接口系统命令(命令行、菜单式、命令脚本式、图形用户接口GUI);系统调用(形式上类似于过程调用,在应用编程中使用)。,在裸机上添加:设备管理、文件管理、存储管理(针对内存和外存)、处理机管理(针对CPU);合理组织工作流程:作业管理、进程管理。,批处理操作系统,作业的处理流程作业提交:作业的输入;作业执行作业完成:作业的输出;,图1 批处理系统中作业处理及状态,分时操作系统,把计算机的系统资源(尤其是CPU时间)进行时间上的分割,每个时间段称为一个时间片(time slice),每个用户依次轮流使用时间片。分时特征如下:,多路性:多个用户同时工作。共享系统资源,提高了资源利用率。节省维护开支,可靠性高:终端的概念至今仍在使用。促进了计算机的普遍应用,提高资源利用率:远地用户通过终端(较便宜)联机使用。独立性:各用户独立操作,互不干扰。交互性:系统能及时对用户的操作进行响应,显著提高调试和修改程序的效率:缩短了周转时间。,实时操作系统,实时操作系统主要用于过程控制、事务处理等有实时要求的领域,其主要特征是实时性和可靠性。,实时系统的特征实时时钟管理:提供系统日期和时间、定时和延时等时钟管理功能;过载保护:缓冲区排队,丢弃某些任务,动态调整任务周期;过载是指进入系统的任务数目超出系统的处理能力。高度可靠性和安全性:容错能力(如故障自动复位)和冗余备份(双机,关键部件);,实时系统与批处理系统和分时系统的区别,专用性质:许多实时系统是专用系统,而批处理与分时系统通常是通用系统。实时控制:实时系统用于控制实时过程,要求对外部事件的迅速响应,具有较强的中断处理机构。高可靠性:实时系统用于控制重要过程,要求高度可靠,具有较高冗余。如双机系统。事件驱动和队列驱动:实时系统的工作方式:接受外部消息,分析消息,调用相应处理程序进行处理。可与通用系统结合成通用实时系统:实时处理前台作业,批处理为后台作业。,监控程序与实时操作系统,监控程序:是最原始的低端单片机管理程序,由应用程序员自行编制;用户通过监控程序提高计算机的资源利用率,但这种利用是有限的。随着计算机技术的发展,计算机的硬件、软件资源愈来愈丰富,监控程序已不能高效支持,在此需求下不得不采用管理功能更全面的操作系统来完成。,操作系统的服务,服务类型程序执行和终止(包括分配和回收资源)I/O操作文件系统操作通信:本机内,计算机之间(通常通信服务的使用者为进程,而不是笼统说主机)配置管理:硬件、OS本身、其他软件差错检测服务提供方式:系统命令和系统调用,早期低端嵌入式系统工作特点,传统的前/后台方式,不复杂的小系统常采用前/后台方式进行程序操作,整个程序为一个大循环体。其中前台为中断级,时间相关性很强的关键操作放在前台执行。后台为任务级,用于处理前台产生的各种信息。,前后台系统,后台程序:系统后台程序按顺序执行各种动作,通常用于处理前台产生的各种信息。,前台程序:前台为中断服务程序,用于响应外部事件,并产生一些信息提供给后台处理。,前后台系统的优缺点,嵌入式操作系统,运行在嵌入式硬件平台上,对整个系统及其所操作的部件、装置等资源进行统一协调、指挥和控制的系统软件。嵌入式操作系统以微内核为主,其它诸如窗口系统界面、文件管理模块、通信协议等还要由开发人员自已设计或者外购。内核大多数只提供内存管理、多任务管理、外围资源管理。,嵌入式操作系统,电子消费产品-家用电器、手机、武器、控制设备嵌入式(计算机)系统硬件不再以物理上独立的装置或设备形式出现,而是大部分甚至全部都隐藏和嵌入到各种应用系统中。特点:微型化-可用内存小(1MB以内、没有外存、微处理器字长短且运算速度有限、能提供的能源较少、外部设备和被控设备千变万化)可定制-专业化(剪裁性)实时性-语音、视频、军事武器、航空航天、交通运输可靠性易移植性,嵌入式系统与嵌入式操作系统,嵌入式系统是基于单片机系统嵌入到对象系统的整合,实现对象的智能化控制。因此要求具有专用性、微小化、控制的可靠性高、低功耗和成本低等特点。跟随嵌入式系统的完备管理,提出嵌入式操作系统,特点是异常响应时间可确定、程序微小化且可靠、可裁剪和易移植性等。,嵌入式操作系统的现状,VxWorks、pSOSWindows CEQNX OSuC/OS-IIuCLinuxLinux,C/OS-II原理及应用,C/OS-II简介工作原理C/OS-II移植简介C/OS-II使用初步,C/OS-II简介工作原理C/OS-II移植简介C/OS-II使用初步,C/OS-II原理及应用,C/OS-II简介,概述,C/OS-II读做“micro C O S 2”,意为“微控制器操作系统版本2”。C/OS-II是源码公开的著名实时内核,可用于各类8位、16位和32位单片机或DSP。从C/OS算起,该内核已有10多年应用史,在诸多领域得到广泛应用。C/OS-II是一个完整的、可移植、可固化、可剪裁的占先式实时多任务内核。C/OS-II使用ANSI C语言编写,包含一小部分汇编代码,使之可以供不同架构的微处理器使用。至今,从8位到64位,C/OS-II已在超过40种不同架构的微处理器上运行。,C/OS-II特点,提供源代码:购买作者撰写的嵌入式实时操作系统C/OS-II一书即可获得C/OS-II V2.52版本的所有源代码,购买此书的其它版本可以获得相应版本的全部源代码。可移植性(portable):C/OS-II的源代码绝大部分是使用移植性很强的ANSI C写的,将与微处理器硬件相关的汇编语言使用量压缩到最低的限度,以使C/OS-II便于移植到其它微处理器上。目前,C/OS-II已经被移植到多种不同架构的微处理器上。可固化(ROMmable):只要具备合适的软硬件工具,就可以将C/OS-II嵌入到产品中成为产品的一部分。可剪裁(scalable):C/OS-II使用条件编译实现可剪裁,用户程序可以只编译自己需要的(C/OS-II的)功能,而不编译不要需要的功能,以减少C/OS-II对代码空间和数据空间的占用。可剥夺(preemptive):C/OS-II是完全可剥夺型的实时内核,C/OS-II总是运行就绪条件下优先级最高的任务。,C/OS-II特点,多任务:C/OS-II可以管理64个任务,然而,C/OS-II的作者建议用户保留8个给C/OS-II。这样,留给用户的应用程序最多可有56个任务。可确定性:绝大多数C/OS-II的函数调用和服务的执行时间具有确定性,也就是说,用户总是能知道C/OS-II的函数调用与服务执行了多长时间。任务栈:C/OS-II的每个任务都有自己单独的栈,使用C/OS-II的占空间校验函数,可确定每个任务到底需要多少栈空间。系统服务:C/OS-II提供很多系统服务,例如信号量、互斥信号量、时间标志、消息邮箱、消息队列、块大小固定的内存的申请与释放及时间管理函数等。中断管理:中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被中断唤醒,则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255层。,C/OS-II特点,稳定性与可靠性:C/OS-II是C/OS的升级版,C/OS自1992年以来已经有数百个商业应用。C/OS-II与C/OS的内核是一样的,只是提供了更多的功能。2000年7月,C/OS-II在一个航空项目中得到了美国联邦航空管理局对商用飞机的、符合RTCA DO 178B标准的认证。这表明,该操作系统的质量得到了认证,可以在任何应用中使用。,作者及其著作,uC/OS-II的体系结构,练习题,1、什么是计算机的操作系统?它应该具备什么功能?2、简述嵌入式系统与普通操作系统的区别?3、观察人们日常生活中嵌入式系统的应用?4、什么是实时系统?试列举几个日常生活中的实时系统?,第2章 uC/OS-II中的任务,uC/OS-II操作系统内核的主要工作就是对任务进行管理。,本章的主要内容有:uC/OS-II任务引入;任务的基本概念,用户任务和系统任务;任务代码、任务控制和任务堆栈;任务的优先权及表示任务优先权的参数;任务就绪表结构及操作;任务切换及任务调度;任务的创建、删除、挂起、恢复和查询;uC/OS-II的初始化和启动。,uC/OS-II多任务管理,多任务操作系统,多任务运行的实现实际上是靠CPU在许多任务之间转换和调度。CPU只有一个,轮番服务于一系列任务中的某一个。多任务运行使CPU的利用率达到最高,并使应用程序模块化。最大特点是,开发人员可以将很复杂的应用程序层次化,程序将更容易设计和维护。,多任务系统工作原理,产生系统运作所必需的节拍,调度程序对所有任务进行运行控制,多任务系统工作原理,任务1,任务2,.,空闲任务,信号量,邮箱,内存管理,数据队列,最多支持64个任务;空闲任务一定存在,当所有任务都不运行时才运行空闲任务;所有任务都有不同的优先级,优先级为0表示最高,空闲任务优先级最低;任务之间的通信通过ucos提供的各种事件机制进行。,多任务系统工作原理,操作系统调度程序,CPU资源,操作系统的调度程序对所有任务实现运行控制;任务切换实际就是把当前任务所占用的CPU资源用其它任务来替换;CPU资源包括寄存器R0-R15、CPSR、SPRS和其它一些全局变量;调度程序由系统节拍驱动。,2.1 任务的基本概念,任务是具有规定执行时间的一段程序代码。由于任务运行时是完全占有CPU时间片,因此可认为是一个“线程”。从应用程序的角度来看,uC/OS-II的任务就是一个线程,就是C语言函数和与之相关联的数据结构构成的实体。从任务的存储结构来看,uC/OS-II的任务由三个组成部分构成:任务程序代码、任务堆栈和任务控制块。,(a)任务的组成,任务的代码Void mytask(void*pdata)For(;),任务,(b)任务链表,图2-1 uC/OS-II的任务在内存中的结构,2.1.1 任务的状态,uC/OS-II中的5种状态:睡眠状态:就绪状态:运行状态:等待状态:中断服务状态:,2.1.1 任务的状态,uC/OS-II中的5种状态:睡眠状态:就绪状态:运行状态:等待状态:中断服务状态:,任务只是以代码的形式驻留在程序空间(ROM或RAM),还没有交给操作系统管理时的情况叫做睡眠状态。简言之就是在内存中的无任务控制块的任务。OSTaskDel()OSTaskCreate()OSTaskCreateExt(),2.1.1 任务的状态,uC/OS-II中的5种状态:睡眠状态:就绪状态:运行状态:等待状态:中断服务状态:,任务配备了任务控制块且在任务就绪表中进行了就绪登记,任务具备了运行充分条件,这是的任务状态叫就绪状态。OSTaskCreate()OSTaskCreateExt()OSFlagPost()OSMboxPost()OSMboxPostOpt()OSMutexPost()OSQPost()OSQPostFront()OSQPostOpy()OSSemPost()OSTaskResume()OSTimeTick()OSStart()OsIntExit()OS_TASK_SW(),2.1.1 任务的状态,uC/OS-II中的5种状态:睡眠状态:就绪状态:运行状态:等待状态:中断服务状态:,处于就绪状态的任务如果经调度器判断获得了CPU的的使用权,则任务就进入运行状态。任何时刻只能有一个任务处于运行状态,就绪的任务只有当所有优先级高于本任务的任务都转为等待状态时,才进入运行状态。OSStart()OsIntExit()OS_TASK_SW(),2.1.1 任务的状态,uC/OS-II中的5种状态:睡眠状态:就绪状态:运行状态:等待状态:中断服务状态:,正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的使用权让给其他任务而使任务进入等待状态。OSFlagPend()OSMboxPend()OSMutexPend()OSQPend()OSSemPend()OSTaskSuspend()OSTimeDly()OSTimeDlyHMSM(),2.1.1 任务的状态,uC/OS-II中的5种状态:睡眠状态:就绪状态:运行状态:等待状态:中断服务状态:,一个正在运行的任务一旦响应中断申请就会中止运行而去执行中断服务程序,这时任务的状态叫做中断服务状态。,任务的运行状态,每个任务都有确定的状态,而同时只能是一个任务占有CPU;拥有运行权的任务一定是就绪任务中优先级最高的。,睡眠状态,就绪状态,运行状态,等待状态,ISR,用户任务代码的一般结构,1.任务一般结构任务的执行代码通常是一个无限循环结构,并且在这个循环中可以响应中断,这种结构也叫超循环结构。,例2-1:一个用C语言编写的任务Void MyTask(Void*pdata)for(;)可以被中断的用户代码;OS_ENTER_CRITICAL();/进入临界段(关中断)不可以被中断的用户代码;OS_EXIT_CRITICAL();/退出临界(开中断)可以被中断的用户代码;,2、用户应用程序的一般结构,要在自己的系统中使用C/OS-II编写自己的应用程序,就必须遵守C/OS-II的编程规范。主要包括主函数和用户任务,它们的关系如下。,编写应用程序,根任务,目标板初始化(启动系统时钟),创建其它的任务,执行任务循环,任务1,执行特定操作,执行任务循环,任务n,执行特定操作,执行任务循环,.,要在自己的系统中使用C/OS-II编写自己的应用程序,就必须遵守C/OS-II的编程规范。主要包括主函数和用户任务,它们的关系如下。,编写应用程序,#include config.hOS_STK TaskStartStkTASK_STK_SIZE;OS_STK TaskStkTASK_STK_SIZE;int main(void)OSInit();OSTaskCreate(Task1,(void*)0,编写应用程序,void Task1(void*pdata)pdata=pdata;/*避免编译警告*/TargetInit();/*目标板初始化*/for(;)OSTimeDly(OS_TICKS_PER_SEC/50);if(GetKey()!=KEY1)continue;OSTimeDly(OS_TICKS_PER_SEC/50);if(GetKey()!=KEY1)continue;OSTaskCreate(Task2,(void*)0,将该任务放在循环中创建,是因为该任务执行一次后会自行删除,编写应用程序,/任务功能:鸣叫两声,然后删除自己void Task2(void*pdata)pdata=pdata;/*避免编译警告*/BeeMoo();/*使蜂鸣器鸣叫*/*延时*/OSTimeDly(OS_TICKS_PER_SEC/8);BeeNoMoo();/*使蜂鸣器停止鸣叫*/OSTimeDly(OS_TICKS_PER_SEC/4);BeeMoo();/*延时*/OSTimeDly(OS_TICKS_PER_SEC/8);BeeNoMoo();/*使蜂鸣器停止鸣叫*/OSTaskDel(OS_PRIO_SELF);/*删除自己*/,2.1.3 系统任务,uC/OS-II预定义了:空闲任务和统计任务。1.空闲任务OSTaskIdle()空闲任务:运行系统中无应用任务时,uC/OS-II提供的一个占用CPU的任务,且级别最低,任何有用任务都可抢占这一任务,这一任务叫空闲任务。空闲任务不能用软件删除。,Void OSTaskIdle(void*pdata)#if OS_CRITICAL_METHOD=3 OS_CPU_SR cpu_sr;#endif pdata=pdata;/防编择器报错 for(;)OS_ENTER_CRITICAL();/关闭中断 OSdleCtr+;/计算 OS_EXIT_CRITICAL();/开放中断,2.1.3 系统任务,2.统计任务OSTaskStat()统计任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCPUsage中。因此叫统计任务。操作:OS_CFG.H中的常数OS_TASK_STAT_EN=1;调用OSStatInit()对统计任务初始化。,2.1.4 任务的优先权及优先级别,uC/OS-II的每个任务都必须具有一个惟一的优先级别。64级,0为最高级;数字越大级别越低。OS_CFG.H中OS_LOWEST_PRIO表示最低级别的常数。总数可为OS_LOWEST_PRIO+1个。除了系统任务两个外,应用任务可用OS_LOWEST_PRIO-1个任务。创建任务时,用OSTaskCreate()中第4个参数prio来指定。INT8U OSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT8U prio)OSTaskCreate(Task2,(void*)0,&TaskStkTASK_STK_SIZE-1,10),2.2 任务堆栈,堆栈:满足后进先出(LIFO)访问数据的存储结构。作用:快速保存保护数据(寄存器内容等)。,2.2.1 任务堆栈的创建,在文件OS_CPU.H中定义了一个数据类型OS_STK:typedef INT32U OS_STK;/*堆栈是32位宽度*/或Typedef unsigned int OS_STK;/*16位*/这样,在应用程序中定义任务堆栈区就非常简单,即定义一个OS_STK类型的一个数组即可。例如:#define TASK_STK_SIZE 512/定义堆栈的长度(1024B)OS_STK TaskStkTASK_STK_SIZE;/定义数组为任务堆栈当调用OSTaskCreate()创建一个任务时,数组的指针传递函数中第3个ptos参数,关联任务,实现任务堆栈。例如:创建堆栈长度为128,优先级为20,任务参数pdata的实参为MyTaskAgu。,例如:创建堆栈长度为128,优先级为20,任务参数pdata的实参为MyTaskAgu。#define MyTaskStkN 64OS_STK MyTaskStkMyTaskStkN;Void main(void)OSTaskCreate(MyTask,但有两种情况的参数输入:增长方向向上和向下,与实际处理器类型有关。&MyTaskStk0和&MyTaskStkMyTaskStkN-1。OS_STK_GROWTH=1时需将堆栈的最高内存地址传递给任务创建函数。否则0传递给任务创建函数。,#define MyTaskStkN 64OS_STK MyTaskStkMyTaskStkN;Void main(void)#if OS_STK_GROWTH=1OSTaskCreate(MyTask,#endif,2.2.2 任务堆栈的初始化,OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT16U opt)return(stk);,任务的初始化由操作系统负责,通过调用任务的初始化函数OSTaskStkInit()完成初始化工作。预置诸如指向任务的指针、程序状态字PSW等。这与CPU有关,因此实现细节在移植章节中介绍。,2.3 任务控制块及任务控制块链表,任务控制块(OS_TCB):记录堆栈指针、任务的当前状态、任务的优先级别等一些与任务管理有关的属性的表。作用:关联任务代码和任务堆栈。使任务控制块、任务代码和任务堆栈成为一个整体。系统通过控制块管理任务。控制块就是任务的身份证。管理系统多个任务,uC/OS-II把系统所有任务的控制块链接为两条链表,并通过这两条链表管理各任务控制块,进而再通过任务控制块来对任务进行相关的操作。,2.3.1 任务控制块的结构,typedef struct os_tcb OS_STK*OSTCBStkPtr;/指向任务堆栈栈顶的指针#if OS_TASK_CREATE_EXT_EN 0 void*OSTCBExtPtr;/指向任务控制块扩展的指针 OS_STK*OSTCBStkBottom;/指向任务堆栈栈底的指针 INT32U OSTCBStkSize;/Size of task stack(in number of stack elements)*/INT16U OSTCBOpt;/*Task options as passed by OSTaskCreateExt()*/INT16U OSTCBId;/*Task ID(0.65535)*/#endif struct os_tcb*OSTCBNext;/*Pointer to next TCB in the TCB list*/struct os_tcb*OSTCBPrev;/*Pointer to previous TCB in the TCB list*/#if(OS_Q_EN 0)/*Message received from OSMboxPost()or OSQPost()*/#endif,.OSTCBStkPtr是指向当前任务栈顶的指针。C/OS-允许每个任务有自己的栈,尤为重要的是,每个任务的栈的容量可以是任意的。OSTCBStkPtr是OS_TCB数据结构中唯一的一个能用汇编语言来处置的变量(在任务切换段的代码Context-switching code之中,)把OSTCBStkPtr放在数据结构的最前面,使得从汇编语言中处理这个变量时较为容易。,.OSTCBExtPtr 指向用户定义的任务控制块扩展。用户可以扩展任务控制块而不必修改C/OS-的源代码。.OSTCBExtPtr只在函数OstaskCreateExt()中使用,故使用时要将OS_TASK_CREAT_EN设为1,以允许建立任务函数的扩展。例如用户可以建立一个数据结构,这个数据结构包含每个任务的名字,或跟踪某个任务的执行时间,或者跟踪切换到某个任务的次数(见例3)。注意,这个扩展指针变量放在紧跟着堆栈指针的位置,为的是当用户需要在汇编语言中处理这个变量时,从数据结构的头上算偏移量比较方便。,.OSTCBStkBottom是指向任务栈底的指针。如果微处理器的栈指针是递减的,即栈存储器从高地址向低地址方向分配,则OSTCBStkBottom指向任务使用的栈空间的最低地址。类似地,如果微处理器的栈是从低地址向高地址递增型的,则OSTCBStkBottom指向任务可以使用的栈空间的最高地址。函数OSTaskStkChk()要用到变量OSTCBStkBottom,在运行中检验栈空间的使用情况。用户可以用它来确定任务实际需要的栈空间。这个功能只有当用户在任务建立时允许使用OSTaskCreateExt()函数时才能实现。这就要求用户将OS_TASK_CREATE_EXT_EN设为1,以便允许该功能。.OSTCBStkSize存有栈中可容纳的指针元数目而不是用字节(Byte)表示的栈容量总数。也就是说,如果栈中可以保存1,000个入口地址,每个地址宽度是32位的,则实际栈容量是4,000字节。同样是1,000个入口地址,如果每个地址宽度是16位的,则总栈容量只有2,000字节。在函数OSStakChk()中要调用OSTCBStkSize。同理,若使用该函数的话,要将OS_TASK_CREAT_EXT_EN设为1。,.OSTCBOpt把“选择项”传给OSTaskCreateExt(),C/OS-目前只支持3个选择项OS_TASK_OTP_STK_CHK,OS_TASK_OPT_STK_CLR和OS_TASK_OPT_SAVE_FP。任务栈要清零。任务要做浮点运算。.OSTCBId用于存储任务的识别码。这个变量现在没有使用,留给将来扩展用。.OSTCBNext和.OSTCBPrev用于任务控制块OS_TCBs的双重链接,该链表在时钟节拍函数OSTimeTick()中使用,用于刷新各个任务的任务延迟变量.OSTCBDly,每个任务的任务控制块OS_TCB在任务建立的时候被链接到链表中,在任务删除的时候从链表中被删除。双重连接的链表使得任一成员都能被快速插入或删除。.OSTCBEventPtr是指向事件控制块的指针,后面的章节中会有所描述(见任务间通讯与同步)。.OSTCBMsg是指向传给任务的消息的指针。用法将在后面的章节中提到(见任务间通讯与同步)。.OSTCBDly当需要把任务延时若干时钟节拍时要用到这个变量,或者需要把任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。在这种情况下,这个变量保存的是任务允许等待事件发生的最多时钟节拍数。如果这个变量为0,表示任务不延时,或者表示等待事件发生的时间没有限制。.OSTCBStat是任务的状态字。当.OSTCBStat为0,任务进入就绪态。可以给.OSTCBStat赋其它的值,在文件uCOS_II.H的描述。.OSTCBPrio是任务优先级。,#if(OS_VERSION=251)OSTCBStat可能值:OS_STAT_RDY:表示任务处于就绪状态;OS_STAT_SEM:表示任务处于等待信号量状态;OS_STAT_MBOX:表示任务处于等待消息邮箱状态;OS_STAT_Q:表示任务处于等待消息队列状态;OS_STAT_SUSPEND:表示任务处于被挂起状态;OS_STAT_MUTEX:表示任务处于等待互斥型信号量状态。,2.3.2 任务控制块链表,uC/OS-II用两条链表来管理任务控制块。一条是空任务块链表,所有任务控制块没有分配任务。另一条是任务块链表,所有控制块已经分配任务。空任务控制块链表由初始化操作OSInit()建立。(OS_CORE.C)任务块链表则是在调用OSTaskCreate()创建任务时建立。具体方法:任务在空任务控制块链表中申请到控制块,然后填充上任务属性后,再形成新的链表。,图2-4 uC/OS-II初始化进创建一个空的任务控制链表,OSTCBFreeList,图2-5 uC/OS-II任务控制块链表和OSTCBPrioTbl数组及变量OSTCBCur,OSTCBList,OSTCBCur,OSTCBPrioTbl,0,1,2,3,OS_MAX_TASKS+OS_N_SYS_TASKS-2,OS_MAX_TASKS+OS_N_SYS_TASKS-1,OSTCBFreeList,2.3.3 任务控制块的初始化,分配任务控制块和初始化操作操作系统的职责。(1)应用程序调用函数OSTaskCreate()创建一个任务;(2)函数调用系统函数OSTCBInit()来为任务控制块进行初始化;(3)被创建任务从空任务控制块链表获取一个任务控制块;(4)用任务的属性对任务控制块各个成员进行赋值;(5)将这个任务控制块链入到任务控制块链表的头部。,INT8U OSTCBInit(INT8U prio,/任务的优先级别,保存在OSTCBPrio中 OS_STK*ptos,/任务堆栈栈顶指针,保存在OSTCBStkPtr中 OS_STK*pbos,/任务堆栈栈底指针,保存在OSTCBStkBottom中 INT16U id,/任务的标识符,保存在OSTCBId中 INT16U stk_size,/任务堆栈的长度,保存在OSTCBStkSize中 void*pext,/任务控制块的扩展指针,保存在OSTCBExtPtr中 INT16U opt/任务控制块的选择项,保存在OSTCBOpt中,INT8U OSTCBInit(INT8U prio,OS_STK*ptos,OS_STK*pbos,INT16U id,INT16U stk_size,void*pext,INT16U opt)OS_TCB*ptcb;OS_ENTER_CRITICAL();ptcb=OSTCBFreeList;(1)if(ptcb!=(OS_TCB*)0)(2)OSTCBFreeList=ptcb-OSTCBNext;OS_EXIT_CRITICAL();ptcb-OSTCBStkPtr=ptos;(3)ptcb-OSTCBPrio=(INT8U)prio;ptcb-OSTCBStat=OS_STAT_RDY;ptcb-OSTCBDly=0;#if OS_TASK_CREATE_EXT_EN 0 ptcb-OSTCBExtPtr=pext;ptcb-OSTCBStkSize=stk_size;ptcb-OSTCBStkBottom=pbos;ptcb-OSTCBOpt=opt;ptcb-OSTCBId=id;,OS_TCBInit()首先试图从OS_TCB缓冲池中得到一个任务控制块OS_TCB(1),如果缓冲池中有空余的OS_TCB,这个OS_TCB就被初始化。(3)Ptos指向栈顶指针。,#else pext=pext;stk_size=stk_size;pbos=pbos;opt=opt;id=id;#endif#if OS_TASK_DEL_EN 0 ptcb-OSTCBDelReq=OS_NO_ERR;#endif ptcb-OSTCBY=prio 3;ptcb-OSTCBBitY=OSMapTblptcb-OSTCBY;ptcb-OSTCBX=prio#endif,OS_ENTER_CRITICAL();(4)OSTCBPrioTblprio=ptcb;(5)ptcb-OSTCBNext=OSTCBList;ptcb-OSTCBPrev=(OS_TCB*)0;if(OSTCBList!=(OS_TCB*)0)OSTCBList-OSTCBPrev=ptcb;OSTCBList=ptcb;OSRdyGrp|=ptcb-OSTCBBitY;(6)OSRdyTblptcb-OSTCBY|=ptcb-OSTCBBitX;OS_EXIT_CRITICAL();return(OS_NO_ERR);(7)else OS_EXIT_CRITICAL();return(OS_NO_MORE_TCB);,OSTCBInit()需要将OS_TCB插入到已建立任务的OS_TCB的双向链表中(5),且禁止中断(4)。该双向链表开始于OSTCBList,而一个新任务的OS_TCB常常被插入到链表的表头。最后,该任务处于就绪状态(6),并且OSTCBInit()向它的调用者OSTaskCreate()返回一个代码表明OS_TCB已经被分配和初始化了(7)。,2.4 任务就绪表及任务调度,多任务操作系统的核心工作就是任务调度。调度就是通过一个算法在多个任务中确定哪个任务来运行。做这项工作的函数就叫做调度器。uC/OS-II调度任务的思想是每时每刻总是让优先级最高的就绪任务处于运行状态。利用调度器确定运行的任务顺序。,2.4.1 任务就绪表结构,系统中每个任务都在这个表中占据一个位(0或1)表示任务的就绪状态任务就绪表。INT8U OSRdyTbl存储就绪状态位。(OS_CORE.C)8位字节为一组。每组管理8个任务,若有8组,共可管理最多64个就绪任务。组有就绪任务情况由INT8U OSRdyGrp表达。,2.4.1 任务就绪表结构,2.4.1 任务就绪表结构,由于变量OSRdyGrp有8个二进制位,每位对应OSRdyTbl数组的一个元素,每个元素又可以记录8个任务,因此uC/OS-II最多可以管理88=64个任务。,任务的优先级别prio,指明任务所在数组元素的下标和该数组元素在变量OSRdyGrp中所对应的位,指明任务在数组元素中所对应的位,图2-8任务的优先级别与OSRdyGrp各数据位及数组元素中各数据位之间关系,例2-5,已知某一个已经就绪的任务的优先级别prio=30,试判断应该在就绪表的哪一位上置1。答:30的二进制形式为00011110,其低6位为011110,于是可知应该在OSRdyTbl3的D6位上置1,同时要把应量OSRdyGrp的D3位置1,2.4.2 对任务就绪表的操作,(1)将优先级别prio的任务置为就绪状态:OSRdyGrp|=OSMapTblprio3;OSRdyTblprio3|=OSMapTblprio&0 x07其中OSMapTbl是uC/OS-II为加快运算速度定义的一个数组,它的各元素值为:,2.4.2 对任务就绪表的操作,(2)从就绪表中删除一个任务 如果要使一个优先级别为prio的任务脱离就绪状态,则可使用如下代码:if(OSRdyTblprio3以上代码将就绪任务表数组OSRdyTbl中相应元素的相应位清零,而对于OSRdyGrp,只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。也就是说OSRdyTblprio3所有的位都是零时,OSRdyGrp的相应位才清零。为了找到那个进入就绪态的优先级最高