Keil的C51是支持51单片机最成功的C语言,它功能强大且代码效率极高,其应用最为广泛。但是,C51和标准C有一定的区别,主要体现在数据类型和数据存储结构上的差别,下面主要介绍C51和标准C有区别的内容。
一、C51的数据类型
C语言的基本数据类型有char、int、short、long、float、double。对于C51来说,short和int类型相同,float和double类型相同。也就是说,C51不支持双精度浮点运算。
C51的数据类型
数据类型 | 长度 | 取值范围 | 数据类型 | 长度 | 取值范围 |
unsigned char | 单字节 | 0~255 | float | 4字节 | ±1.18e-38~±3.40e38 |
char | 单字节 | -128~127 | * | 1-3字节 | 对象的地址 |
unsigned int | 双字节 | 0~65535 | bit | 1位 | 0或1 |
int | 双字节 | -32768~32767 | sfr | 单字节 | 0~255 |
unsigned long | 4字节 | 0~4294967295 | sfr16 | 双字节 | 0~65536 |
long | 4字节 | -2147483648 ~2147483647 | sbit | 1位 | 0或1 |
1、char、int、long三种类型均分无符号型(unsigned)和有符号型(signed,缺省),有符号型的数据采用补码表示,与标准C的定义相同,其数据长度和取值范围见上表。
2、float也与标准C一样,符合IEEE-754标准,数据长度和取值范围见上表。float的使用和运算,需要数学库“math.h”的支持。
3、指针型(*),它本身就是一个变量,只是这个变量存放的不是普通的数据,而是指向一个数据的地址。指针变量本身也要占据一定的内存,在C51中,指针变量的长度一般为1~3个字节。如char * dat表示dat是一个字符型的指针变量,float * dat1表示dat1是一个浮点型指针变量。指针变量直接指示硬件的物理地址,因此用它可以方便对8051的各部分物理地址直接操作。
以上数据类型在标准C中都有定义,以下4种类型是C51的扩充数据类型。
4、位类型:bit
布尔处理器是8051单片机的特色,使用它可以方便进行逻辑操作。位类型(bit)可以定义一个位变量,由C51编译器在8051内部RAM区20H~2FH的128个位地址中分配一个位地址。需要注意的是,位类型不能定义指针和数组。
5、特殊功能寄存器:sfr
8051及其兼容产品的特殊功能寄存器必须采用直接寻址的方式来访问,8051的特殊功能寄存器离散地分布在80H~FFH的地址空间里。sfr可以对8051的特殊功能寄存器进行定义,sfr型数据占用一个字节,取值0~255。
6、16位特殊功能寄存器:sfr16
8051及其兼容产品的16位特殊功能寄存器(如DPTR),就可以用sfr16来定义,sfr16型数据占用两个字节,取值0~65535。
在C51编译器提供的头文件reg51.h中,已经把所有的特殊功能寄存器进行定义,我们可以直接用include命令包括在程序中,参见附录2。注意,在使用时,所有的sfr的名称都必须大写,如开系统中断写为“EA=1”。
7、可寻址位类型:sbit
利用sbit可以对8051内部RAM的位寻址空间及特殊功能寄存器的可寻址位进行定义。
例如:sbit flag = P1^0;表示P1.0这条I/O口线定义名为flag的标志。
在使用中需注意,只有unsigned char 和bit类型是8051CPU可以直接用汇编语言支持的数据类型,它们的操作效率最高。其他的数据类型都有多条汇编指令组合操作,需占用大量的程序存储空间和数据存储器资源。C51还支持结构类型和联合类型等复杂类型数据,与标准C相同,不另介绍。
8、数据类型的转换
不同类型的数据是可以相互转换的,可以通过赋值或者强制转换。赋值转换次序为:bit – char – int – long – float,如果反向赋值,则结果丢弃高位。 强制转换是通过强制转换运算符来实现的,形式为:(类型名)(表达式),如:(int)(x + y)和(float)(5%3);
二、C51数据的存储结构
数据分常量和变量。常量可以用一个标志符号来代表。变量由变量名和变量值组成,每一个变量占据一定的存储空间,这些存储空间存放变量的值。8051的存储空间比较复杂,因此,数据的存放也同样复杂,详见下表:C51的存储器类型。
一般地,C51对变量定义时,除定义数据类型外,还可以定义存储类型。其格式为:
“数据类型 [存储类型] 变量名”,或者“[存储类型] 数据类型 变量名”。
如:unsigned char data name_var,或者data unsigned char name_var。
存储类型为可选项,如果不做存储类型的定义,系统将按照编译时的存储模式来默认。具体默认存储类型参见下表:存储模式与默认存储类型。
C51的存储器类型
存储器类型 | 说 明 |
data | 直接寻址片内RAM,00~7FH空间,速度最快 |
bdata | 可位寻址的片内RAM区20H~2FH空间,容许位和字节混合访问 |
idada | 间接访问片内00~FFH全部256个地址空间 |
pdata | 使用MOVX @Ri指令访问外部RAM分页的00~FFH空间 |
xdata | 使用MOVX @DPTR访问外部RAM的0000~FFFFH全部空间 |
code | 使用MOVC @A+DPTR访问程序存储器0000~FFFFH全部空间 |
存储模式与默认存储类型
存储模式 | 默认存储类型 |
SMALL | 参数和局部变量均为片内RAM,即data存储类型,也包括堆栈 |
COMPACT | 参数和局部变量均为片外分页RAM,pdata存储类型,堆栈置于片内RAM |
LARGE | 参数和局部变量均为片外64K的RAM,xdata存储类型,堆栈置于片内RAM |
三、C51的中断函数
C51增加了一个intrrupt函数选项,支持直接编写中断服务程序函数。其函数定义的形式为:
函数类型 函数名() [ intrrupt n ] [ using n ]
函数类型一般定义为void,intrrupt后的 n 是中断号,指示相应的中断源。C51编译器从code区的绝对地址8n+3处产生中断向量。 n 必须是常数,不允许使用表达式。
中断号与中断向量
中断号 | 中断源 | 中断向量入口 | 中断号 | 中断源 | 中断向量入口 |
0 | 外部中断0 | 0003H | 3 | 定时器1 | 001BH |
1 | 定时器0 | 000BH | 4 | 串行口 | 0023H |
2 | 外部中断1 | 0013H | 5 | 定时器2 | 002BH |
using n是可选的,n为0~3的常数,指示选择8051的4个寄存器组。如果不使用using n,中断函数所有使用的公共寄存器都入栈。如果使用using n,切换的寄存器就不再入栈。注意,带using的函数不允许返回bit类型数值。
编写C51的中断函数时,需要注意的几个问题:
(1) 中断函数没有返回值,因此它必须是一个void类型的函数;
(2) 中断函数不允许进行参数传递;
(3) 不允许直接调用中断函数;
(4) 中断函数对压栈和出栈的处理由编译器完成,无需人工管理;
(5) 需要严格注意using n的使用,必须确保寄存器组的正确切换。