首页 理论教育 C51程序组成与数据结构的单片机应用技术

C51程序组成与数据结构的单片机应用技术

时间:2023-11-06 理论教育 版权反馈
【摘要】:采用C语言编写的51系列单片机应用程序简称C51程序。C51程序中增加了单片机特有的数据类型。C51程序的存储模式与MCS-51单片机的存储器的结构相关。⑤C51程序有专门的中断函数。1)C51程序的组成以例3.1程序为例介绍C51程序的组成结构。C51语言程序的组成如下:预处理命令1行,用于编译预处理。2)C51的数据结构使用单片机C51语言编写程序的过程中,离不开数据结构的应用,因此掌握C51语言的数据结构与类型非常重要。

C51程序组成与数据结构的单片机应用技术

目前单片机开发应用中,常使用C语言作为汇编语言。采用C语言编写的51系列单片机应用程序简称C51程序。C51程序对标准C程序的扩展主要是通过51系列单片机的硬件功能来实现的,其硬件功能有存储模式、存储器类型声明、变量类型声明、位变量和位寻址、特殊功能寄存器、C51指针、函数属性等。

另外,C51程序和标准C程序在以下方面是不同的:

①库函数不同。C51程序是按照51系列单片机的结构来定义的,标准C程序是按照计算机来定义的。

②数据类型不一样。C51程序中增加了单片机特有的数据类型。

③变量的存储模式不同。C51程序的存储模式与MCS-51单片机的存储器的结构相关。

④输入和输出的方式不一样。C51程序的输入/输出是通过单片机的串行口完成的,其指令执行前必须对串行口进行初始化

⑤C51程序有专门的中断函数。

1)C51程序的组成

以例3.1程序为例介绍C51程序的组成结构(语句前的数字代表行号)。

C51语言程序的组成如下:

(1)预处理命令

1行,用于编译预处理。

(2)语句

以分号结束作为标志。

C51语言的语句可分为:

①函数定义语句:3~10,11~20。

②变量定义语句:5。

函数调用语句:16,18。

④控制语句:6,7,8,13。

赋值和运算语句:2,15,17。

⑥空语句:“;”。

⑦函数体:4~10,12~20。

(3)函数

确定程序或函数的功能,有主函数和子函数之分。void main(void){…}是主函数;void delay02s(void){…}是子函数;{…}是函数体。

2)C51的数据结构

使用单片机C51语言编写程序的过程中,离不开数据结构的应用,因此掌握C51语言的数据结构与类型非常重要。

(1)C51的标识符和关键字

标识符就是用户给源程序中的对象的命名。C51语言的标识符必须以字母或者下划线开头,在C51语言中其大小写是不一样的。C51编译器对标识符的前32位有效。变量所用标识符应该有一定的含义,便于阅读源程序。关键字是C51语言的特殊标识符,具有固定的名称和含义;且在C51语言程序中标识符和关键字不能相同。

Keil μVision2中的关键字,除了C语言的32个关键字外,还根据51单片机的特点扩展了相关的关键字。即标准关键字和扩展关键字。其标准关键字和扩展关键字分别见表3.1和表3.2。

表3.1 标准关键字

续表

表3.2 扩展关键字

(2)C51的数据类型

在标准C语言中,其基本数据类型有int、char、long、short、double、float,而在C51编译器中int和short相同,float和double相同,在此不作说明。其基本数据类型的具体定义见表3.3。

表3.3 单片机C语言编辑器所支持的基本数据类型

①char(字符类型)。char类型的长度是一个字节,通常用于定义处理字符数据的变量或常量。char类型分为无符号字符类型unsigned char和有符号字符类型signed char,默认值为signed char类型。unsigned char类型可用字节中所有的位来表示数值,所能表达的数值范围是0~255。signed char类型可用字节中最高位字节表示数据的符号,“0”表示正数,“1”表示负数,负数用补码表示,所能表示的数值范围是-128~+127。unsigned char常用于处理ASCII字符或用于处理小于或等于255的整型数。

②int(整型)。int长度为两个字节,用于存放一个双字节数据。int类型分为有符号整型数signed int和无符号整型数unsigned int,其默认值为signed int类型。signed int表示的数值范围是-32 768~+32 767,字节中最高位表示数据的符号,“0”表示正数,“1”表示负数。unsigned int表示的数值范围是0~65 535。

③long(长整型)。long长度为4个字节,用于存放一个四字节数据。long类型分为有符号长整型signed long和无符号长整型unsigned long,默认值为signed long类型。signed int表示的数值范围是-2 147 483 648~+2 147 483 647,字节中最高位表示数据的符号,“0”表示正数,“1”表示负数。unsigned long表示的数值范围是0~4 294 967 295。

④float(浮点型)。float在十进制中具有7位有效数字,是符合IEEE-754标准的单精度浮点型数据,占用4个字节。

⑤bit(位标量)。bit位标量是C51编译器的一种扩充数据类型,利用它可定义一个位标量,但不能定义位指针,也不能定义位数组。它的值是一个二进制位,不是“0”就是“1”,类似于一些高级语言中的Boolean类型中的True和False。

⑥sbit(可寻址位)。sbit同样是单片机C语言中的一种扩充数据类型,利用它能访问芯片内部的RAM中的可寻址位。例如:

sbit P1_0=P1^0 //P1_0为P1中的P1.0引脚

⑦sfr(特殊功能寄存器)。sfr是一种扩充数据类型,占用一个内存单元,值域为0~255。利用它能访问51单片机内部的所有特殊功能寄存器。例如,用“sfr P0=0x80”访问特殊功能寄存器P0口,在语句中用P0=255(对P0端口的所有引脚置高电平)之类的语句来操作特殊功能寄存器。

⑧sfr16(16位特殊功能寄存器)。sfr16占用两个内存单元,值域为0~65 535。sfr16和sfr一样都是用于操作特殊功能寄存器,所不同的是,sfr16用于操作占两个字节的寄存器,如DPTR。

⑨*(指针)。指针本身就是一个变量,在这个变量中存放的是指向另一个数据的地址。这个指针变量要占据一定的内存单元,对不同的处理器长度也不尽相同,在C51中它的长度一般为1~3个字节。指针变量也有整型、实型、字符型等类型。

(3)C51中的常量

常量是在程序运行过程中不能改变值的量,而变量则是可以在程序运行过程中不断变化的量。变量可以使用所有C51编译器支持的数据类型,而常量的数据类型只有整型、浮点型、字符型、字符串型和位标量。

①整型常量。整型常量可以表示为十进制,如123、0、-89等。十六进制以0x开头,如0x34、-0x3B等。长整型就在数字后面加字母L,如104L、034L、0xF340等。

②浮点型常量。浮点型常量可分为十进制和指数两种表示形式。十进制表示:由数字和小数点组成,如0.888、3345.345、0.0等;若整数部分或小数部分为0,则可以省略,但必须有小数点。指数表示:[±]数字[.数字]e[±]数字。[]中的内容为可选项,其中内容根据具体情况可有可无,但其余部分必须有,如125e3、7e9、-3.0e-3。

③字符型常量。字符型常量是单引号内的字符,如‘a’‘d’等。不可以显示的控制字符,可以在该字符前面加一个反斜杠“\”组成专用转义字符。常用转义字符见表3.4。

表3.4 常用转义字符

④字符串型常量。字符串型常量由双引号内的字符组成,如“test”“OK”等。当引号内没有字符时表示为空字符串。在使用特殊字符时同样要使用转义字符,如双引号。在C语言中字符串常量是作为字符类型数组来处理的,在存储字符串时系统会在字符串尾部加上\0转义字符,以作为该字符串的结束符。字符串常量“A”和字符常量‘A’是不同的,前者是字符串,在存储时占用两个字节;后者是字符,在存储时占用一个字节。

⑤位标量。位标量是C51编译器的一种扩充数据类型,它的值是一个二进制位,不是“0”就是“1”。

常量主要用于不必改变值的场合,如固定的数据表、字库等。常量的定义方式有几种,下面加以说明。

unsigned int code a=200; //这一句用code把a定义在程序存储器中并赋值

const unsigned int c=300; //用const定义c为无符号int常量并赋值

这两句的值都保存在程序存储器中,而程序存储器在运行中是不允许被修改的,所以如果在这两句后面用了类似a=110,a++这样的赋值语句,编译时将会出错。

此外,还可以用预定义语句定义常量:

#define False 0x0;

#define True 0x1;

定义False为0,True为1,在程序中用到False编译时自动用0替换,同理True替换为1。

(4)C51中的变量

变量是指在程序运行中不断变化的量。Keil C51中变量的使用与标准C有所不同。正确地使用变量,有利于获得高效的目标代码。下面详细介绍Keil C51中变量的使用方法。

Keil C51中变量定义格式如下:

[存储类型]数据类型[存储器类型]变量名表

①存储类型。存储类型指的是变量的作用域,单片机程序中变量的存储类型可分为自动变量、全局变量、静态变量和寄存器变量。

a.自动变量(auto):在函数内部或者复合语句中使用的变量。在C51中函数或复合语句内部定义自动变量时,关键字auto可以省略。在程序执行过程中,自动变量是动态分配空间的。当函数或者复合语句执行完毕后,该变量的存储空间立刻自动取消,此时自动变量失效。

b.全局变量:以关键字extern标识的变量类型。全局变量一般定义在所有函数的外部。全局变量有时又称外部变量。在编译程序时,全局变量将被静态地分配适当的存储空间。该变量一旦分配空间,再在整个程序运行过程中便不会消失,即全局变量对整个程序文件都有效。

c.静态变量:关键字是static。从变量的作用域来看,该变量定义在函数内部就是内部静态变量;若定义在函数外部就是外部静态变量,静态变量始终占有内存空间。

d.寄存器变量(register):存放在单片机内部寄存器中,处理速度快,无须声明,编译器自动识别。(www.xing528.com)

②存储器类型。存储器类型用于指定该变量在C51硬件系统中所使用的存储区域,是标准C中没有的。存储器类型共有6种,见表3.5。

表3.5 Keil C51所能识别的存储器类型

如果省略存储器类型,系统则会按编译模式Small、Compact或Large所规定的默认存储器类型去指定变量的存储区域。存储模式决定没有明确指定存储类型的变量。存储模式有Small模式、Compact模式和Large模式3种。

a.Small模式:所有缺省变量参数均装入内部RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。

b.Compact模式:所有缺省变量均位于外部RAM区的一页(256 B),具体哪一页可由P2口指定,在STARTUP.A51文件中说明,也可用pdata指定。其优点是空间比Small宽裕;其缺点是速度比Small慢,但比Large快,是一种中间状态。

c.Large模式:所有缺省变量可放在多达64 KB的外部RAM区,其优点是空间大,可存变量多;其缺点是速度较慢。

③Keil C51变量的使用方法。

a.全局变量和静态局部变量。全局变量一般会在多个函数中被使用,并在整个程序运行期间有效;静态局部变量虽然只在一个函数中使用,但在整个程序运行期间有效。对于这些变量,应尽量选择data型,这样在目标代码中就可以用直接寻址指令访问,获得最高的访问速度,提高程序的工作效率。

b.数组(包括全局和局部)。定义数组一般用idata存储类型,如果因数组元素过多而在编译时报错,可以改用pdata和xdata存储类型。

c.供查表用的数据。这类数据的特点是需要始终保持不变,且使用时只读,故定义为code型。全局或局部code型变量在存储时无区别。

d.非静态局部变量。非静态局部变量仅在某一函数内使用,退出该函数时变量也被释放。若系统使用Small存储模式,则对于这些变量可以不加存储说明,由编译软件自行按最优原则决定,因为仅在函数内使用的非静态局部变量,有可能使用工作寄存器R0~R7,这样会更快速,更节省存储空间。例如,unsigned char i,j;,系统尽可能会用R0~R7存储i和j。若系统使用了Compact或Large存储模式,则应将这些变量定义为data存储模式,以防系统自行决定时被定义为pdata或xdata模式而降低工作效率。

④C51中新增变量。

a.特殊功能寄存器变量sfr:存储在片内特殊功能寄存器中,用来对特殊功能寄存器进行读/写操作。

它的格式如下:

sfr 8特殊功能寄存器名=特殊功能寄存器地址常数;

sfr 16特殊功能寄存器名=特殊功能寄存器地址常数;

例如:sfr P1=0x90;定义P1口,其地址为90H;sfr16 DPTR=0x82;定义DPTR口,其地址为82H。

b.位变量bit:存储在片内数据存储器的可位寻址字节(20H~2FH)的某个位上,这个变量在实时控制中具有很高的实用价值。

它的定义格式如下:

bit 位变量;

例如:

bit data a1;

c.特殊功能寄存器位变量sbit:存储在片内特殊功能寄存器的可位寻址字节(地址可以被8整除者)的某个位上,用来对特殊功能寄存器的可位寻址位进行读/写操作。sbit在定义可位寻址对象时有3种形式:

sbit位变量名=位地址常数。

例如:

sbit P1_1=Ox91

sbit位变量名=特殊功能寄存器名+位的位置。

例如:

sft P1=0x90,sbit P1_1=P1^1

先定义一个特殊功能寄存器名,然后指定位变量名所在的位置,只有当可寻址位于特殊功能寄存器中时才可以采用这种方法。

sbit位变量名=字节地址^位置。

例如:

sbit P1_1=0x90^1

d.外部数据存储器变量:若设置成pdata和xdata存储类型,则将把变量存储在片外数据存储器中。这两种存储类型的访问速度最慢,建议尽量不要使用。在使用这两种存储类型时,注意尽量只用它保存原始数据或最终结果,尽量减少对其访问的次数,需要频繁访问的中间结果不要用它保存。

e.指针变量:单片机C语言支持一般指针(Generic Pointer)和存储器指针(Memory_Specific Pointer)。

一般指针:其声明和使用均与标准C相同,不过同时还能说明指针的存储类型。

例如:

long*state //一个指向long型整数的指针,而state本身则依存储模式存放

char*xdata ptr //一个指向char数据的指针,而ptr本身放于外部RAM区

以上的long、char型数据指针指向的数据可存放于任何存储器中,一般指针本身用3个字节存放,分别为存储器类型、高位偏移、低位偏移量

存储器指针:基于存储器的指针在说明时即指定了存储类型。例如:

char data*str; //str指向data区中char型数据

int xdata*pow; //pow指向外部RAM的int型整数

这种指针存放时因为只存放偏移量,所以只需一个字节或两个字节就够了。

⑤变量的赋值。

a.整型变量和浮点型变量赋值。格式:

变量名=表达式;

例如,一个复合语句{int a,m;float n;a=100;m=5;n=a*m*0.a;}。

b.字符型变量,如{char a0,a1,a2;a0=‘b’;a1=65;}。

c.指针变量,如{int*i;char*str;*i=100;str=“good”;}。

d.数组的赋值,如{int m[2][2];char s[10];char*f[2];m[0][0]=8;strcpy(s,"moring");f[0]="thank you";}。

3)C51中绝对地址的访问

C51对片外扩展硬件I/O的定义用包含语句#include<absacc.h>建立头文件absacc.h,用#define语句定义其硬件译码地址。例如:

#include<absacc.h>

#define PORA XBYTE[0x20f4] //将PORA定义为片外I/O端口,长度为8位,地址为20F4H

头文件absacc.h中的函数有:

①CBYTE:访问code区,字符型,char。

②DBYTE:访问data区,字符型。

③PBYTE:访问pdata区域或I/O口,字符型。

④XBYTE:访问xdata区域或I/O口,字符型。

⑤CWORD:访问code区,整型,int。

⑥DWORD:访问data区,整型。

⑦PWORD:访问pdata区或I/O口,整型。

⑧XWORD:访问xdata区或I/O口,整型。

(1)绝对宏

在程序中用#include<absacc.h>即可使用其中定义的宏来访问绝对地址,包括CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD。

例如:

rval=CBYTE[0x0002];//指向程序存储器的0002h地址

rval=XWORD[0x0002];//指向外RAM的0004h地址

(2)_at_关键字

直接在数据定义后加上_at_const即可,需注意的是:

①绝对变量不能被初始化。

②bit型函数及变量不能用_at_指定。

例如:

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈