1.6 变量、存储类型与存储模式 |
|
全局(global)变量定义在函数外面,生命期从所定义的地方开始,其后面的所有函数都可以读/写该全局变量。本书有关案例在使用定时器/计数器(Timer/Counter)时,为得到更大的延时值,程序中定义了全局变量tCount,在定时器中断内对该变量累加,从而得到更大的延时间隔,如果源程序中其他位置不需要使用该变量,则tCount可以不必放在程序最前面,而是放在中断函数的上一行。
静态(Static)变量具有固定的内存定位,如果在某个函数内部定义了静态变量及初值,仅仅在第一次调用该函数时,该静态变量将被初始化,此后对该函数的调用都不会再初始化该变量,这类似于定义了一个专属于该函数的全局变量。在本书多个有关定时器的案例中,为了通过软件实现更长的延时,常常在定时器溢出中断函数内部定义static INT8U tCount=0,通过在每次溢出中断发生时,累加tCount变量来实现更长的延时。
局部(Local)变量定义在函数内部,对于循环及其他的临时计算应尽可能使用局部变量,作为优化处理的一部分,编译程序会试图将局部变量维持在寄存器中,寄存器访问是最快的内存访问类型,特别是unsigned char和unsigned int类型的变量。
外部(Extern)变量用于声明当前C程序设计中使用的变量,定义在当前项目内的其他C程序文件中,例如,某单片机程序项目由2个以上的C语言程序文件构成,当前C程序文件中定义有extern INT8U x;它表示变量x是一个外部变量,该变量定义在项目内其他的C程序文件内。
易变型(Volatile)变量表示一个单变量或数组的值是会随时变化的,即使程序没有专门对其进行任何赋值操作。例如,作为输入的I/O端口,其引脚值将随时可能被用户操作改变;在中断函数内被修改的变量相对于主程序流程来讲也是随时变化的;很多特殊功能寄存器的值也将随着指令的运行而动态改变。所有这些类型的变量要注意将它们明确定义成“volatile”类型,该类型定义可通知编译器在优化处理过程中不能无故消除它们。
在单片机C程序所设计的中断函数内,凡是修改的是全局变量或全局数组,而这些变量或数组又被主程序或其他函数引用时,要注意添加volatile关键字。
8051系列单片机中,程序存储器与数据存储器严格分开,特殊功能寄存器与片内数据存储器统一编址,这与一般微型计算机的存储结构是不同的。
Keil C51编译器完全支持8051单片机硬件结构,可完全访问8051硬件系统的所有部分,编译器通过将变量、常量定义成不同的存储类型(data、bdata、idata、pdata、xdata、code),从而将它们定位在不同的存储区中。表1-3列出了Keil C51存储类型与8051单片机存储空间的对应关系。
表1-3 Keil C51存储类型与8051单片机存储空间的对应关系
阅读表1-3时可参考图1-3所示的8051单片机存储器结构。
上述存储类型指示符data、bdata、idata将数据定位在内部数据存储器中,访问内部数据速度很快,它们只需要8位地址。
Keil C51编译器提供了两种外部存储类型:xdata和pdata,指定为xdata存储器类型的数据保存在最大空间为64KB的外部数据存储器空间中,通过P0与P2端口给出的16位地址(2 16 =64KB)可访问外部空间中的任意位置,但是64KB地址空间并非总是用于存储器寻址,单片机外围扩展设备地址也可以映射到存储器空间(Memory Space),这样C程序在访问外围设备时所使用语句与访问扩展内存的语句是相同的,这种技术称为内存映射I/O技术,本书有关8255和部分字符及图形液晶显示案例使用的就是这种技术。第二种存储类型pdata可访问外部数据内存一页中的256B,页地址则由P2提供。
在扩展外部存储器或外部设备时,源程序必须包含绝对内存访问(Absolute MemoryAccess)头文件absacc.h,该文件中有宏定义:
由其中的XBYTE定义可知,表达式 XBYTE[地址] 或 *(XBYTE +地址) 均可用来读/写外部RAM空间的字节数据,本书“62256扩展内存”案例就使用了XBYTE访问外部数据存储器,它相当于汇编语言中的MOVX @DPTR语句。
在8255接口扩展案例中,C程序内定义如下:
这里PA、PB、PC、COM分别用于访问8255的4个不同接口。
上述定义还可以写成:
在涉及数码管显示和图像与文字显示的案例中,由于数码管段码固定,待显示的图像或文字点阵数据也是固定的。将这些数据全部保存在数据RAM中会占用太多宝贵的空间,甚至导致编译失败。提示变量定义超出了数据RAM空间,因为单片机的数据RAM空间本来就是非常有限的。因此,在使用C语言开发单片机程序时,应将那些运行过程中不会发生变化的数据定义为code存储类型,以保证将这些数据分配到Flash程序内存而不是数据内存。
定义变量时如果省略存储类型,编译程序将自动选择默认存储类型,默认存储类型有小模式(Small)、紧缩模式(Compact)和巨模式(Large)限制,存储模式决定了变量的默认存储类型、参数传递区和未指明存储类型变量的存储类型。表1-4列出了这3种存储模式及相关说明。
表1-4 3种存储模式及相关说明
在固定的存储器地址上进行变量传递是Keil C51的特征之一,在Small模式下,参数传递在片内数据存储区完成,Compact和Large模式允许参数在外部存储区中传递。模式选择可在Keil C51项目选项窗口中的Target选项卡下完成,默认选择的是Small模式。