freescalemc9s08单片机原理与应用第06章(编辑修改稿)内容摘要:

/void main (void){ MyFunction()。 /* 第一次进入MyFunction之前,myVar=0 */ MyFunction()。 /* 第二次进入MyFunction之前,myVar=1 */}void MyFunction (void){ static char myVar = 0。 /* 本地变量声明为static */ myVar = myVar + 1。 /* myVar是本地变量,但它保持了自己的值 */} 以上程序的结果为,在第一次调用函数MyFunction()后,变量myVar等于1,第二次调用后,变量myVar等于2。 6. 关键字“static”的使用 在函数体内声明的静态变量,在函数调用期间保持其值不变; 在模块内声明的静态变量,能被模块内所有函数访问; 在模块内声明的静态函数,只能被模块内函数调用。 7. 可变(volatile)变量 可变变量是其值在正常程序流程以外可能改变的变量。 在嵌入式系统中,主要有两种引起这个现象的原因: 一是中断服务程序,二是硬件动作。 例如,通过串口接收到一个字符,然后串口状态寄存器的值会发生改变,这完全在程序流程之外发生。 在嵌入式设备中,最好将所有外设寄存器声明为volatile。 下面通过一个例子来看看编译器是怎样处理一个volatile和一个非volatile变量。 volatile unsigned char PORTA @0x00。 volatile unsigned char SCS1 @0x16。 unsigned char value。 void main(void) { PORTA = 0x05。 /* PORTA = 00000101 */ PORTA = 0x05。 /* PORTA = 00000101 */ SCS1。 value = 10。 } 未使用volatile关键字,编译器将其编译为:CLIMOV 0X05,0X00LDA 0X0ASTA 0X0100STA 0X1800使用volatile关键字后,编译器将其编译为:CLIMOV 0X05,0X00MOV 0X05,0X00LDA 0X16LDA 0X0ASTA 0X0100STA 0X1800 这段代码实际上不做任何事,但它很好地表达了优化怎样强烈地影响程序的结果。 在main()函数中连续两次使用语句“PORTA=5。 ”,这没有意义,但让我们假设这是正确开发程序所必需的。 在这两个语句之后,明显地有一条无意义语句“SCS1。 ”。 让我们看当不使用volatile变量会发生什么。 我们得到了优化过的汇编代码。 重复的语句“PORTA=5。 ”消失了,只剩下一句“STAB 0x300”。 语句“SCS1。 ”似乎什么都不做,因此聪明的编译器将它消去了。 最后,将10加载到累加器并存储。 使用volatile关键字声明PORTA 和SCS1,得到的汇编代码没有优化,连续两次在PORTA写入数值5,然后将SCS1加载到累加器。 最后由于累加器被使用,于是用X寄存器存储数据10。 加载SCS1到累加器是很有用的,这是串行通信接口SCI需要的,读SCS1寄存器目的是清除任何未决的标志。 无意义的语句“SCS1。 ”被翻译为读寄存器的的汇编语句,这将清除SCI中未决的标志。 在嵌入式设备中将所有外设寄存器声明为volatile是一个好习惯。 在分开的头文件中定义所有外设的名字,能使所写代码更友好并简化移植。 8. Const变量 关键字“const”是C语言中命名最差的关键字,它并不表示恒量,而是代表“只读”。 在嵌入式系统中,这点就有很大的不同了。 const声明可用于任何变量,它告诉编译器将其存贮在ROM区,所以如此声明的变量值是不可以改变的。 由于它作为常量工作,必须赋初值。 如:const double PI =。 const 变量与明显的常数相对,很多原文要求用const变量代替明显的常数。 例如:用“const unsigned char channels = 8。 ”代替“define CHANNELS 8”。 Const的用法:const unsigned short a。 unsigned short const a。 const unsigned short *a。 unsigned short * const a。 9. Const volatile 变量 现在讨论一个深奥的问题,一个变量既能是常量,又能是可变量吗。 如果是这样,这意味什么,怎样使用。 答案是“能”。 这个修饰符应该用于能出乎意料地改变任何存储器位置,因此需要volatile限定语, const代表变量是只读的。 最明显的例子是硬件的状态寄存器,像SCI状态寄存器SCS1。 这个寄存器包含信号状态标志,如发送空、发送完成、接收满和其他标志位。 这是一个依赖于串口通信状态的可变寄存器,但标志不能被程序直接改写,所以是只读的,它们只对模块的状态作出响应。 这个状态寄存器最佳声明方法是: const volatile unsigned char SCS1 @0x0016 资源映射1. 访问固定的内存位置 嵌入式系统的特点是需要编程者访问一个指定的存储器位置。 比如在某个项目中需要将绝对地址0x2FFA处的整型变量值设为0xAA55。 完成这个任务的代码是: int * ptr。 ptr = (int *)0x2FFA。 *ptr = 0xAA55。 2. 访问I/O寄存器 在嵌入式领域,需要管理和访问微控制器的片上资源,比如I/O寄存器和控制寄存器等。 那么怎样访问这些寄存器呢。 一个方法是使用“define”定义: define PORTA ( * ( volatile unsigned char * ) 0x0000 ) 这就构成了I/O寄存器,PORTA为地址0x0000处字符型变量。 “define”实际做的是每次发现PORTA时放置一个构件。 也就是说在代码中写“PORTA = 0x3F”,实际做的就是告诉编译器0x0000是一个“volatileunsignedchar”类型的指针,它的内容为0x3F。 另一个方法是在变量声明中使用符号“@”,在地址0x0000处创建一个 volatileunsignedchar型的变量PORTA。 volatile unsigned char PORTA @0x0000。 这是一个编译器特定的语法,它可读性高,但兼容性不好。 如果使用另一个编译器去编译该代码,就发现“@”不能够被识别。 CodeWarrior支持这个特殊语法。 C编译器允许在代码中使用汇编指令,具体形式见如下代码:_asm AssemblyInstuction。 asm (AssemblyInstruction)。 asm { AssemblyInstruction AssemblyInstruction }3. 位操作 在嵌入系统中,在一个给定的地址,一次能访问和修改数据的一位或几位。 C语言有很多方法来完成这个任务。 位结构: 效率随编译器的不同而改变,不具。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。