codewarrior使用详细说明.ppt
,Transition Title,Codewarrior使用指南,田云锋汽车电子 现场应用工程师2005年6月R,Slide 2,内容,codewarrior简介 利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 3,项目创建,Project creationImportant choices are made(derivative,language,targets used for the development)Usually difficult to change any of these once the project is startedCodeWarrior solution:Project WizardIntuitive menu to guide the developer through the selection process,Choice of the derivative,Choice of the language(Absolute assembly,assembly,C,C with Processor Expert,C+)Choice of target(simulator,various hardware connections)Other options(PC-Lint,Board support packages)Complete project template prepared with files,developer can just“insert the code here”,ProjectCreation,H/W SpecificCode generation,Application SpecificCode Development,Test/Debug&Validation,H/W S/WIntegration,ProjectWizardDerivativeLanguageTargets,Slide 4,Hardware specific code,Hardware specific code generationDevelopers have to understand the details of peripheral registers,bit fields,setup and access sequencesTrend is for more and complex peripherals,with more registers,increasing the effort of writing accurate code for each peripheral of the derivative.But there is no added value from a project stand point,all applications need some from of code to perform the function,ProjectCreation,H/W SpecificCode generation,Application SpecificCode Development,Test/Debug&Validation,H/W S/WIntegration,ProcessorExpert,DerivativesKnowledgeDatabase,CodeWarrior solution:Processor Expert-Application design tool using knowledge database,-Graphical selection of peripheral parameters,-Auto-generation of low-level drivers,-High-level beans available,-Makes the users manual easy.,Slide 5,Application specific code,Application specific code developmentNeed a user-friendly editor,be able to develop absolute assembly code,need an efficient compiler(code size,speed)CodeWarrior solution:IDE,Editor,Assembler,Compiler,LinkerIDE with utilities such as file compare,project settings,target settingsMulti-pane color coded editor,go to code definition,go to procedures definitionAbsolute assembler and reallocateable assemblerCompiler with 50+optimizationsLinker with editable parametersprojects that change often or have multiple developers.,ProjectCreation,H/W SpecificCode generation,Application SpecificCode Development,Test/Debug&Validation,H/W S/WIntegration,Editor,Compiler,Assembler,Linker,Slide 6,Test,debug and validation,Test,debug and validationWithout simulator,it is impossible to test software until hardware is available,Developers have to make up for delays at the critical stage,reducing testing,integration and quality,Improved code validation will reduce product maintenance,reduce“end of project”costs.CodeWarrior solution:IDE,Debugger and Simulator,Data Visualization,I/O Stimulation,ProjectCreation,H/W SpecificCode generation,Application SpecificCode Development,Test/Debug&Validation,H/W S/WIntegration,DebuggerMulti-TargetInterface,Simulator,DataVisualization,I/O Stimulation,RTOSawareness,Project manager allowing target specific files selection and system settingsFully configurable debugger,Instruction set accurate simulator,I/O simulationData Visualization(direct,command files)I/O Stimulation(direct,command files)RTOS awareness(e.g.OSEK),Slide 7,Hardware and software integration,Hardware and software integrationWithout simulation,developers risk of getting H/W and S/W problems mixed up(none has been qualified yet),Developers have difficulties to compare a working case(simulation)with a non-working case(hardware target),CodeWarrior solution:Same as previous slide plus:Easily switch between targets for comparison of resultsData Visualization and I/O stimulation(simulation and targets)Flash programming supportRTOS awareness(e.g.OSEK)Foreign target capability through API,ProjectCreation,H/W SpecificCode generation,Application SpecificCode Development,Test/Debug&Validation,H/W S/WIntegration,DebuggerMulti-TargetInterface,Simulator,Multilink,DataVisualization,I/O Stimulation,RTOSawareness,USB(e.g.inDart),API,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程嵌入式编程注意事项 如何使用Processor Expert,Slide 9,创建新工程 1,1、创建新工程,3、输入工程名,2、选择HCS12 New Project Wizard,Slide 10,创建新工程 2,4、选择MCU类型,5、选择语言类型,Slide 11,创建新工程 3,6、选择是否采用Processor Expert,7、选择是否使用PC-lint,如果用Processor Expert,选择 Yes,Slide 12,创建新工程 4,8、选择是否用浮点运算,9、选择存储器类型,Slide 13,创建新工程 5,10、选择调试器类型,Slide 14,源程序文件夹,Start up文件夹,Prm文件夹,Map文件夹,库文件夹,代码长度,变量长度,是否被包含在Target中,是否产生调试信息,列出相关文件,编译,调试,Slide 15,参考文献,Codewarrior manuals/pdf/IED_Users_Guide.pdf,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程嵌入式编程注意事项 如何使用Processor Expert,Slide 17,在新项目中加入或删除文件,点击右键,加入或从此工程中删除文件,新建一文件,并保存到原文件夹中,如果编译时,出现没有调试信息警告,请点击这里,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程嵌入式编程注意事项 如何使用Processor Expert,Slide 19,无限循环,While(1);For(;);Loop:goto Loop;,对嵌入式系统来说:循环是必须要用到的.上述3种方式,第2种更好一些为什么?,因为它不会产生警告信息“always true warning”,Slide 20,编译器优化,CodeWarrior编译器提供了几种从C源代码产生实际汇编代码的优化方法,这些代码被下载到微控制器中全局优化设置面板设定编译器怎样优化目标代码。所有优化程序重新组织目标代码,不影响其逻辑执行顺序。,Slide 21,编译器优化 强度减弱,“Strength Reduction”(强度减弱)是一种优化,力争用开销小的操作代替开销大的操作,所要付出的代价是执行时间或代码大小。在循环内,用加法指令代替乘法指令。下列例子将演示编译器,根据具体应用,来决定哪一种操作用最少代价达到同样结果。,Slide 22,这个变量乘以3,Slide 23,用乘法来实现,Slide 24,变量乘以4,Slide 25,用 2 次左移位来实现.用H:X作为指针来指向我们想要乘的值,Slide 26,这句话等同于 VarA=VarA*4;,Slide 27,编译器优化 死代码消除,死代码消除就是编译器在优化应用程序时,对没被使用的语句将不产生可执行代码 去除逻辑上从未执行的语句或没有被其他语句提到的语句,Slide 28,Slide 29,Slide 30,Slide 31,编译器优化消除死赋值,消除死赋值就是指编译器移去变量在再次赋值之前没有被使用的赋值在下面编译器优化的例子,我们将演示通过改变编译器的优化设置,达到改变CodeWarrior产生代码的方式。,Slide 32,Slide 33,Slide 34,Codewarrior HC08 Compiler Options Settings,Slide 35,所有的代码将被忽略,Slide 36,在循环中用到的变量定义成全局变量,Slide 37,这段代码并没有忽略掉,因为它是全局变量,有可能会被硬件(中断)用到,Slide 38,在循环内复制代码,目的是展开分支操作下面的例子演示一下循环解开是如何工作的:,编译器优化 循环解开,通过改变编译器设置,我们可选择不同的优化项,在生成代码时将会有差异,Slide 39,示例(没有循环解开):,编译器产生与4次循环相关的代码。,Slide 40,示例(有循环解开):,相同的代码,但改变设置为“loop unrolling”,编译器产生如下代码。,相当于把循环展开for(i=0;i 4;j+)Array i=i;-Array 0=0;Array 1=1;Array 2=2;Array 3=3;,Slide 41,更多的优化选项:,Slide 42,更多的优化选项:,Slide 43,条件编译,编译指示符:#if、#else、#elif、#endif这些指示符均用于条件编译:#if#else OR#elif#endif只有当条件表达式的值不为零时,才编译跟有#if指示符的行。否则以后的行都被跳过直到遇到匹配的#else或endif。#error定义一个用于显示的编译错误。,Slide 44,对于嵌入式系统:同一源代码支持多平台;源代码的适应性(在编译时设置),利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程嵌入式编程注意事项 如何使用Processor Expert,Slide 46,模拟调试器界面,工具条,Slide 47,模拟调试器:特点,功能强大的图形界面(拖&拉操作,弹出式菜单.).模块化和可扩展系统(基于组件概念).不同的组件可以加入:来自Metrowerks(Codewarrior)公司的组建来自半导体公司的组件用户组件对所有的目标和目标接口,界面(GUI)完全相同,Slide 48,模拟调试器:界面,对不同的simulator和debugger,界面完全相同。对所有的CPU,界面完全相同。仅仅是子窗口中的内容不同。,Slide 49,模拟调试器:界面,断点信息,汇编指令地址,汇编指令机器码,汇编指令,Profiling 信息(代码所花时间百分比),源代码,高级语言展开/折叠命令,覆盖信息,Slide 50,模拟调试器:界面,CPU 寄存器,存储区地址,存储区中的内容,存储区中的内容(字符),Slide 51,模拟调试器:界面,执行的函数,目标类型,目标列表,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 53,启动程序,Startup Code一般用汇编语言写的,并且会连接到你编译过的可执行的模块中.它为执行C语言写的程序做准备:,关闭中断把初始化过的数据从ROM中拷贝到RAM中将未初始化数据区清零给堆栈分配空间并初始化创建并初始化堆开放中断调用main(),Slide 54,Slide 55,复位后第一个执行的是启动程序,复位向量存贮了_startup()所在位置,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 57,代码放在哪里?,在*.PRM文件中,SECTIONS命令块用于定义存贮器的物理区域。在SECTIONS命令块中,每个单独的物理存贮器段用一个名字、一个属性和一个地址范围描述PLACEMENT命令块用于将代码和数据段定位到存贮器段,“.CodeWarrior ManualspdfManual_SmartLinker.pdf”C:Program FilesMetrowerksCW08 V3.1Technical NotesBuildToolstn04.pdf,Slide 58,#pragma,Slide 59,存储区分配,Slide 60,代码放在哪里?,变量放在Default_RAM 的位置,除非另外规定一个PRAGMA声明频繁使用的变量应放在直接页RAM($40-$FF)在直接页中访问操作数采用直接寻址模式(8位寻址模式)比扩展寻址模式(16位寻址模式)少一个时钟周期,Slide 61,数据段(VarA)想存放在一个特定区域内(0 x0080-0 x00A9),Slide 62,Slide 63,Slide 64,funcition1 被放在 FunctionsROM代码段中,其地址为 0 xEF00 到 EFFF,Slide 65,常数段想存放在特定的位置,Slide 66,Slide 67,Slide 68,数组存在我们期望的位置,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 70,如何对IO进行操作?,利用Codewarrior头文件中已经定义好的IO寄存器或者:#define PortA(*(volatile unsigned char*)0 x0000)或者volatile unsigned char PortA 0 x0000;,Slide 71,访问固定内存位置,嵌入式系统通常的特点是需要编程者访问一个指定的存贮器位置。练习:在某个项目中需要将绝对地址0 xFFA处整型变量的值设为0 xAA55(编译器为纯粹的ANSI编译器)。完成这个任务的代码是:,Int*ptr;ptr=(int*)0 x2FFA;*ptr=0 xAA55;,Slide 72,访问CPU寄存器,CPU中的寄存器没有对应的固定地址可以用汇编指令对它们进行访问C语言无法直接访问这些寄存器C编译器允许在C代码中使用汇编指令,1)_asm AssemblyInstuction;2)asm(AssemblyInstruction);3)asm-,Slide 73,修改CPU中CCR寄存器的I位,Slide 74,利用汇编指令来修改 I 位,Slide 75,位域,位结构效率随编译器的不同而改变;不同的编译器不能移植。位类型无法移植提高代码效率移位和屏蔽可移植,合理提高效率经常被优化成位操作,Slide 76,联合体是一个变量,不同的时间表示不同的类型和大小的对象,编译器会根据要求决定变量的大小。,Slide 77,联合体提供一种可以对单一存贮区不同类型数据操作的方法,程序中没有嵌入任何依赖于机器的信息,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 79,CodeWarrior 编译器提供了一种非ANSI标准的方式来实现中断:,中断向量表分配 MCU 数据手册,在 C 源文件中,中断服务程序前面加“interrupt 中断向量号”,int time_counter;interrupt 7 INT_Timer(void)time_counter+;,方法1:利用关键字 interrupt:,Slide 80,中断向量表分配 MCU 数据手册,Slide 81,方法2:在PRM文件中声明,在PRM文件中声明,在C代码中写中断服务程序,#pragma TRAP_PROCvoid INCcount(void)int card1;tcount+;,在 PRM 文件中,将中断服务程序名和中断向量地址对应,VECTOR ADDRESS 0 xFFF0 INCcount,Slide 82,方法3:在向量表中初始化,Slide 83,利用interrupt关键字声明中断服务程序,Slide 84,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 86,如何使用汇编和C语言混合编程,汇编和C语言中使用相同的符号(变量及函数名)注意参数传递规则注意函数返回值原则注意目标文件格式(Elf-Dwarf or HIWARE).接口模块(C/Assembly)或(Assembly/C),Slide 87,在C中访问汇编变量,Slide 88,在汇编中访问C变量,Slide 89,在C中调用汇编函数,Slide 90,在汇编中调用C函数,函数(C代码中),void AddVar(unsigned int first,unsigned int second)ASMData=Cdata+first+second;,函数声明(汇编),XREF AddVar,在汇编中调用C函数,LDD CData;Load value of Cdata in D PSHD;PUSH D on the stack LDAB#10;Load 10 in D CLRA JSR AddVar,利用向导创建一个新工程项目 在新项目中加入或删除文件 编译 调试 启动程序 PRM文件设置 如何对IO及寄存器进行操作 如何写中断程序 如何使用汇编和C语言混合编程 嵌入式编程注意事项 如何使用Processor Expert,Slide 92,嵌入式编程 vs.PC编程,嵌入式编程环境的主要特点:有限的RAM;有限的ROM;有限的栈空间;面向硬件编程;严格的定时(ISR,任务,);很多不同种类的指针(far/near/rom/uni/paged/);特殊关键字/标识符(,interrupt,tiny,),Slide 93,数据类型,通过为变量选择最合适的数据类型可以最大程度地得到最短的代码和执行时间 8位微控制器内部的数据的长度是8位(一字节),然而C首选的数据类型是int 8位机处理8位数据类型比16位数据类型效率更高“int“和大数据类型只有当所描述的数据的大小需要时才使用 当优先考虑代码效率时,双精度和浮点操作效率低,应当避免,Slide 94,HC08的数据类型,ANSI标准没有精确定义数据类型的大小,但是 CodeWarrior 定义了.,0,255,Slide 95,默认CodeWarrior 的数据类型,所有的基本数据类型可以被改变但是建议尽量使用默认值,Slide 96,数据类型选择,对8位MCU,在选择数据类型时,有3条原则:尽量使用最小的数据类型尽可能使用无符号数 在表达式内声明数据类型,以便将数据类型减小到最小(强制类型转换),使用typedefs得到固定的大小-根据编译器和系统而改变-移植到不同的机器代码不变-当值需要固定位时使用,Slide 97,定义完整的数据类型,在main函数里声明了3种不同数据类型的变量,Slide 98,仅最后面的位写入值;并且使用了一个寄存器,每个变量的其余位被清零clr,X,变量在堆栈里有一个地址,Slide 99,在main函数里声明了3种不同数据类型的变量,Slide 100,Slide 101,所有声明的全局变量均被使用。,Slide 102,在这种情况下,编译器为所有变量保留了内存,Slide 103,变量声明的内存区,每个变量有不同的大小(1、2和4字节),根据变量大小的不同,每个加操作用不同的方法完成,Slide 104,修饰符,以下关键字用于声明变量,以指定特定需要或内存中变量存贮的相关条件。Staticvolatile const这三个关键字,一起让我们不仅可写出好的代码,而且可写出紧凑的代码,Slide 105,静态变量,使用静态变量有二个主要功能:第一个最常用的用法是定义一个变量,在函数连续调用期间,变量不会消失。第二个使用静态的用法是限制变量的范围。在模块级定义时,能被整个模块中所有函数访问,不能被其它模块中的函数访问,Slide 106,静态变量示例,FILE1.c#include/includes functions contained in file/FILE2.cvoid main(void)MyFunction();/included in FILE2.c MyFunction();/included in FILE2.c,FILE2.cvoid MyFunction(void)/Definition of MyFunction in FILE2.C static char myVar=0;/local variable declared static myVar=myVar+1;,Slide 107,静态函数,静态函数只能被其所在模块中的其它函数调用使用静态函数是结构化编程的好习惯静态函数能产生小而快的代码编译器在编译时确切地知道什么函数能调用一个给定的静态函数。因此,函数的相关内存区域能被调整,以致使用调用的一个短版本或跳转指令,Slide 108,Volatile变量,在嵌入式系统中,这种情况通过两种主要途径发生:通过一个中断服务程序硬件动作的结果 例如,通过一个串口接收到一个字符,结果串口状态寄存器更新,这完全在程序流程之外发生。很多程序员知道编译器不会试图优化一个volatile寄存器,而宁可每次重载它,Volatile变量其值在正常程序流程以外可能改变的变量,Slide 109,volatile的变量从不会被编译器优化,访问定义为volatile的变量从不会被编译器优化,volatile unsigned char PORTA 0 x00;volatile unsigned char SCS1 0 x16;unsigned char value;void main(void)PORTA=0 x05;/*PORTA=00000101*/PORTA=0 x05;/*PORTA=00000101*/SCS1;value=10;,Slide 110,Volatile 变量示例,/*MC68HC908GP20/32 Official Peripheral Register Names*/volatile unsigned char PORTA 0 x0000;/*Ports and data direction*/volatile unsigned char PORTB 0 x0001;volatile unsigned char PORTC 0 x0002;volatile unsigned char PORTD 0 x0003;volatile unsigned char PORTE 0 x0008;volatile unsigned char DDRA 0 x0004;/*Data Direction Registers*/volatile unsigned char DDRB 0 x0005;volatile unsigned char DDRC 0 x0006;volatile unsigned char DDRD 0 x0007;volatile unsigned char DDRE 0 x000C;volatile unsigned char PTAPUE 0 x000D;/*Port pull-up enables*/volatile unsigned char PTCPUE 0 x000E;volatile unsigned char PTDPUE 0 x000F;,Slide 111,Const 变量,Const声明可用于任何变量,它告诉编译器将其存贮在ROM区中 编译器保留了那个位置程序存贮器地址。由于位于ROM中,其值不能改变 Cons变量必须初始化比如:const double PI=3.14159265;,Slide 112,Const修饰符,Const 变量与明显的常数相对,很多文章要求用const变量代替明显的常数。例如:用const unsigned char channels=8;代替#define CHANNELS 8。本方法的基本原理是在调试器内部,你能检查一个const变量,然而一个明显的常数不可访问。不幸的是,在很多8位机上你将为这一好处付出极大的代价。这两个主要代价是:一些编译器在RAM中创建一个真实的变量来支持cost变量,这是一个极大的惩罚。一些编译器如CodeWarrior,知道变量为const,将把变量存贮在ROM中。无论怎样,变量仍作为变量处理和访问,典型地用某些变址寻址(16位)的方式。与直接寻址(8位)方式相比,这种方法通常很慢。,Slide 113,Const volatile 变量,一个变量既能是常量,又能是可变量吗?答案是“能”。这个修饰符应该用于能出乎意料地改变的任何存贮器位置,因此需要volatile限定语,由于const该变量是只读的。最明显的例子是硬件状态寄存器,象SCI状态寄存器SCS1。这个寄存器包含信号状态标志,如发送空、发送完成、接收满以及其它。这是一个可变寄存器由于这些标志的改变依赖于串行通信的状态,这也是只读,由于标志不能被程序直接改写,它们只对模块的状态作出响应。这个状态寄存器最佳声明方法是:/*SCI Status Register*/const volatile unsigned char SCS1 0 x0016,Slide 114,栈指针与函数参数,栈指针支持C的关键特性:在汇编程序和C编译器中,堆栈通常用于给子程序传递变量;允许使用递归;是自动变量的基础。典型地子程序将把需要的操作数放入累加器。堆栈相对寻址允许访问堆栈上的数据,提供直接访问操作数。排除从堆栈压入以及弹出数值所需要的代码和时间,堆栈指针指令与等份的变址指令相比需要一个额外的字节和一个额外的执行周期。,typedef struct unsigned charID;unsigned shortTime;ObjectType;void foo(unsigned char value)volatile ObjectType instance;instance.ID=value;,Slide 115,堆栈指针寻址,堆栈指针相对寻址进一步增强了C代码的效率。有两种类型:8位偏移的堆栈指针相对寻址 16位偏移的堆栈指针相对寻址它们和间接寻址方式工作相似,但使用堆栈指针代替H:X变址寄存器。注意当中断不允许时可用堆栈指针作为额外的变址寄存器。,Slide 116,堆栈帧,帧指针函数通常有一个包含其所有本地数据的堆栈帧。编译器并不设置一个明白的帧指针,但堆栈上的本地数据和参数都根据SP寄存器访问。入口代码 通常入口代码是一系列为本地变量保留空间的指令:PSHA;仅当有寄存器参数 PSHX;仅当有寄存器参数 AIS#(-s);为本地变量保留空间 S是函数的本地数据的大小(单位:字节)出口代码 出口代码从堆栈中移除本地变量,并返回到调用者:AIS#(t);移除本地栈空间,包括最终的寄存器参数RTS;返回调用者,Slide 117,除函数返回一对象大于二字节,函数结果都返回到寄存器中。依据返回类型,使用不同的寄存器。如下表所示:返回大对象:函数返回大于二字节的对象均与一个附加的参数一起调用,它被传到H:X。这个参数是对象应复制到的地址。,HC08返回值,Slide 118,声明了四个不同类型的函数,每个函数返回一不同类型的变量,每个函数有一个不同类型的参数(void,byte,word),Slide 119,被调用的函数跳转到其源码所在的地址,函数返回用 RTS指令,Slide 120,参数在寄存器A中,Slide 121,Slide 122,A用作参数寄存器,也用作直接寻址数组中的字节,Slide 123,函数指针,函数指针与数据指针一样有用处:当你想用一个间接访问当你想用同一段代码,根据环境的不同调用不同的函数,Slide 124,定义指向函数的指针,下面的代码定义了一个指向函数的指针,带了一个整型参数并返回一整数:int(*function)(int);(*function)括号是必须的,因为定义中的优先关系。没有括号,则表示定义了一个函数返回一个整型指针,Slide 125,Example:,pf 是一个静态函数指针,INT是参数,返回值为voidvoid fna(INT);/Example prototype of a function to be calledtypedef void(*const PFV_I)(INT);/Declaration using typedefstatic PFV_I pf=fna,foo2,foo3,foo4);/Direct declarationstatic void(*const pf)(INT)=fna,foo2,foo3,foo4;/Example useINT a=6;pfjump_index(a);/Calling method 1(*pfjump_index)(a);/Calling method 2,Slide 126,Example:,函数指针初始化,现在函数指针指向另一个函数,周期性中断毁调用函数指针指向的函数,Slide 127,HC08QL 示例,SLIC 模块仅有一个中断用户必须读取状态向量寄存器SLIC State Vector register(SLCSV)来确定中断源可能 C 代码:Switch-case Nested ifs(if嵌套)Pointers to functions(函数指针),Slide 128,Slide 129,Debug(1):,Slide 130,Debug(2):,Slide 131,Debug(3),Slide 132,When to use pointers:,if 嵌套可读性好,当使用函数少时,代码较小 Switch 可读性最好,代码最大 Pointers 函数越多,产生的代码少,但是RA