【基础知识】C51单片机变量定义

【基础知识】C51单片机变量定义


  • 摘自《IAP15W4K58S4单片机的存储器与应用编程》主编:丁向荣;主审:姚永平;

在使用一个变量或常量之前,必须先定义该变量或常量,指出其数据类型和存储器类型,以便编译系统为其分配相应的存储单元。
在C51中定义变量的格式为:[存储种类]数据类型[存储器类型]变量名表

1
2
3
1. auto int data x;
2. char code y=0x22;

行号1中,变量x的存储种类、数据类型、存储器类型分别为auto、int、data。行号2中,变量y只定义了数据类型和存储器类型,未直接给出存储种类。在实际应用中,“存储种类”和“存储器类型”是可选项,默认的存储种类是auto(自动);如果省略存储器类型,则按Keil C编译器编译模式SMALL、COMPACT、LARGE所规定的默认存储器类型确定存储器的存储区域。C语言允许在定义变量的同时给变量赋初值,如行号2中对变量的赋值。

  • (1)变量的存储种类
    变量的存储种类有4种,分别为auto(自动)、extern(外部)、static(静态)和register(寄存器)。默认设置时,变量的存储种类为auto。
  • (2)变量的存储器类型
    KeilC编译器完全支持8051系列单片机的硬件结构,可以访问其硬件系统的各个部分。对于各个变量,可以准确地赋予其存储器类型,使之能够在单片机内准确定位。KeilC编译器支持的存储器类型如表4-1-3所示。
    在这里插入图片描述
  • (3)KeilC编译器的编译模式与默认存储器类型
    SMALL:变量被定义在8051单片机的内部数据存储器(data)区中,因此对这种变量的访问速度最快。另外,所有的对象,包括堆栈,都必须嵌入内部数据存储器。
    COMPACT:变量被定义在外部数据存储器(pdata)区中,外部数据段长度可达256字节。这时对变量的访问是通过寄存器间接寻址(MOVX @Ri)实现的。采用这种模式编译时,变量的高8位地址由P2口确定。因此,在采用这种模式的同时,必须适当改变启动程序STARTUP.A51中的参数:PDATASTART和PDATALEN。用L51连接时,还必须采用控制命令PDATA对P2口地址定位,以确保P2口为所需要的高8位地址。
    LARGE:变量被定义在外部数据存储器(xdata)区中,使用数据指针DPTR访问。
    这种访问数据的方法效率不高,尤其是对于2个或多个字节的变量,采用这种数据访问方法对程序的代码长度影响非常大。另外,一个不便之处是数据指针不能对称操作。

2)算术运算符

  • (1)算术运算符与表达式C语言有以下算术运算符。
    +:加法或取正值运算符。②一:减法或取负值运算符。
    *:乘法运算符。
    /:除法运算符(取高值)。
    %:取余运算符。
  • (2)自增和自减运算符与表达式
    ++:自增运算符。
    --:自减运算符。

自增和自减运算符是C语言中特有的,其作用分别是对运算对象做加1和减1运算。
自增和自减运算符只能用于变量,不能用于常数和表达式。自增和自减运算符可以位于变量前面,也可位于变量的后面,但其功能不完全相同。
a++:先使用a的值,再执行a+1操作。
++a:先执行a+1操作,再使用a的值。

  • (3)复合赋值运算符
    在赋值运算符“=”的前面加上其他运算符,就构成了复合赋值运算符。复合赋值运算符首先对变量进行某种运算,然后将运算结果赋值给该变量。复合运算的一般形式为:
1
2
变量 复合赋值运算符 表达式;

C语言中有以下几种复合赋值运算符。
+=:加法赋值运算符。例如,x +=3;等效于x =x+3;。
-=:减法赋值运算符。例如,x -=3;等效于x =x-3;。
*=:乘法赋值运算符。例如,x =3;等效于x =x3;。
/=:除法赋值运算符。例如,x/=3;等效于x =x/3;。
%=:取模(余)赋值运算符。例如,x %=3;等效于x =x%3;。
>>=:右移位赋值运算符。例如,x >>=3;等效于x =x>>3;。
<<=:左移位赋值运算符。例如,x <<=3;等效于x =x<<3;。
&=:逻辑与赋值运算符。例如,a &=b;等效于a =a&b;。
|=:逻辑或赋值运算符。例如,a l=b;等效于a =a l b;。
^ =:逻辑异或赋值运算。例如,a ^=b;等效于a =a ^ b;。
11 ~=:逻辑非赋值运算符。例如,a ~=b;等效于a =~b;。

  • 3)指定工作寄存器区
    当需要指定函数中使用的工作寄存器区时,使用关键字using后跟一个0 ~ 3的数,对应工作寄存器组0~3区。例如:
1
2
3
4
5
unsigned char GetKey(void)using 2
{
/∥用户代码区
}

using后面的数字是2,说明使用工作寄存器组 2,RO~R7对应地址为10H ~17H。

  • 4)函数的定义与调用
    函数是C语言程序的基本模块,所有的函数在定义时是相互独立的,它们之间是平衡关系,所以不能在一个函数中定义另外一个函数,即不能嵌套定义。函数之间可以相互调用,但不能调用主函数。
    C语言系统提供功能强大、资源丰富的标准函数库,用户在进行程序设计时,应善于利用这些资源,以提高效率,节省开发时间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <REG51.h>
#define x P1
void delay(void);//语句3,声明延时子函数
/x----LED灯驱动函数--—-\*/
void light(void)
x =~x;
}

void main(void){
while(1){
light();//1ight()在主函数前面定义,因此可直接调用
delay();//delay()在主函数后面定义,故调用前必须先声明,见语句3
}
void delay(void){
unsigned int i,j;
for(i=0;i<500;i++){
for(j=0;j<121;j++)
{;}
}
}

  • ·函数的连接:当程序中的子函数与主函数不在同一个程序文件时,要通过连接的方法实现有效的调用。一般有两种方法,即外部声明文件包含

对于外部声明,定义的delay()ligh()两个子函数与调用主函数不在一个程序文件中,则当主函数要调用delay()ligh()时,可在调用前做外部声明。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <REG51.H>
extern void delay(void);//声明该函数在其他文件中
extern void light(void);∥声明该函数在其他文件中

void main(void)
{
while(1)
{
1ight();
delay();
}
}

对于文件包含,当主函数需要调用分属在其他程序文件中的子函数时,也可用包含语句将含有该子函数的程序文件包含进来。包含可以理解为:将包含文件的内容放在包含语句位置处。
delay()light()两个子函数在test.c程序文件中定义,主函数要调用delay()light()时,可用包含语句将test.c程序文件包含进来,类似包含头文件的意义。例如:

1
2
3
4
5
6
7
8
9
10
11
#include<reg51.h>
#include"test.c"
void main(void)
{
while(1)
{
light();
delay();
}
}

  • 5)局部变量与全局变量
  • (1)局部变量

局部变量是指在函数内部定义的变量,只在该函数内部有效。

  • (2)全局变量

全局变量是指在程序开始处或各个功能函数的外面定义的变量。在程序开始处定义的变量在整个程序中有效,可供程序中所有的函数共同使用;在各功能函数外面定义的全局变量只对定义处开始往后的各个函数有效,只有从定义处往后的各个功能函数可以使用该变量。

书籍资源

1
2
3
「单片机原理与应用项目教程...列单片机 丁向荣.pdf」
链接:https://www.aliyundrive.com/s/kWjiDD2ZwvR