Presentation is loading. Please wait.

Presentation is loading. Please wait.

Beyond Technology NEUCLEUS的原理和应用 (Ver0.9) IS事业部 孙丕宏.

Similar presentations


Presentation on theme: "Beyond Technology NEUCLEUS的原理和应用 (Ver0.9) IS事业部 孙丕宏."— Presentation transcript:

1 Beyond Technology NEUCLEUS的原理和应用 (Ver0.9) IS事业部 孙丕宏

2 目的与目标 培训目的 培训对象 培训要求 培训的员工需要了解基本的C与汇编编成,尤其是需要熟悉和理解操作系统的基本概念和多任务的基本原理。
通过介绍在Nucleus plus的原理和应用,使开发人员掌握Nucleus的基本原理和使用方法,以满足软件开发的需要并满足客户的要求。 培训对象 培训对象主要是软件开发人员,尤其是在基于Nucleus系统下进行软件开发的人员。 培训要求 培训的员工需要了解基本的C与汇编编成,尤其是需要熟悉和理解操作系统的基本概念和多任务的基本原理。

3 第一部分 介绍 Nucleus 介绍 特点

4 简介篇 Nucleus介绍 美国著名RTOS 厂商 ATI 公司(Accelerated Technology Incorporated ) 推出的 NUCLEUS + 实时多任务操作系统以其微内核技术,原代码提供及广泛的CPU支持种类和易学易用等特点得到了国内众多用户的认可。 Nucleus主要应用领域在:网络、路由、桥接、Hubs、数据通讯、顶置盒、数字摄像机、ISDN、调制器、数字绘图仪、GSM、蜂窝电话、PDA、打印机、GPS、无线通讯、汽车、医疗仪器、RAID、适配卡、智能卡、安全保密、工业控制、扫描仪、煤气分析仪、游戏机、多媒体、手持产品、消费产品、局域网、广域网、导航设备、卫星通信、自动提款机、视频产品、条码机、过程控制等等

5 简介篇 Nucleus + 特点 1、提供源代码     NUCLEUS+提供注释严格的C源级代码给每一个用户。这样,用户能够深入地了解底层内核的运作方式,并可根据自己的特殊要求删减或改动系统软件,这对软件的规范化管理及系统软件的测试都有极大的帮助。另外,由于提供了RTOS的源级代码,用户不但可以进行RTOS 的学习和研究,而且产品在量产时也不必支付License,可以省去大量的费用。 2、性价比高 NUCLEUS+由于采用了先进的微内核 ( Micro-kernel ) 技术,因而在优先级安排,任务调度,任务切换等各个方面都有相当大的优势。另外,对C++语言的全面支持又使得NUCLEUS+的Kernel成为名副其实的面向对象的实时操作系统内核。然而,其价格却比较合理。所以,容易被广大的研发单位接受。 3、易学易用 NUCLEUS+能够结合Paradigm,SDS以及ATI自己的多任务调试器组成功能强大的集成开发环境,配合相应的编译器和动态联结库以及各类底层驱动软件,用户可以轻松地进行RTOS的开发和调试。另外,由于这些集成开发环境 ( IDE ) 为所有的开发工程师所熟悉,因而,容易学习和使用。 4、功能模块丰富 NUCLEUS+除提供功能强大的内核操作系统外,还提供种类丰富的功能模块。例如用于通讯系统的局域和广域网络模块,支持 图形应用的实时化Windows模块,支持Intnet网的WEB产品模块,工控机实时BIOS模块,图形化用户接口以及应用软件性能分析模块等。用户可以根据自己的应用来选择不同的应用模块。

6 简介篇 支持CPU类型 x86,68xxx,68HCxx,NEC V25, ColdFire, 29K,i960, MIPS, SPARClite, TI DSP, ARM6/7, StrongARM, H8/300H, SH1/2/3, PowerPC, V8xx, Panasonic MN10200 等。 可以说NUCLEUS+是支持CPU类型最丰富的实时多任务操作系统。

7 简介篇 开发环境 NUCLEUS+的实时多任务环境由编译器 ( Compiler ) ,连接定位器 ( Linklocater ) ,多任务调试器 ( Multi-task Debugger ) ,监控器 ( Monitor ) 以及相应的动态连接库组成。 NUCLEUS+提供标准的接口平台以支持优秀的第三厂商软件工具。用户可以根据自己的应用和系统的要求来选择相应的工具。例如 Microsoft C/C++、Borland C/C++、Turbo C/C++、Metaware High C、Parlap C 等编译器 (Compiler) ,Paradigm 的 连接定位器 (Linklocater) 和Turbo Debugger、SSI 的 Linkerlocater 和 Debugger 等都可以满足用户不同的应用要求。

8 第二部分 应用开发 2.1 应用开发综述 2.2 安装Nucleus + 2.3 应用Nucleus + 2.4 程序初始化
开发篇 第二部分 应用开发 2.1 应用开发综述 2.2 安装Nucleus + 2.3 应用Nucleus + 2.4 程序初始化 2.5 目标系统 2.6 配置选项

9 应用开发综述 建立一个嵌入式实时应用程序是非常直接的。驻留在主机系统上的应用程序文件可以编译/汇编成目标文件并连接。结果映像文件既可以下载到目标系统也可以放到目标系统的ROM 中。 针对目标系统的调试软件通常包括ICE 仿真工具和TRM(目标仿真)工具。拥有ICE 工具是更好的选择,因为ICE 工具给我们开发人员完全控制和了解目标系统硬件状况。ICE 工具在校验新硬件时尤其有用。 考虑到费用问题和ICE 有时有局限性,许多项目采用TRM 调试。TRM 就是一个小型的运行在目标系统(通常为ROM)上的软件组件。TRM 提供包括下载、下断点和内存入口服务。ICE 和TRM 都有宿主系统控制。这通常由串口来完成。 源级调试允许开发人员使用真正的C 源代码调试应用程序。这种性能需要宿主系统上附加的程序,该程序在C 源代码和目标系统内存之间建立联系。大多数的源代码级调试使用ICE 和TRM 来真正控制和进入目标系统硬件。 Nucleus PLUS 整合了大量的C 源代码调试器。另外,Nucleus PLUS 调试器对为Nucleus PLUS应用程序附加扩展的多任务调试能力有效。

10 安装Nucleus + Nucleus PLUS 的安装很简单。: 1) 在主机上创建名为NUCLEUS 的目录;
2) COPY所有文件至NUCLEUS 目录(2M左右); 3) 通过运行批处理文件BUILD LI.BAT 建立Nucleus PLUS 库; 4) Nucleus 库文件NUCLEUS.LIB 必须与连接器更易接近。这可能要通过既要在应用程序开发目录中拷贝它又要在NUCLEUS 目录中设置连接器以至于能找到它来完成。 5) NUCLEUS.H 文件必须贴近应用程序。这可能要通过既要在应用程序开发目录中拷贝它又要在NUCLEUS 目录中设置编译器器以至于能找到它来完成。

11 使用Nucleus+ 使用Nucleus PLUS 的步骤被描述成下列通用的方式:
1) 如果有必要,修改低级系统初始化文件,INT.S。注:这些文件通常以汇编语言形式交货并且它的的扩展是指定的开发工具。 2) 定义Application_Initialize 函数,Nucleus PLUS 启动系统时它优先运行。注意NUCLEUS.H 文件必须包含以至于能被Nucleus PLUS 服务调用。 3) 定义应用程序任务。如果用到Nucleus PLUS 服务,文件NULCUES.H 必须被包含。 4) 编译 和/或 汇编所有应用程序软件,包括低级系统初始化文件INT.s。 5) 用Nucleus PLUS 库和必要的开发工具库连接INT.a 和所有应用程序目标文件。 6) 下载应用程序映像文件到目标系统并让它跑起来!

12 应用程序初始化 Application_Initialize 子程序负责定义初始化应用程序环境。它包含有任务、邮箱、队列、信号量、事件集、内存池和其他Nucleus PLUS 对象。 Application_Initialize 配备有指向第一个有效地内存地址的指针。之后的内存没有被编译器或Nucleus PLUS 使用,因此对应用程序有效。虽然Application_Initialize 详细内容依靠应用程序,下面的模板依然有效: # include <nucleus.h> void Application_Initialize(void *first_available_memory) { /* Nucleus PLUS对象的应用程序详细初始化,包括任务、邮箱、队列、管道、事件集、内存池的创建。*/ } 从初始化子程序调用的服务不能被挂起,直到初始化子程序不再作为一个任务运行。也要注意至少一个任务或是中断处理器被Application_Initialize 创建,并且Application_Initialize是优先级高于第一个任务运行的最后一个子程序。

13 例1: Application_Initialize 创建一个内存池和一个任务
#include <nucleus.h> /*定义任务控制结构*/ NU_TASK Task; /*定义动态内存池控制结构*/ NU_MEMORY_POOL Memory_Pool; Void Application_Initialize(void *first_available_memeory) { void *stack_ptr; /*创建一个4000 字节开始于起始地址的动态内存池*/ NU_Create_Memory_Pool(&Memory_Pool,”SYSTEM”, first_available_memory,4000,50,NU_FIFO); /*从系统内存池创建一个任务堆栈*/ NU_Allocate_Memory(&Memory Pool, &stack_ptr,500,NU_NO_SUSPEND); /*创建一个以功能函数abc(0,NU_NULL)为入口点的应用任务*/ NU_Create_Task(&Task,ABC_TASK,abc,0,NU_NULL,stack_ptr,500,10, NU_PREEMPT,NU_START); }

14 配置选项 Nucleus PLUS 应用程序有一个有条件的编辑选项。在命令行编译应用程序源文件通过定义NU_NO_ERROR_CHECKING 变量,所有Nucleus PLUS 服务错误检测逻辑被忽略(Bypassed)。这可以提升Nucleus PLUS 服务运行性能。 当建立Nucleus PLUS 库时,有几个有条件的编辑选项被有效应用。这些选项可以加到MAKELIB.BAT 文件的编译命令里。这些文件驻留在NUCLEUS 主文件夹里,包含所有建立Nucleus库所必须的命令。 下面是对有条件的有效编译符号和他们对应的含义的定义: 编译符号 含义 NU_ENABLE_HISTROY 每个服务调用历史条目结果。这个符号可以被加到所 有**C.C 文件的编译命令当中 NU_ENABLE_STACK_CHECK 使能堆栈检测。这个符号可以被加到所有**C.C 文件的编 译命令当中 NU_ERROR_STRING 如果有致命系统错误发生建立一个ASCII 错误信息。本选 型只用于编译ERD.C,ERI.C 和ERC.C 时。 NU_NO_ERROR_CHECKING 忽略错误检测,和任何用户的应用程序代码

15 第三部分 功能的描述 3.1 初始化 3.2 任务 3.3 任务通信 3.4 任务同步 3.5 定时器 3.6 内存管理 3.7 中断
3.8 输入/输出驱动器 3.9 系统诊断

16 3.1 初始化 INT_Initialize 子程序在Nucleus PLUS 系统中是最先运行的。对大多数的目标环境,硬件
INT_Initialize 负责所有与目标硬件相关的初始化。与目标硬件相关的初始化通常包括设置不同种类的处理器控制寄存器,中断向量表,全局的C 数据元素,一些Nucleus PLUS 变量,和系统堆栈指针。当INT_Initialize 完成,控制转移到高级Nucleus PLUS 初始化子程序INC_Initialize上。注意控制不会返回INT_Initialize。 INC_Initialize 调用每个Nucleus PLUS 组件的初始化子程序。在所有Nucleus PLUS 初始化完成之后,INC_Initialize 调用用户供应的初始化子程序Application_Initialize。 Application_Initialize 子程序负责定义初始化应用环境。初始化应用任务,邮箱,队列,管道,信号量,事件集,内存池和其他Nucleus PLUS 对象都在子程序中被定义,这个子程序的格式在《开始》章节描述。 在Application_Initialize 返回后,INC_Initialize 开始初始化任务调度表。具体过程如图所示。

17 图:Nucleus PLUS 初始化流程 INC_Initialize 调用每个Nuleus PLUS组件的初始化应用子程序
INT_Initialize:初始化下类 ●处理器控制器寄存器 ●中断向量表 ●全局C数据元素 ●一些Nucleus PLUS变量 ●系统堆栈指针 调用每个Nuleus PLUS组件的初始化应用子程序 INC_Initialize 用户提供的初始化子程 Application_Initialize: 初始化应用任务,邮箱,队列,管道,信号量,事件集,内存池和其他Nucleus PLUS对象 初始化任务调度表

18 3.2 任务 任务就是目的明确的半独立程序段。大多数现代实时应用都要求多任务。另外,这些任务的重
要等级经常变化。管理这些竞争、实时任务的运行是Nucleus PLUS 的主要目的。 任务状态 每个任务都有五种状态:运行、就绪、挂起、中止、完成。下列列表描述了每个任务的状态: 表一 任务状态列表 状态 含义 运行 任务正在运行 就绪 任务就绪,但其他任务正在运行 挂起 等待服务请求完成之前任务休眠状态。当响应 结束,任务转入等待状态 中止 任务被禁止。一旦进入这种状态,任务直到复 位之前不能运行。 完成 任务完成并返回到初始入口子程序。一旦进入 这种状态,任务直到复位前都不能运行 优先级 用户分配,范围0~255,用来定义Nulceus PLUS 任务的重要性,数字越小优先级越高 备注:给任务分配优先级时必须小心。如果一不小心,优先级可能导致任务饿死和系统超负荷。

19 3.3任务通信 Nucleus PLUS 为通信目的提供: 邮箱(mailbox) 队列(queues) 管道(pipes)。
 邮箱,队列,管道是独立的公共设备。  任务之间和其他系统设备之间的联系由应用程序确定。这些通信设备之间主要的差别是数据通信的类型。

20 3.3.1 邮箱 邮箱为传输简单数据提供低消耗方案。每个邮箱可以保持4 个32 位字大小的单一消息。消息以(数)值方式发送和接受。一个发送消息要求拷贝消息到邮箱,一个接受消息要求从邮箱中把消息拷贝出来。 消息尺寸 一列消息包括一个或多个32 位字。固定的和长度可变的消息都支持。消息类型的格式在队列创建 的时候定义。长度可变的消息队列需要为队列中的每个消息消耗一个附加的32 位字。 挂起 发送和接收邮箱服务为非条件的挂起、时间间隙挂起和无挂起提供配置广播:邮箱的消息可以被广播。这种服务类似于发送请求,除了所有从邮箱等待消息的任务改成了等待广播消息。(类同与同报Event) 动态创建 Nucleus PLUS 邮箱可以动态创建和删除。一个应用程序在邮箱数量上没有预先限制。每个邮箱需要一个控制块。控制块的内存由应用程序提供 结论 发送和接受邮箱消息的处理时间请求为常量。然而,按优先级顺序挂起任务所需的处理时间受当前在邮箱上挂起的任务数影响。 邮箱信息 应用程序任务可以获得活动邮箱的列表。每个邮箱的详细信息也也可以获得。这些信息包括邮箱名、挂起类型、信息是否出现、第一个任务等待。

21 3.3.2 队列 队列提供了传输多个消息的机制。消息以数值形式发送接受。一个发送消息要求拷贝消息到队列,一个接收消息要求从队列上拷贝消息。消息可以放在对列的前端或队列的后端。 消息尺寸:   一列消息包括一个或多个32 位字。固定的和长度可变的消息都支持。消息类型的格式在队列创建的时候定义。长度可变的消息队列需要为队列中的每个消息消耗一个附加的32 位字。另外,接收消息要求在长度可变消息队列指定最大消息尺寸,在固定长度消息队列指定合适的消息尺寸上有同样的要求。 发送和接收队列服务为非条件的挂起、时间间隙挂起和无挂起提供配置。 挂起 广播 队列的消息可以被广播。这种服务类似于发送请求,除了所有从队列等待消息的任务改成了等待广播消息。 动态创建  Nucleus PLUS 队列可以动态创建和删除。一个应用程序在队列数量上没有预先限制。每个队列需要一个控制块。控制块的内存由应用程序提供。 结论 发送和接受队列消息请求的基本处理时间为常量。然而,按优先级顺序挂起任务所需的处理时间受当前在队列上挂起的任务数影响。 队列信息 应用程序任务可以获得活动队列的列表。每个队列的详细信息也也可以获得。这些信息包括队列名、消息类型、挂起类型、消息出现的次数、第一个任务等待。

22 3.3.3 管道 管道提供了传输多个消息的机制。消息以数值形式发送接受。一个发送消息要求拷贝消息到管道,一个接收消息要求从管道上拷贝消息。消息可以放在管道的前端或队列的后端。 消息尺寸 一列管道消息包括一个或多个32 位字。固定的和长度可变的消息都支持。消息类型的格式在管道创建的时候定义。长度可变的消息管道需要为管道中的每个消息消耗一个附加的32 位。 挂起   发送和接收管道服务为非条件的挂起、时间间隙挂起和无挂起提供配置 广播 管道消息可以被广播。这种服务类似于发送请求,只是所有从队列等待消息的任务改成了等待广播消息。 动态创建 Nucleus PLUS 管道可以动态创建和删除。一个应用程序在管道数量上没有预先限制。每个管道需要一个控制块和一个管道数据区。每个内存由应用程序提供。 结论 发送和接受管道消息请求的基本处理时间为常量。然而,拷贝消息所需的时间与消息尺寸有关联。另外,按优先级顺序挂起任务所需的处理时间受当前在管道上挂起的任务数影响 队列信息 应用程序任务可以获得活动管道的列表。每个管道的详细信息也可以获得。这些信息包括管道名、消息格式、挂起类型、消息出现的次数、第一个任务等待   

23 3.4 任务同步 Nucleus PLUS 提供: 信号量(semaphores), 事件集(event groups)
信号(signals) 解决信号同步问题。信号量和事件集都是独立的,公用的设备。任务和其他系统设备的联系由应用程序 决定。信号(signals),换一种说法,与指定任务关联。

24 3.4.1 信号量(semaphores) 信号量提供了控制应用程序临界区运行的机制。Nucleus PLUS 提供了范围从0~ 的计算信号量。信号量两个基本操作是获得和释放。获得信号量请求消耗信号量,释放信号量请求增加了信号量。 信号量最普通的应用是资源配置。另外,带初始值信号量的创建可以用来指示事件。 挂起 获得信号量服务为无条件挂起、时间间隙挂起、无挂起提供配置。 死锁 两个任务或多个任务永远挂起试图获得两个或更多个信号量,死锁就涉及到这种状况 预防是处理死锁的最佳措施。这项技术把规则强加到应用程序使用的变量。例如,如果任务不允许一次占用超过一个信号量,死锁被保护。作为选择,如果任务在同一个次序获得多个信号量死锁可以被保护。获得信号量挂起时可选的空闲时间(Timeout)可以用来从死锁状态恢复 优先级倒置 优先级倒置在高优先级任务请求低优先级任务使用的信号量引起挂起时发生。如果不同优先级任务共享相同的受保护的资源,这种情况不可避免。在这种情况下,在优先级倒置里,有限和可预料的时间量可接受。 动态创建 Nucleus PLUS 信号量可以动态被创建和删除。应用程序可能拥有的信号量数没有预先限定。每个信号量需要一个控制块。控制块的内存由应用程序提供。信号量在创建时赋初值 结论 获得和释放信号量要求的运行时间为常量。然而,以优先级顺序挂起一个任务所需的运行时间受当前在信号量上挂起的任务数影响。 信号量信息 应用程序任务可以获得激活的信号量列表。每个信号量的详细信息也可以得到。这些信息包括:信号量名、当前值、挂起类型、任务等待数、第一个等待任务

25 3.4.2 事件集 事件集提供一个机制来描述一个指定系统事件的发生。事件由事件集中单个位来描述。这位叫事件标志。每个事件集有32 个事件标志。 事件标志可以通过逻辑AND/OR 组合被设置和清除。事件标志也可以以逻辑AND/OR 组合接收。另外,事件标志可以在接收完后自动复位。 挂起 接收事件标志请求为无条件挂起、时间间隙挂起、无挂起提供选项 动态创建 Nucleus PLUS 事件集可以动态创建和删除。应用程序可能拥有的事件集数没有预先限定。每个事件集需要一个控制块。控制块的内存由应用程序提供。 结论 获得和释放信号量要求的运行时间为常量。然而,在事件集中置位事件标志所需的时间受事件集上挂起的任务数影响。 事件集信息 应用程序任务可以获得激活的事件集列表。每个事件集的详细信息也可以得到。这些信息包括:事件集名、当前事件标志、任务等待数、第一个等待任务。

26 3.4.3信号 信号在某种程度上讲很相似。然而,他们在操作上有几个非常重要的差别。事件标志的用法天生就是同步的。直到指定的服务请求完成,任务不承认事件标志出现。信号以异步的方式运行。当信号出现,任务中断并且任务提前指定的信号处理子程序运行。每个任务可以处理32 个信号。每个信号对应一个描述位。 信号处理子程序 任务信号处理子程序必须在任何信号运行之前被提供。 使能信号子程序 任务缺省可以在所有信号禁止的情况下创建。个别信号可以被每个任务动态使能或禁止 清除信号 当信号处理被调用信号自动清除。另外,当请求接收信号的恳求完成时信号被清除。注:在请求接收信号恳求时,任务不能挂起。 多信号 一旦信号处理子程序开始运行,任务的信号被清除。信号处理子程序不能被新信号中断。任何新信号的处理在当前信号处理完成后进行。在第一个信号被验证之前发送的同样的信号被放弃。 结论 至少在最坏的情况下,发送和接收信号要求的运行时间是常量。当然运行信号处理子程序所需的时间由应用程序指定。

27 3.5 定时器 大多数实时应用需要在按周期性的时间间隔运行。每个Nucleus PLUS 任务都有一个内建定时器。这个定时器用来提供任务休眠和服务调用的时间 节拍 节拍是所有NucleusPlUS 定时器设备时间的基本单元。每一拍对应单个硬件定时器中断。实际的时钟节拍值是用户可编程的。错误空白大约一拍左右可以满足一个定时器请求。这是因为在定时器请求之后一节拍可以立即发生。因此,定时器请求的第一拍表示的是从零到硬件定时器中断率范围的真实时间。例如,在实际时间n 和n-l拍之间一个N 拍的下降请求实际时间值中止。 硬件请求 Nucleus PLUS 定时器服务需要硬件提供的周期性的定时器中断。没有中断,定时器设备不运行。然而,其他的 Nucleus PLUS 设备在没有定时器设备时不会激活。

28 连续时钟 Nucleus PLUS 维持一个连续的技术节拍时钟。这个时钟的最大值为 。时钟在到达节拍大值后自动复位。 这个连续时钟为应用程序的使用专门保留。它可以在若任何时间由应用程序读出或写入。 任务时钟 每个任务都有一个内建定时器。这个定时器为任务休眠请求和挂起时间间隙请求而准备。 应用时钟 Nucleus PLUS 为应用程序提供可编程定时器。这些定时器在他们到时时运行指定的用户提供子程序。用户提供时间到子程序作为一个高级中断服务子程序运行。因此,自挂起请求被禁止。另外,运行必须保持最小化。

29 定时器重新置初值 当一个定时器定时时间到时,指定的定时时间到时子程序开始运行。在运行结束之后,定时器既是静止的又可以重新置初始值。如果定时器置初始值为零,在初始化到时后还是禁止的。然而,如果定时器置初始值为非零,在时间间隔结束后重新置初值。 使能/禁止 应用程序定时器在创建期间可以被自动使能。另外,定时器可以被动态使能和禁止。 复位 初始化一个定时器的节拍、重新置初值的比率和一个定时器到时子程序可以被应用程序动态复位。 动态创建 Nucleus PLUS 应用程序定时器可以动态创建和删除。应用程序拥有的定时器数的没有预先限定。每个定时器请求一个控制块。控制快的内存由应用程序提供。 结论 创建、使能、禁止和修改应用程序定时器所需的处理时间是不变的。然而,运行用户提供的定时子程序所需的处理时间由定时子程序自身和同时结束的定时器数决定。 定时器信息 应用程序可以获得激活的定时器列表。每个定时器的详细信息也可以获得。这些信息包括定时器名称、状态、初始化节拍、重置值、保持节拍和到时计数。

30 3.6 内存管理 Nucleus PLUS 提供分区和动态内存管理设备。分区内存管理是确定性的但不是非常灵活。动态内存管理非常灵活但是有不确定性。大多数应用程序对两种类型的内存管理设备都有需要。 分区内存池 一个分区内存池包含一个指定固定尺寸的内存分区数。池的内存位置、池的字节数和在每个分区中的字节数都由应用程序决定。单个的分区从分区内存池中分配和收回。 动态内存池 一个动态内存池包含一个用户指定的字节数。内存在池中的位置由应用程序决定。Nucleus PLUS为动态内存池提供可变长度的分配和释放服务。分配以最适合的方式(first_fit_manner)运行。例如,满足要求的第一个有效内存被分配。如果分配的块比要求的大的多,没有使用的内存返回到动态内存池。先前释放的块在分配搜索期间又从新合并了。 内存池 内存分区

31 3.7 中断 中断是为外部和内部事件提供立即响应的机制。当中断发生时,处理器挂起当前运行的程序,并且转移控制权到适当的中断服务子程序(ISR)。中断的强制运行是固有的、处理器指定的 保护 关中断来保护数据结构不是个好办法。Nucleus PLUS 通过把应用程序的ISRs 区分为低级到高级组件来处理保护问题。 低级中断 低级中断服务子程序(LISR)和正常的ISR 一样运行,包括使用当前堆栈 高级中断: 高级中断支持动态创建和删除。每个HISR 由它自己的堆栈空间和控制块。每个的内存由应用程序提供。当然,HISR 必须在LISR 激活之前被创建。 HISR 信息 应用程序任务可以获得激活HISRs的列表。每个HISR的详细信息也可以获得。这些信息包括HISR名、总预定计数、优先级和堆栈参数。 中断潜伏期 中断潜伏期是描述每个中断关闭时间值的术语。一旦Nucleus PLUS 不依赖于关中断保护禁止同步ISR 访问,中断潜伏期是很短和恒定的。事实上,在一些Nucleus PLUS 端口,中断关闭只能超过几个指令周期。 应用程序中断锁定 应用程序提供禁止和使能中断的能力。一个中断通过应用程序关闭保持到应用程序解锁。 直接向量访问 Nucleus PLUS 提供直接设置中断向量的能力。ISRs 直接下载到向量表被允许用来存储和恢复 使用的寄存器

32 3.8 输入/输出驱动器 大多数的实时应用程序需要不同外围设备的输入输出。这些输入输出的管理通常由一个I/O 器件驱动器来完成 通用接口
Nucleus PLUS 为初始化、赋值、释放、输入、输出、状态和中止请求提供一个标准的I/O 驱动器接口。 驱动器内容 一个I/O 驱动器通常处理初始化、分配、释放、输入、输出、状态和中止请求过程。如果I/O 驱动器由中断驱动,中断处理子程序也是必须的。 保护 除了大多数Nucleus PLUS 服务的可用性之外,I/O 驱动器也提供服务保护内部数据结构不被同步高优先级ISR 访问。低优先级ISR 同步访问的保护通过禁止适当的中断来保护。 挂起 I/O 驱动器可以被系统中不同的线程调用 动态创建 Nucleus PlUS I/O 驱动器可以动态创建和删除 驱动器信息 应用程序任务可以获得激活的I/O 驱动器的列表。指定的驱动器的详细信息也可获得。

33 3.9 系统诊断 Nucleus PLUS 提供给应用程序任务几种提高系统故障的诊断能力的设备 错误管理
如果一个致命的系统错误出现,处理转到通用错误处理子程序。默认情况下,这个程序准备一个ASCII 错误消息并暂停系统。然而,附加的错误处理可以由应用程序开发人员加入。 系统历史 Nucleus PLUS 为各种系统活动提供一个环形的事件日志。应用程序任务和HISR 可以进入这些日志。Nucleus PLUS 服务有一个有条件的编辑选项,用来使能每次服务请求发生时进入历史日志。历史日志的每次进入包含有关服务和调用的信息。 版本信息 RLD_Release_String 是一个全局C 字符串,包含当前Nucleus PLUS 软件版本和版权信息。这个字符串在目标系统中的检查提供对在下面的Nucleus PLUS 快速鉴定。 许可信息 LID_License_String 是一个全局C 字符串,包含用户许可信息,包括用户的序列号。

34 第四章 Nucleus PLUS 服务 4.1 任务控制服务 4.2 任务通信服务 4.3 任务同步服务 4.4 定时器服务
4.5 内存服务 4.6 中断服务 4.7 I/O 驱动器服务 4.8 开发服务 4.9 服务定义

35 4.1 任务控制服务 任务控制服务用来控制应用程序任务的运行。下列服务 运行任务控制函数:
NU_Create_Task NU_Delete_Task NU_Resume_Task NU_Suspend_Task NU_Terminate_Task NU_Reset_Task NU_Change_Time_Slice NU_Change_Priority NU_Change_Preemption NU_Sleep NU_Relinquish NU_Check_Stack NU_Current_Task_Pointer NU_Established_Tasks NU_Task_Pointers NU_Task_Information

36

37 4.2 任务通信服务 任务通信服务提供对Nucleus PLUS 邮箱、队列、管道的访问。下面的服务适合任务通信:
NU_Broadcast_To_Mailbox NU_Create_Mailbox NU_Delete_Mailbox NU_Established_Mailboxs NU_Mailbox_Information NU_Mailbox_Pointers NU_Receive_From_Mailbox NU_Reset_Mailbox NU_Send_To_Mailbox NU_Broadcast_To_Queue NU_Create_Queue NU_Established_Queues NU_Delete_Queue NU_Queue_Pointers NU_Queue_Information NU_Reset_Queue NU_Receive_From_Queue NU_Send_To_Queue NU_Send_To_Front_of_Queue NU_Create_Pipe NU_Broadcast_To_Pipe NU_Established_Pipes NU_Delete_Pipe NU_Pipe_Pointers NU_Pipe_Information NU_Reset_Pipe NU_Receive_From_Pipe NU_Send_To_Pipe NU_Send_To_Front_of_Pipe

38 4.3 任务同步服务 任务同步服务提供访问Nucleus PLUS 信号量、事件标志、信号。下列服务适合任务同步:
NU_Create_Semaphore NU_Delete_Semaphore NU_Established_Semaphores NU_Obtain_Semaphore NU_Release_Semaphore NU_Reset_Semaphore NU_Semaphore_Information Nu_Semaphore_Pointers NU_Create_Event_Group NU_Delete_Event_Group NU_Established_Event_Groups NU_Retrieve_Events NU_Event_Group_Pointers NU_Receive_Signals NU_Event_Group_Information NU_Send_Signals NU_Register_Signal_Handler NU_Set_Events NU_Control_Signals

39 4.4 定时器服务 定时器服务提供访问Nucleus PLUS 定时器资源的接口。下列服务适合定时器资源:
NU_Control_Timer NU_Create_Timer NU_Delete_Timer NU_Established_Timers NU_Reset_Timer NU_Retrieve_Clock NU_Set_Clock NU_Timer_Information NU_Timer_Pointers

40 4.5 内存服务 内存服务提供访问Nucleus PLUS 固定和可变长短内存管理设备接口。下列服务适合内存管理:
NU_Allocate_Partition NU_Create_Partition_Pool NU_Deallocate_Partition NU_Delete_Partition_Pool NU_Established_Partition_Pools NU_Partition_Pool_Information NU_Partition_Pool_Pointers NU_Create_Memory_Pool NU_Allocate_Memory NU_Delete_Memory_Pool NU_Deallocate_Memory NU_Memory_Pool_Information NU_Established_Memory_Pools NU_Memory_Pool_Pointers

41 4.6 中断服务 中断服务提供访问Nucleus PLUS 中断管理资源的入口。下列服务适合中断设备:
NU_Activate_HISR NU_Control_Interrupts NU_Local_Control_Interrupts NU_Create_HISR NU_Current_HISR_Pointer NU_Delete_HISR NU_Established_HISRs NU_HISR_Information NU_HISR_Pointers NU_Protect NU_Register_LISR NU_Setup_Vector NU_Unprotect

42 4.7 I/O 驱动器服务 驱动器服务提供访问Nucleus PLUS 设备驱动器的标准接口。下列服务适合I/O 驱动器:
NU_Create_Driver NU_Delete_Driver NU_Driver_Pointers NU_Established_Drivers NU_Request_Driver NU_Resume_Driver NU_Suspend_Driver

43 4.8 开发服务 开发服务提供访问Nucleus PLUS 开发支持设备的接口。下列服务适合开发支持:
NU_Disable_History_Saving NU_Enable_History_Saving NU_License_Information NU_Make_History_Entry NU_Release_Information NU_Retrieve_History_Entry

44 4.9 服务定义 每个Nucleus PLUS 服务作为本章的保留部分进行描述。服务的描述按字母排序。 包含文件(Inclde File)
为了使用Nucleus PLUS 服务,NUCLEUS.H 文件必须被包含。 编辑选项 默认情况下,检查提供给Nucleus PLUS 服务的参数是否有错。错误检查可以在应用程序C 文件中编辑期间通过定义变量NU_NO_ERROR 为CHECKING 来禁止。看目标编译器文档来决定如何在编辑期间定义变量。 标准数据类型 Nucleus PLUS 定义几个标准的数据类型。抛开平台,这些数据类型在尺寸和性能上保持不变。因此,Nucleus PLUS 服务可以以同样的方式在所有的目标环境上运行。下类数据类型由Nucleus PLUS 定义 数据类型 含义 UNSIGNED 32 位无符号整型 SIGNED 32 位带符号整型 OPTION 很容易操作的最小数据类型,通常为一个无符号字符 DATA ELEMENT 和上一个OPTION 数据类型相同 UNSIGNED_CHAR 8 位无符号字符 Nucleus PLUS 参考手册CHAR 8 位字符 STATUS 与目标编译器符号整型数据类型相同 INT 整型数据类型,与正常的机器上的字的尺寸对应 VOID 等于目标编译器void 的数据类型

45 描述格式 描述格式用来描述每个Nucleus PLUS 服务在本章中的一致性。描述每一节的摘要讨论格式如下: 函数原型 本章包含服务完全的C 定义。所有的Nucleus PLUS 服务适合ANSI C。 描述 本章包括一个段落描述服务的操作。另外,服务的参数在本章也进行了详细的描述。 返回值 无论如何,在服务中,本章定义了值的返回。 任务改变 本章指出服务是否能够导致任务环境的改变。如果任何任务挂起或恢复可以导致调有服务,本章列出‘是’。否则,如果服务不能挂起或恢复任何任务,本章列出‘否’。注:如果‘是’在本章列出,其他的任务可能在服务返回调用程序前运行。 允许调用 本节定义了在Nucleus PLUS 服务可以被调用时线程的运行。虽然大多数的服务可以从不同线程的运行被调用,挂起也只能在任务线程调用的服务上被指定。其他线程的运行包括:应用程序初始化(Application_Initialize),信号处理(signal Handling),低优先级中断服务子程序(LISR),和高优先级中断服务子程序(HISR)

46 第五章 扩展讨论 5.1 内存使用 5.2 自定义服务 5.3 执行线程 5.4 中断处理 5.5 I/O 驱动器

47 5.1 内存使用 Nucleus PLUS 给应用程序提供为每个系统对象指定内存利用的能力。系统对象包括任务,HISRs,队列、管道、邮箱、信号量、事件标志集、内存分区池、动态内存池和I/O 驱动器。 系统对象的内存分配有几种方法。 1. 使用全局C 数据结构进行分配内存。 2. 从动态内存池或是分区内存池动态分配内存。 3. 从目标系统的绝对物理区域分配内存。 使用全局C 数据结构对系统对象分配内存是分配控制结构最简单的方法。下面是为每种类型的系统对象进行控制块分配的例子: 系统对象 例子 NU_TASK Example_Task NU_HIST Example_HISR NU_DRIVER Example_Driver NU_QUEUE Example_Queue NU_MAILBOX Example_Mailbox NU_PIPE Example_Pipe NU_EMAPHORE Example_Semaphore NU_EVENT_GROUP Example_Event_Group NU_PARTITION_POOL Example_Psrtition_Pool NU_MEMORY_POOL Example_Memory_Pool Example_*为驻留在全局C 数据区的控制块。适当的控制块的指针被传递到相应创建的服务。 从Nucleus PLUS 内存池给系统对象分配内存非常常见。内存池是系统对象自身的,因此可以被 创建用来管理其他的内存区。

48 例: 例1: 创建的动态内存池(System_Memory 是先前创建的内存池中一个全局C 控制块分配任务控制块和一个1000 字节堆栈
NU_TASK *Example_Task_Ptr; VOID *Example_Stack_Ptr; /*为任务控制结构分配内存*/ NU_Allocate_Memory(&System_Memory,(VOID **)&Example_Task_Ptr, sizeof(NU_TASK), NU_NO_SUSPEND); /*为任务堆栈配置内存*/ NU_Allocate_Memory(&System_Memory,&Example_Stack_Ptr,1000,NU_NO_SUSPEND); NU_MEMORY_POOL System_Memory; 例2: 假设地址0X 是一个4096 字节的高速内存区。第一个例子在这块内存区创建一个动态内存池 /*创建一个动态内存池管理地址在0x 的高速内存*/ NU_Create_Memory_Pool(&System_Memory,SYSTEM(VOID *)0x200000,4096,20,NU_FIFO);

49 例3: 给高优先级的任务的任务块和一个2000 字节堆栈在高速内存区上分配内存。 NU_TASK *Example_Task_Ptr; VOID *Example_Stack_Ptr; CHAR *High_Speed_Mem_Ptr; /*放置起始地址在高速内存指针*/ High_Speed_Mem_Ptr = (CHAR *) 0x200000; /*在开始处分配任务控制块*/ Example_Task_Ptr = (NU_TASK *) High_Speed_Mem_Ptr; /*调整高速内存指针*/ High_Speed_Mem_Ptr = High_Speed_Mem_Ptr + sizeof(NU_TASK); /*分配任务堆栈区*/ Example_Stack_Ptr = (VOID *) High_Speed_Mem_Ptr; /*万一需要更多分配,调整高速内存区指针*/ High_Speed_Mem_Ptr = High_Speed_Mem_Ptr ; /*用Example_Task_Ptr & Example_Stack_Ptr 调用创建任务*/

50 5.2 定制服务 Nucleus PLUS 服务可以被组合成专门的应用程序服务。例如,假设一个应用程序需要确认每个通过邮箱发送到其他任务的消息。通过在两个邮箱上操作创建发送/接收服务,这很容易实现。一个邮箱用来真正的传送数据,另一个邮箱用于消息确认。新的发送服务把消息放入第一个邮箱然后从第二个邮箱等待确认。新的接收服务从第一个又想等待消息并通过第二个邮箱发送确认。 不同的Nucleus PLUS 服务也可以组合成指定的应用程序服务。例如,允许在多邮箱、队列和管道上挂起的新的服务可以通过使用计数信号量和期望的通信机制来实现。在服务当中,计数信号量初始化为0。每次一个消息被放入一个通信对象,信号量增加(释放)。在接收请求中,信号量第一个被获得。如果信号量为0,任何通信对象中都没有消息且可以挂起。另外,如果信号量可以获得,最少有一个消息出现。每个通信对象检查直到消息出现。

51 5.2.1 多个邮箱挂起例程 本节包含C 源代码实例说明在多个邮箱上的挂起。虽然此例用的是邮箱,可以很容易的应用于其他的通信机制,包括队列和管道。下面是自定义多邮箱挂起服务的服务接口: MM_Create 创建一个多邮箱对象 MM_Send 发送消息至多邮箱交换 MM_Receive 从一个挂起的邮箱接收消息 下面显示了一个假设多邮箱挂起头文件。(注:Nucleus PLUS 软件中不包含下面的例子文件)。 #include <nucleus.h> /*这是多邮箱挂起服务控制结构*/ typedef struct MMAIL_STRUCT { NU_SEMAPHORE message_count; NU_MAILBOX mailbox_1; NU_MAILBOX mailbox_2; NU_MAILBOX mailbox_3; }MMAIL; /*定义多邮箱服务接口*/ Nucleus PLUS 参考手册 Translator:Novar 131 STATUS = MM_Create(MMAIL *mmail_control); STATUS = MM_Send(MMAIL *mmail_control,INT mailbox_id, VOID *message,UNSIGNED suspend); STATUS = MM_Receive(MMAIL *mmail_control, 下面是一个多任务挂起服务的C 源程序例子。(注:Nucleus PLUS 软件中不包含下面例子。) /*创建一个多任务控制块*/ STATUS MM_Create(MMAIL *mmail_control) /*创建单片控制块*/ NU_Create_Semaphore(&(mmail_control ->message_count), “MMCOUNT”,0,NU_FIFO); NU_Create_Mailbox(&(mmail_control ->mailbox_0), “MM_MB_0”,NU_FIFO);

52 NU_Create_Mailbox(&(mmail_control ->mailbox_1),
“MM_MB_1”,NU_FIFO); NU_Create_Mailbox(&(mmail_control ->mailbox_2), “MM_MB_2”,NU_FIFO); /*返回一个成功状态,虽然状态应该从每个先前调用被检测。*/ return(NU_SUCCESS); } /*发送一个消息到多邮箱对象*/ STATUS MM_Send(MMAIL *mmail_control, INT Mailbox_id, VOID *message, UNSIGNED suspend) { STATUS status; /*决定哪个邮箱发送请求*/ if (mailbox_id == 0) /*发送消息至邮箱0*/ status = NU_Send_To_Mailbox(&(mmail_control ->mailbox_0), message,suspend); else if (mailbox_id == 1) /*发送消息到邮箱1*/ status = NU_Send_To_Mailbox(&(mmail_control ->mailbox_1), else /*发送消息至邮箱2*/ status = NU_Send_To_Mailbox(&(mmail_control ->mailbox_2), Nucleus PLUS 参考手册 Translator:Novar 132 /*确定是否消息发送成功*/ if (status == NU_SUCCESS) /*递增计数信号量*/ NU_Release_Semaphore(&(mmail_control -> message_count)); /*返回状态至调用*/ return(status);

53 /*从多邮箱中一个接收消息*/ STATUS MM_Receive(MMail *mmail_control,VOID *message, UNSIGNED suspend) { STATUS status; /*获得消息信号量*/ status = NU_Obtain_Semaphore(&(mmail_control ->message_count),suspend); /*确定消息是否出现*/ if (status = NU_SUCCESS) /*寻找第一个有效消息,从邮箱0 开始*/ status = NU_Receive_From_Mailbox(&(mmail_control ->mailbox_0), message,NU_NO_SUSPEND); /*确定下一个邮箱是否需要被查询*/ if (status != NU_SUCCESS) /*检查邮箱1*/ status = NU_Receive_From_Mailbox(&(mmail_control->mailbox_1), else /*消息必须在邮箱2 中*/ status = NU_Receive_From_Mailbox(&(mmail_control->mailbox_2), /*返回一个完整的状态到调用*/ return(status); }

54 5.3 执行线程 一个Nucleus PLUS 应用程序总是八个可能运行线程中的一个。下面是所有那可能运行线程的列表。 初始化线程
初始化线程是系统运行的第一个线程。初始化线程的入口点为INT_Initialize。在Application_Initialize 函数返回之后,初始化线程中止,控制权转移到调度循环SchedulingLoop)上。 系统错误线程 有几个可能发生的系统错误,它们中大多数在初始化期间被跟踪。然而,堆栈溢出的条件在任务和HISR 运行时跟踪。这个线程在函数ERC_System 错误调用时执行。默认情况,系统错误是致命的,因此在这个线程中控制暂停。看附录B 中系统错误代码。 调度循环(Scheduling Loop) 调度循环发生入口在TCT_Schedule。这个线程执行响应转移控制权到最高优先级的HISR 上或任务就绪运行。当没有任务或HISRs 就绪运行,控制暂停在一个TCT_Schedule 简单的循环中。 任务线程 任务线程描述了应用程序的处理线程的多数情况。每个任务线程有它自己的堆栈。每个任务线程的入口在任务创建时指定。任务线程对完全访问Nucleus PLUS 服务没有限制。 信号处理器线程 信号处理线程运行在相关任务线程的顶端。信号处理器线程对Nucleus PLUS 服务访问有限制。主要的限制就是不允许自挂起。

55 用户ISR 线程 用户中断服务子程序线程是典型的少量汇编语言子程序,可以直接挂到中断向量。此线程负责保存和恢复所有使用的寄存器。对此类型线程,Nucleus PLUS 服务完全不受限。实际上,C 函数也不受限,除了线程不能通过编译器保存和恢复所有使用的寄存器。 LISR 线程 低级中断服务子程序在Nucleus PLUS 中注册。这样就允许Nucleus PLUS 保存和恢复所有有需要的寄存器。因此LISR 线程可以用C 语言写。LISR 线程对Nulceus PLUS 服务访问受限。最重要的就是active_HER 服务。 下列服务从LISRs 访问有效: NU_Activate_HISR NU_Local_Control_Interrupts NU_Current_HISR_Pointer NU_Current_Task_Pointer NU_License_Information NU_Retrieve_Clock HISR 线程 高级中断服务子程序形成了Nucleus PLUS 中断的第二部分。HISR 线程和任务线程一样被调度,也可以调用大多数Nucleus PLUS 服务。然而,HISR 线程不允许自挂起请求。HISR 子程序入口点在HISR 创建期间确定。

56 5.4 中断处理 Nucleus PLUS 既支持可控(managed)也支持不可控(unmanaged)ISRs。可控的ISR 就是不需要存储和释放上下文信息,不可控ISRs 对保存和恢复所有使用寄存器负全责。可控ISRs 可以用C 或汇编编程。不可控ISRs 一般都用汇编。 可控(Managed)ISRs 可控ISRs 在文中可以参照低优先级中断服务子程序(LISR)。LISRs 和传统ISR 运行方式相同,除了所有上下文压栈和恢复由Nucleus PLUS 管理 5.4.2 不可控ISRs(Unmanage ISRs) Nucleus PLUS 通过直接访问中断向量表(在大多数处理器架构中)支持不可控ISRs。NU_Setup_Vector 服务可以用来联合一个指定的中断向量到不可控ISR。二者选一,不可控ISR 的地址可以直接放到Nucleus PLUS 向量表中,在INT.S 文件中定义。 不可控ISRs 最典型的用法就是用于高频率中断。上下文信息(压栈资料)保存与恢复所消耗的资源数量与中断的频度成比例。当中断之间的时间与保存和恢复上下文信息所需时间取得相似成就时,就需要使用不可控ISRs。例如,如果一个中断每30uS 发生发生一次且可控中断需要15uS 的消耗,在中断管理上,处理能力丢失了一半。

57 5.5 I/O 驱动器 5.5.1 运用I/O 驱动器 Nucleus PLUS 提供一套基本I/O 驱动器设备。这些设备帮助提供了一个与周边硬件支持无关的 一致的驱动器接口。Nucleus PLUS 提供的基本IO 驱动器设备如下: 􀂾 创建IO 驱动器 􀂾 删除IO 驱动器 􀂾 请求IO 驱动器 在IO 驱动器可以使用之前必须被创建。这个由调用Nucleus PLUS 中NU_Create_Driver 服务完成。IO 驱动器的创建使得它被系统的其余部分所知。注:创建的IO 驱动器在创建期间不能被访问。如果IO 驱动器不再需要了可以被删除。Nucleus PLUS 服务U_Delete_Driver 执行此项功能。一个删除的IO 驱动器不再被访问。

58 5.5.2 驱动器执行 IO 驱动器信息干预了如何使用IO 驱动器。。IO 驱动器基本上是一个带开关陈述的C 函数。它们通常包括LISR 和HISR 中断处理器和自定义函数。所有Nucleus PLUS IO 驱动器有一个类似于下面模板的入口函数: VOID Driver_Entry(NU_DRIVER *driver,NU_DRIVER_REQUEST *request)

59 第六章 样例系统 本章提供一个Nucleus PLUS 系统样例的描述和完整代码列表。 6.1 样例概况 6.2 样例系统

60 6.1 样例概况 样例系统在本章描述,包含了一个应用程序初始化(Application_Initialize)函数和六个任务。所有任务都在初始化期间创建。除了任务运行,任务通信和同步在系统中都有实例。 在样例系统代码列表中,数据结构咱第5 和第26 行之间定义。Nucleus PLUS 控制结构在第7和第16 行之间定义。 Application_Initialize 在第36 行开始,在第93 行结束。 在这个例子中,所有系统对象(任务、队列、信号量和事件标志集)都在初始化期间创建。样例系统的任务在第47 行和80 行之间创建。通信队列在第85 行创建。系统信号量在第89 行创建。最后,系统事件标志集在第92 行创建。注:由第一个有效内存参数指定开始地址的20000 字节内存池在第47 行首次创建。这个内存池用于分配所有的任务堆栈和真正的队列区。 任务0 是系统启动后第一个运行的程序。这是因为任务0 是系统中优先级最高(priority 1)的任务。任务3 在任务0 挂起后运行(priority 5)。任务4 在任务3 挂起后执行。认识到为什么任务3 在任务4 之前运行非常重要,尽管他们有相同的优先级。原因就是任务3 创建且第一个启动(看Application_Initialize)。同样优先级任务按照他们就绪运行的顺序运行。在任务4 挂起后,任务5 运行(priority 7)。在任务5 挂起后,任务1 运行(priority 10)。最后任务2 在任务1因为队列满条件挂起后运行(priority 10)。 任务0 在第101 和126 行之间定义。和所有样例系统中的任务一样,任务0 做一些预备的初始化之后开始执行一个无限循环。任务0 无限循环的处理包括连续调用NU_Sleep 和NU_Set_Events。 因为NU_Sleep 的调用,任务0 循环每18 个定时器节拍运行一次。注:任务5 在每次调用 NU_Set_Events 函数时进入就绪状态。一旦任务5 优先级低于任务0,在任务0 再次运行NU_Sleep 调用之前,任务5 不会运行。

61 任务1 在第123 行和第165 行之间定义。任务1 连续发送单个32 位消息到队列0。当管道充满时,任务1 挂起,直到队列0 空间有效(有可用空间)。任务1 的挂起允许任务2 恢复运行。
任务2 在第181 和第223 行之间定义。任务2 连续从队列0 接收单个32 位消息。当队列为空时,任务挂起,直到队列0 空间有效(有可用消息)。任务1 的挂起允许任务2 恢复运行。 任务3 和任务4 共享同样的指令代码。然而,每个任务有它自己的唯一堆栈。任务3 和任务4 在232 和262 行之间定义。每个任务竞争一个二进制的信号量。一旦信号量被获得,在再次释放信号量之前任务休眠100 个时钟节拍。这种行为允许其他尝试获得同一信号量的任务运行和挂起。当信号量被释放时,等待信号量的挂起任务运行。 任务5 在267 和292 行之间定义。此任务在一个死循环中等待事件标志被置位。被等待的事件标志被任务0 置位。因此,任务5 和任务0 以同样的频率运行。

62 6.2 样例系统 下面时样例系统的源代码列表。注:左边的行号不是真正的文件中的一部分。这里的代码仅供参考。
1 /*包含必要的Nucleus PLUS 文件*/ 2 #include “nucleus.h” 3 4 5 /*定义应用程序数据结构*/ 6 7 NU_TASK Task_0; 8 NU_TASK Task_1; 9 NU_TASK Task_2; 10 11 NU_TASK Task_4; 12 NU_TASK Task_5; 13 NU_QUEUE Queue_0; 14 NU_SEMAPHORE Semaphore_0; 15 NU_EVENT_GROUP Event_Group_0; 16 NU_MEMORY_POOL System_Memory; 17 18 19 /*分配全局计数器*/ 20 UNSIGNED Task_Time; 21 UNSIGNED Task_2_message_received; 22 UNSIGNED Task_2_ invalid_messages; 23 UNSIGNED Task_1_messages_sent; 24 NU_TASK *Who_has_the_resource; 25 UNSIGNED Event_Detections; 26 27 28 /*定义引用函数的原型*/ 29 void task_0(UNSIGNED argc,VOID *argv); 30 void task_1(UNSIGNED argc,VOID *argv); 31 void task_2(UNSIGNED argc,VOID *argv); 32 void task3_and_4(UNSIGNED argc,VOID *argv); 33 void task_5(UNSIGNED argc,VOID *argv);

63 34 35 36 /*定义应用程序初始化子程序,初始化子程序决定初始化Nucleus PLUS 应用程 37 序环境*/ 38 39 void Application_Initialize(void *first_available_memeory) 40 { 41 VOID *pointer; 42 43 44 45 /*创建一个系统内存池将用于分配任务堆栈,队列区域等*/ 46 47 NU_Create_Memory_Pool(&System_Memory,”SYSTEM”, 48 first_available_memory,20000,50,NU_FIFO); 49 50 /*创建系统中的每个任务*/ 51 52 /*创建任务0*/ 53 NU_Allocate_Memory(&System_Memory,&pointer,1333, NU_NO_SUSPEND); 54 NU_Create_Task(&Task_0,”TASK_0”,task_0,0,NU_NULL,pointer, ,1,20,NU_PREEMPT,NU_START); 56 57 /*创建任务1*/ 58 NU_Allocate_Memory(&System_Memory,&pointer,1000, NU_NO_SUSPEND); 59 NU_create_Task(&Task_1,”TASK_1”,task_1,3,NU_NULL,pointer, ,10,5,NU_PREEMPT,NU_START); 61 62 /*创建任务2*/ 63 NU_Allocate_Memory(&System_Memory,&pointer,1333, NU_NO_SUSPEND); 64 NU_Create_Task(&Task_2,”TASK_2”,task_2,0,NU_NULL,pointer, ,13,5,NU_PREEMPT,NU_START); 66 67 /*创建任务3。注意任务4 用的同一个指令区*/ 68 NU_Allocate_Memory(&System_Memory,&pointer,1000, NU_NO_SUSPEND); 69 NU_Create_Task(&Task_3,”TASK_3”,task3_and_4,0,NU_NULL,

64 70 pointer,1000,5,0,NU_PREEMPT,NU_START);
71 72 /*创建任务4。注意任务3 使用同样的指令区*/ 73 NU_Allocate_Memory(&System_Memory,&pointer,1000, NU_NO_SUSPEND); 74 NU_Create_Task(&Task_4,”TASK_4”,task_4,3,NU_NULL,pointer, ,5,0,NU_PREEMPT,NU_START); 76 77 /*创建任务5*/ 78 NU_Allocate_Memory(&System_Memory,&pointer,1000, NU_NO_SUSPEND); 79 NU_Create_Task(&Task_5,”TASK_5”,task_5,0,NU_NULL,pointer, ,7,0,NU_PREEMPT,NU_START); 81 82 /*创建通信队列*/ 83 NU_Allocate_Memory(&System_Memory,&pointer, 100 *sizeof(UNSIGNED),NU_NO_SUSPEND); 84 NU_Create_Queue(&Queue_0,”QUEUE_0”,pointer,100,NU_FIXED_SIZE,1,NU_FIFO); 85 86 /*创建同步信号量*/ 87 NU_Create_Semaphore(&Semaphore_0,”SEM_0”,1,NU_FIFO); 88 89 /*创建事件标志集*/ 90 NU_Create_Event_Group(&Event_Group_0,”EVGROUP0”); 93 94 /*定义任务0。任务0 每18 个时钟节拍递增一次Task_Time 变量。另外,任务 95 0 置位任务5 正在等待的事件标志集,每个循环一次反复*/ 101 void task_0(UNSIGNED argc,VOID *argv) 102 { 103 104 STATUS status; 105 106 107 *访问argc 和argv 只是为了避免编辑警告*/ 108 status = (STATUS) argc + (STATUS)argv; 109 110 /*设置时钟为0。这个时钟每18 个系统定时器节拍为一拍。*/ 111 Task_Time = 0;

65 112 113 while(1) 114 { 115 116 /*休眠18 个定时器节拍。在IND.ASM 中时钟节拍值可编程,且与目标系统的 速度有关*/ 118 NU_Sleep(18); 119 120 /*递增次数*/ 121 Task_Time++; 122 123 /*设置事件标志来消除任务5 的挂起*/ 124 NU_Set_Events(&Event_Group_0,1,NU_OR); 125 } 126 } 127 128 129 /*定义队列发送任务。对列满条件和配置文件指定的时间片导致任务挂起。*/ 130 131 132 133 void task_1(UNSIGNED argc,void *argv) 134 { 135 136 STATUS status; 137 UNSIGNED Send_Message; 138 139 /*访问argc 和argv 只是为了避免编辑警告*/ 140 status = (STATUS)argc + (STATUS)argv; 141 142 /*初始化消息计数器*/ 143 Task_1_messages_send = 0; 144 145 /*初始化消息内容。接收器将检查消息内容是否错误。*/ 146 147 Send_Message = 0; 148

66 149 while(1) 150 { 151 152 /*发送消息到Queue_0,任务2 从里面读。注意如果目标队列充满,这个任务挂 起直到空间有效*/ 154 status = NU_Send_To_Queue(&Queue_0,&Send_Message,1,NU_SUSPEND); 157 158 /*确定消息是否发送成功*/ 159 if (status == NU_SUCCESS) Task_1_message_sent++; 161 /*修改下一个发送消息的内容*/ Send_Message++; 164 165 166 167 168 /*定义队列接收任务。注意队列空条件和配置文件指定的时间片导致任务挂起*/ 169 170 180 181 void task_2(UNSIGNED argc,VOID *argv) 182 183 184 STATUS status; 185 UNSIGNED Receive_Message; 186 UNSIGNED received_size; 187 UNSIGNED message_expected; 188 189 /*访问argc 和argv 只是为了避免编辑警告*/ 190 status = (STATUS)argc + (STATUS)argv; 191 192 /*初始化消息计数器*/ 193 Task_2_message_received = 0; 194 195 /*初始化消息错误计数器*/ 196 Task_2_invalid_messages = 0;

67 197 198 /*初始化消息内容为期望值*/ 199 message_expected = 0; 200 201 while(1) 202 203 204 /*从Queue_0 重新获得任务1 写入的消息,注意如果源队列为空,这个任务挂起知道有东西可用*/ 206 207 status = NU_Receive_From_Queue(&Queue_0,&Receive_Message,1,&received_size,NU_SUSPEND); 209 210 /*确定消息是否接收正确*/ 211 if (status == NU_SUCCESS) Task_2_message_received++; 213 214 /*检测消息内容是否与任务期望一致*/ 215 216 if ((received_size !=) || (Receive_Message != message_expected)) Task_2_invalid_messages++; 219 220 message_expected++; 221 222 223 224 225

68 226 /*Task_3_and_4 只想要单个资源。一旦其中一个任务获得资源,它将在释放
227 它之前保持33 个时钟节拍。在这期间,其他任务挂起等待这个资源。注意任务3 和都使用同样的代码区但是堆栈不一样。*/ 229231 232 void task_3_and_4(UNSIGNED argc,VOID *argv) 233 { 234 235 STATUS status; 236 237 /*访问argc 和argv 只是为了避免编辑警告*/ 238 status = (STATUS)argc + (STATUS)argv; 239 240 /*循环分配和收回资源*/ 241 while(1) 242 { 243 244 /*分配资源。挂起知道它变得有效*/ 245 status =NU_Obtain_Semaphore(&Semaphore_0,NU_NU_SUSPEND); 247 /*如果status 为成功,显示这个任务拥有资源*/ 248 249 if (status == NU_SUCCESS) 250 { 251 Who_has_the_resource = NU_Create_Task_Pointer(); 253 254 /*休眠100 个时钟节拍导致其他任务挂起等待资源*/ 255 256 NU_Sleep(100); 257 258 /*释放信号量*/ 259 NU_Release_Semaphore(&Semaphore_0); 260 } 261 } 262 } 263

69 264 265 /*定义等待任务0 设置事件的任务*/ 266 267 void task_5(UNSIGNED argc,VOID *argv) 268 { 269 270 STATUS status; 271 UNSIGNED event_group; 272 273 274 /*访问argc 和argv 只是为了避免编辑警告*/ 275 status = (STATUS)argc + (STATUS)argv; 276 277 /*初始化事件跟踪计数器*/ 278 Event_Detections = 0; 279 280 /*永远继续这个处理*/ 281 while(1) 282 { 283 284 /*等待一个事件且消耗它*/ 285 status = NU_Retrieve_Events(&Event_Group_3,1, 286 NU_OR_CONSUME,&event_group,NU_SUSPEND); 287 288 /*如果status 成功,递增计数器*/ 289 if (status == NU_SUCCESS) 290 Event_Detections++; 291 } 292 }


Download ppt "Beyond Technology NEUCLEUS的原理和应用 (Ver0.9) IS事业部 孙丕宏."

Similar presentations


Ads by Google