




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第三章 单片机的C51语言 3.1.1 C51语言概述【P60】 C51是在标准C的基础上,根据单片机存储器硬件结构及内部资源,扩展了相应的数据类型和变量,而C51在语法规定、程序结构与设计方法上,都与标准C基本相同。Keil C语言的编译器及编译过程如图3-1所示。图3-1 Keil C语言的编译器及编译过程C语言是美国国家标准协会(ANSI)制定的编程语言标准,1987年ANSI公布87 ANSI C,即标准C语言。Keil C51语言是在ANSI C的基础上针对51单片机的硬件特点进行的扩展,并向51单片机上移植,经过多年努力,C51语言已经成为公认的高效、简洁而又贴近51单片机硬件的实
2、用高级编程语言。目前大多数的51单片机用户都在使用C51语言来进行程序设计。用C51进行单片机软件开发,有如下优点:(1)可读性好。C51语言程序比汇编语言程序的可读性好,因而编程效率高,程序便于修改。【P53的汇编程序】(2)模块化开发与资源共享。用C51开发出来的程序模块可以不经修改,直接被其他项目所用,这使得开发者能够很好地利用已有的大量的标准C程序资源与丰富的库函数,减少重复劳动。(3)可移植性好。为某种型号单片机开发的C语言程序,只需将与硬件相关之处和编译连接的参数进行适当修改,就可以方便地移植到其他型号的单片机上。例如,为51单片机编写的程序通过改写头文件以及少量的程序行,就可以方
3、便地移植到PIC单片机上。(4)代码效率高。当前较好的C51语言编译系统编译出来的代码效率只比直接使用汇编语言低1020%左右,如果使用优化编译选项,效果会更好。3.1.2 C51的程序结构C51程序的基本单位是函数。一个C51源程序至少包含一个主函数,也可以是一个主函数和若干其他函数。主函数是程序的入口。下面通过一个可实现LED闪烁控制功能的源程序说明C51程序的基本结构。程序如下:【P60】#include <reg51.h> / 51单片机头文件void delay(); /延时函数声明sbit p1_0=P10; /输出端口定义main() /主函数While(1) /无限
4、循环p1_0=0; /p1.0=“0”,LED亮delay(); /延时p1_0=1; /p1.0=“1”,LED灭delay(); /延时void delay(void) /延时函数unsigned char i; /字符型变量i定义for (i=200;i>0;i-); /循环延时 【在仿真时,可以不用连接电源,晶体振荡器,复位电路】3.1.3 Keil C51的开发环境Keil C51是德国Keil Software公司开发的用于51系列单片机的C51语言开发软件。Keil C51在兼容ANSI C的基础上,又增加很多与51单片机硬件相关的编译特性,使得开发51系列单片机程序更为方
5、便和快捷,程序代码运行速度快,所需存储器空间小,完全可以和汇编语言相媲美。它支持众多的MCS-51架构的芯片,同时集编辑、编译、仿真等功能于一体,具有强大的软件调试功能,是众多的单片机应用开发软件中最优秀的软件之一。Keil C51已被完全集成到一个功能强大的全新集成开发环境(IDE)µVision3中【版本在不断更新】,该环境集成了文件编辑处理、编译链接、项目(Project)管理、窗口、工具引用和仿真软件模拟器以及Monitor51硬件目标调试器等多种功能,这些功能可在Keil µVision3环境中进行操作。µVision3内部集成了源程序编辑器,并允许用户
6、在编辑源文件时就可设置程序调试断点,便于在程序调试过程中快速检查和修改程序。此外,µVision3还支持软件模拟仿真(Simulator)和用户目标板调试(Monitor51)两种工作方式。在软件模拟仿真方式下不需任何51单片机及其外围硬件即可完成用户程序仿真调试。在用户目标板调试方式下,利用硬件目标板中的监控程序可以直接调试目标硬件系统,使用户节省购买硬件仿真器的费用。3.1.4 C51与标准C的主要区别不同的嵌入式处理器的C编译系统与标准C的不同之处,主要是它们所针对的嵌入式处理器的硬件系统不同。Keil C51的基本语法与标准C相同,但对标准C进行了扩展。理解Keil C51对
7、标准C的扩展部分是掌握Keil C51的关键。C51与标准C的主要区别如下:(1)头文件的差异。51系列单片机厂家有多个,它们的差异在于内部资源如定时器、中断、I/O等数量以及功能的不同,而对使用者来说,只需要将相应的功能寄存器的头文件加载在程序内,就可实现所具有的功能。因此,Keil C51系列的头文件集中体现了各系列芯片的不同资源及功能。(2)数据类型的不同。51系列单片机包含位操作空间和位操作指令,因此Keil C51与ANSI C相比又扩展了4种类型,以便能够灵活地进行操作。(3)数据存储类型的不同。C语言最初是为通用计算机设计的,在通用计算机中只有一个程序和数据统一寻址的内存空间,而
8、51系列单片机有片内、外程序存储器,还有片内、外数据存储器。标准C并没有提供这部分存储器的地址范围的定义。此外,对于80C51单片机中大量的特殊功能寄存器也没有定义。(4)标准C语言没有处理单片机中断的定义。(5)Keil C51与标准C的库函数有较大的不同。由于标准C的中的部分库函数不适于嵌入式处理器系统,因此被排除在Keil C51之外,如字符屏幕和图形函数。有一些库函数可以继续使用,但这些库函数都必须针对51单片机的硬件特点来作出相应的开发,与标准C库函数的构成与用法有很大的不同。例如库函数printf和scanf,在标准C中,这两个函数通常用于屏幕打印和接收字符,而在Keil C51中
9、,它们主要用于串行口数据的收发。(6)程序结构的差异。由于51单片机的硬件资源有限,它的编译系统不允许太多的程序嵌套。其次,标准C所具备的递归特性不被Keil C51支持,在C51中,要使用递归特性,必须用reentrant进行声明才能使用。但是从数据运算操作、程序控制语句以及函数的使用上来说,Keil C51与标准C几乎没有什么明显的差别。如果程序设计者具备了有关标准C的编程基础,只要注意Keil C51与标准C的不同之处,并熟悉AT89S51单片机的硬件结构,就能够较快地掌握Keil C51的编程。3.2 C51语言程序设计基础3.2.1 C51语言中的数据1. 数据类型【P63】Keil
10、 C51的基本数据类型如表3-1所示。针对80C51单片机的硬件特点,C51在标准C的基础上,扩展了4种数据类型(见表中最后4行)。注意:扩展的4种数据类型,不能使用指针对它们存取。表3-1 Keil C51支持的数据类型数据类型位数字节数值 域unsigned char810255signed char81-128+127unsigned int162065535signed int162-32768+32767unsigned long32404294967295signed long324-2147483648+2147483647float32410-3810E+38double648
11、10-30810E+308bit10或1sbit10或1sfr810255sfr16162065536其中,有符号数据类型,可以忽略signed标识符,如signed int 等价于int,signed char 等价于char等。在C51语言程序中,有可能会出现在运算中数据类型不一致的情况。C51允许任何标准数据类型的隐式转换。隐式转换的优先级顺序如下:Bitcharintlongfloatsignedunsigned也就是说,当char型与int型进行运算时,先自动对char型扩展为int型,然后与int型进行运算,运算结果为int型。C51除了支持隐式类型转换外,还可以通过强制类型转换符
12、“()”对数据类型进行人为的强制转换。2. C51的扩展数据类型【P64】 80C51系列单片机用特殊功能寄存器SFR来控制定时器、计数器、串口、并口和外围设备。它们分别用位、字节和字进行访问。与此对应,编译器提供bit、sbit、sfr和sfr16数据类型访问SFR。下面对表3-1中扩展的4种数据类型进行说明。(1) 位变量bit类型 利用它可以定义一个位变量或位函数,但不能定义位指针,也不能定义位数组。它的值可以是1(true), 也可以是0(false)。在C51中,允许用户通过位类型符定义位变量。位类型符有两个:bit和sbit。可以定义两种位变量。bit位类型符用于定义一般的可位处理
13、位变量。它的格式如下: bit 位变量名;例如:bit flag1;bit flag2;所有的bit变量存放在80C51内部数据存储区的(20H2FH)位段。因为这个区域只有16个字节长,所以在某个范围内最多只能定义128个位变量。(2)特殊功能寄存器sfr类型特殊功能寄存器可以用sfr 来定义,通过名字或地址来引用特殊功能寄存器。51系列特殊功能寄存器在片内RAM区的80HFFH之间,“sfr” 数据类型占用一个内存单元。利用它可访问80C51内部的所有特殊功能寄存器。 格式如下: sfr sfr_name=地址常数;sfr_name是特殊功能寄存器名,“地址常数”必须是一个常数,不允许用带
14、操作数的表达式。其数值范围必须在特殊功能寄存器的地址范围,即位于0x800xffH之间。例如:sfr P0=0x80这一语句定义P0口在片内的寄存器,在后面语句中可用“P0=0xff”(使P0的所有引脚输出为高电平)之类的语句来操作特殊功能寄存器。 同样: sfr P1=0x90; sfr P2=0xa0;sfr P3=0xb0;P1、P2和P3是声明的SFR名。【实际上,这些定义在REG51.H文件中已经定义过】(3)特殊功能寄存器sfr16类型“sfr16”数据类型占用两个内存单元,用来定义16 位的特殊功能寄存器。sfr16和sfr一样用于操作特殊功能寄存器。所不同的是它用于操作占两个字
15、节的特殊功能寄存器。特殊功能寄存器名一般用大写字母表示。地址一般用直接地址形式(常数)。不允许用带操作数的表达式。而且必须是低位和高位字节中的低位字节的地址。例如DPTR。通过名字或地址来引用特殊功能寄存器。编译器提供sfr16数据类型,将两个8位的SFR作为一个16位的SFR来访问。例如: sfr16 DPTR=0x82语句定义了片内16位数据指针寄存器DPTR,其低8位字节地址为82H,高8位字节地址为83H。在后面的语句中可以对DPTR进行操作。(4)特殊功能位 sbit在51系列单片机中,经常要访问特殊功能寄存器中的某些位,可位寻址的特殊功能寄存器的位变量定义用关键字sbit。格式如下
16、:sbit 位变量名=位地址;位地址可有2种形式:位直接地址,其取值范围为0x800xff特殊功能寄存器名带位号,特殊功能寄存器与位号之间一般用“”作间隔。【常用】例如:sbit EA=0xAF; 【IE寄存器的D7,即IE.7】【参见P27的表2.3】sbit EA=IE7; 【IE寄存器的D7,即IE.7】符号“”前面是特殊功能寄存器的名字,“”的后面数字定义特殊功能寄存器可寻址位在寄存器中的位置,取值必须是07。注意,不要把bit与sbit混淆。bit用来定义普通的位变量,值只能是二进制的0或1(位变量存放在RAM:20H2FH之间)。而sbit定义的是特殊功能寄存器的可寻址位,其值是可
17、进行位寻址的特殊功能寄存器的位绝对地址(地址在80HFFH之间)。【例4-5】sbit型变量的定义。sbit P=0xd0;【 sbit P=PSW0; 】【见P27】sbit CY=0xd7;【 sbit P=PSW7; 】sfr P1=0x90;sbit P1_0=P10;sbit P1_1=P11;sbit P1_2=P12;sbit P1_3=P13;sbit P1_4=P14;sbit P1_5=P15;sbit P1_6=P16;sbit P1_7=P17;在C51中,为了用户处理方便,C51编译器把MCS-51单片机的常用的特殊功能寄存器和特殊位进行了定义,放在一个“reg51.
18、h”或“reg52.h”的头文件中,当用户要使用时,只需要在使用之前用一条预处理命令#include <reg51.h>或#include <reg52.h>把这个头文件包含到程序中,然后就可在程序中使用殊功能寄存器名和某些特殊位名称。典型reg51.h头文件的部分内容如下:C51编译器在头文件“reg51.h”中定义了全部sfr/sfr16和sbit变量。用一条预处理命令#include <reg51.h>把这个头文件包含到C51程序中,无需重定义即可直接使用它们的名称。REG51.H文件中定义的内容Header file for generic 80C5
19、1 and 80C31 microcontroller.-*/#ifndef _REG51_H_#define _REG51_H_/* BYTE Register */ 字节寄存器【21个】sfr P0 = 0x80;sfr P1 = 0x90;sfr P2 = 0xA0;sfr P3 = 0xB0;sfr PSW = 0xD0;sfr ACC = 0xE0;sfr B = 0xF0;sfr SP = 0x81;sfr DPL = 0x82;sfr DPH = 0x83;sfr PCON = 0x87;sfr TCON = 0x88;sfr TMOD = 0x89;sfr TL0 = 0x8A
20、;sfr TL1 = 0x8B;sfr TH0 = 0x8C;sfr TH1 = 0x8D;sfr IE = 0xA8;sfr IP = 0xB8;sfr SCON = 0x98;sfr SBUF = 0x99;/* BIT Register */ 可位寻址的位变量/* PSW */【程序状态字】sbit CY = 0xD7;sbit AC = 0xD6;sbit F0 = 0xD5;sbit RS1 = 0xD4;sbit RS0 = 0xD3;sbit OV = 0xD2;sbit P = 0xD0;/* TCON */sbit TF1 = 0x8F;sbit TR1 = 0x8E;sbi
21、t TF0 = 0x8D;sbit TR0 = 0x8C;sbit IE1 = 0x8B;sbit IT1 = 0x8A;sbit IE0 = 0x89;sbit IT0 = 0x88;/* IE */sbit EA = 0xAF;sbit ES = 0xAC;sbit ET1 = 0xAB;sbit EX1 = 0xAA;sbit ET0 = 0xA9;sbit EX0 = 0xA8;/* IP */ sbit PS = 0xBC;sbit PT1 = 0xBB;sbit PX1 = 0xBA;sbit PT0 = 0xB9;sbit PX0 = 0xB8;/* P3 */sbit RD =
22、 0xB7;sbit WR = 0xB6;sbit T1 = 0xB5;sbit T0 = 0xB4;sbit INT1 = 0xB3;sbit INT0 = 0xB2;sbit TXD = 0xB1;sbit RXD = 0xB0;/* SCON */sbit SM0 = 0x9F;sbit SM1 = 0x9E;sbit SM2 = 0x9D;sbit REN = 0x9C;sbit TB8 = 0x9B;sbit RB8 = 0x9A;sbit TI = 0x99;sbit RI = 0x98;#endif3. 数据的存储类型【P65】 针对80C51存储空间的特点,可以利用存储空间的修
23、饰符,来指明所定义的变量应分配在什么样的存储空间。C51存储类型与80C51的实际存储空间的对应关系见表3-2。下面对表3-2作以说明。(1)片内数据存储器 片内数据存储区是可读/写的。80C51系列最多可有256字节的内部数据存储区。内部数据区,可以分成3个不同的存储类型data、idata和bdata。data:片内直接寻址区,位于片内RAM的低128字节。为片内直接寻址的RAM空间,寻址范围为0127(00H7FH,主要在30H7FH之间)。在此空间内,存取速度最快。idata:片内间接寻址区,片内RAM所有地址单元(00HFFH)。为片内间接寻址的RAM空间,寻址范围0255。由于只能
24、间接寻址,访问速度比直接寻址慢。【只有52系列才有】bdata:片内位寻址区,位于片内RAM位寻址区20H2FH,位地址范围位0127。在此空间允许按字节和按位寻址混合访问。【如果不用位变量,仍然可以作为字节地址访问】bit定义的变量,严格来说只能是bdata。例如:unsigned char bdata flag; 表3-2 存储器类型说 明data直接访问的内部数据存储器,访问速度最快(位于片内RAM的低128字节,字节地址:00H7FH)bdata可位寻址的内部数据存储器,可用字节方式,也可用位方式访问,位于20H2FH(16个字节)idata间接访问的内部数据存储器,可以访问所有的内部
25、存储空间(256字节)【只有52系列才有】pdata片外RAM的一个分页寻址区,每页256字节xdata外部数据存储器RAM(64KB),常用于存放不常用的变量或等待处理的数据,字节地址:0000HFFFFHcode外部程序存储器空间(64KB),常用于存放数据表格、常数等固定信息(2)片外数据存储器 外部数据存储区是可读/写的。可通过一个数据指针加载一个地址来间接访问外部数据区。因此,访问外部数据区比访问内部数据存储区慢。 外部数据存储区最多可有64KB。由于硬件设计时,要把外围设备映射到该存储区,所以这些地址不一定都能用来作为数据存储区。 编译器提供两种不同的存储类型来访问外部数据xdat
26、a和pdata。 xdata该标识是指外部数据存储区(64KB)内的任何地址,寻址范围为065535【字节地址:0000HFFFFH】。pdata该标识符仅指一页或256字节的外部数据存储区,寻址范围为0255。 在定义变量时,通过指明存储器类型,可以将所定义的变量存储在指定的存储区域中。 访问内部数据存储器比访问外部数据存储器快得多。因此,应该把频繁使用的变量放置在内部数据存储器中,把很少使用的变量放在外部数据存储器中。 在变量声明中,可以包括存储器类型和singed或unsinged属性。例如: unsigned char data var1; unsigned char code tex
27、t=”Enter Parameter”; unsigned long xdata array100; unsigned char xdata vector1044; unsigned char bdata flag; 【如果位变量区有未用的单元,可以进行字节访问】unsigned char code data=0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,;/把常数放到程序存储器中如果在变量的定义中,没有包括存储器类型,那么将自动选用默认的存储器类型。(
28、3)片外程序存储器code:外部程序存储器的64KB空间。程序存储区用来存放程序代码、数据及表格(数据及表格中的数据是不变的)。程序的代码(CODE)存储区是只读的,不能写入。硬件决定最多可能有64KB的程序存储区。【因为是16位】用code标识符来访问片内、片外统一编址的程序存储区,寻址范围为065535。【P66】如果在定义变量时,省略了存储类型说明,C51编译器会根据当前编译模式自动认定默认的存储类型。编译模式分为:小编译模式(SMALL)、紧凑编译模式(COMPACT)和大编译模式(LARGE)3种,具体的内容见下表:【在keil中要进行选择,目前只用SMALL就可以了】3种编译模式的
29、特点小结编译模式变量存储区域默认存储类型特点SMALL片内低128RAMdata访问数据的速度最快,但由于存储容量较小,难于满足需要定义较多变量的场合COMPACT片外页256BRAMpdata介于两者之间,且受片外RAM的容量限制LARGE片外64KBRAMxdata访问数据的效率不高,但由于存储容量大,可满足需要定义较多变量的场合所以,在SMALL编译模式下,语句char a 等价于char data a;而在LARGE编译模式下,语句char a等价于char xdata a。一般采用SMALL模式,所以,在变量声明中,如果没有修饰符,则数据默认的存储空间为data型,也就是在片内RAM
30、中。对单片机编程,正确地定义数据类型以及存储类型,是所有编程者在编程前都需要首先考虑的问题。在资源有限的条件下,如何节省存储单元并保证运行效率,是对开发者的一个考验。只有对C51中的各种数据类型以及存储类型非常熟练的掌握,才能运用自如。定义变量类型应考虑如下问题:程序运行时该变量可能的取值范围,是否有负值,绝对值有多大,以及相应需要的存储空间大小。在够用的情况下,尽量选择8位即一个字节的char型,特别是unsiged char。对于51系列这样的定点机而言,浮点类型变量将明显增加运算时间和程序长度,如果可以的话,尽量使用灵活巧妙的算法来避免浮点变量的引入。定义数据的存储类型通常遵循如下原则:
31、只要条件满足,尽量选择内部直接寻址的存储类型data,然后选择idata即内部间接寻址。对于那些经常使用的变量要使用内部寻址。在内部数据存储器数量有限或不能满足要求的情况下才使用外部数据存储器。选择外部数据存储器可先选择pdata类型,最后选用xdata类型。需指出,扩展片外存储器,原理上虽很简单,但在实际开发中,很多时候,会带来不必要的麻烦,如可能降低系统稳定性、增加成本、拉长开发和调试周期等,推荐充分利用片内存储空间。另外,通常的单片机应用都是面对小型的控制,代码比较短,对于程序存储区的大小要求很低,常常是片内RAM很紧张而片内Flash ROM很富裕,因此如果实时性要求不高,可考虑将一些
32、子函数的常量数据做成数据表,放置在程序存储区,当程序运行时,进入子函数动态调用下载至RAM即可,退出子函数后立即释放该内存空间。3.2.3 一个简单的C51程序一个C51源程序是由一个个模块化的函数所构成,函数是指程序中的一个模块,main()函数为程序的主函数,其他若干个函数可以理解为一些子程序。一个C51源程序无论包含了多少函数,它总是从main()函数开始执行,不论main()函数位于程序的什么位置。程序设计者就是编写一系列的函数模块,并在需要的时候调用这个函数,实现程序所要求的功能。1. C51程序与函数下面通过一个简单C51程序,认识C51程序与函数。【例3-1】 在80C51的P1
33、.0脚接有一只发光二极管,二极管的阴极接P1.0脚,阳极通过限流电阻接+5V,现在让发光二极管每隔800ms闪灭,占空比为50%。已知单片机时钟晶振为12MHz,即每个机器周期1s,采用软件延时的方法,参考程序如下:#include <reg51.h> / 包含reg51.h 头文件sbit P10=P10; / 定义位变量P1.0 ,也可使用sbit P10=0x90void delay(unsigned int count) / 延时函数Delay( ),count是形式参数 / 两个花括号之间为函数Delay( )的函数体unsigned int i,j; / 定义变量i,j
34、for(i=0; i<count;i+) / 如果i<count,则i加1 /在时钟频率为12MHz时,循环120次,大约为1ms for(j=0;j<120;j+) / 如果j<120,则j加1 / unsigned char j;可以节约一个单元空间void main(void) / 主函数main( )while(1) / 主程序轮询 P10=1; / P1.0输出高电平,发光二极管灭 delay(800) ; / 将实际参数800传递给形式参数i,延时800ms P10=0; / P1.0输出低电平,发光二极管亮 delay(800) / 将实际参数800传递给
35、形式参数i,延时800ms 【问题】void delay(unsigned int count)能否改为void delay(unsigned char count)否?下面对程序进行简要说明。程序的第1行是“文件包含”,是将另一个文件“reg51.h”的内容全部包含进来。文件“reg51.h”包含了51单片机全部的特殊功能寄存器的字节地址及大多数可寻址位的位地址定义。程序包含reg51.h的目的就是为了使用P1这个符号,即通知程序中所写的P1是指80C51的P1端口,而不是其他变量。打开reg51.h文件可以看到“sfr P1=0x90;”,即定义符号P1与地址0x90对应,而P1口的地址就
36、是0x90。虽然这里的“文件包含”只有一行,但C编译器在处理的时候却要处理几十行或几百行。 程序的第2行用符号P10来表示P1.0引脚。在C51中,如果直接写“P1.0”编译器并不能识别,而且P1.0也不是一个合法的C51语言程序变量名【因为在reg51.h中,没有定义,需要用户自己定义】,所以必须给它起一个另外的名字,这里起的名字是P10,可是P10是否就是P1.0呢,所以必须给它们建立联系,这里使用了C51的关键字“sbit”来进行定义。第3行第8行对函数delay进行了事先定义,只有这样,才能在主程序中被主函数main ( )调用。自行编写的函数delay( )的用途是软件延时,调用时使
37、用的这个“800”被称为“实际参数”,以延时800ms的时间。注意,若delay( )的定义写在main函数的后面,则需要先作出声明,否则编译无法通过,因为编译到main函数中的delay( )语句时,找不到相应的函数体。main为“主函数”,每一个C语言程序有且只有一个主函数,主函数后面一定有一对花括号“”,在花括号里面书写该函数的代码行。2. 用户自定义函数与库函数用户自定义函数用户根据自己需要所编写的函数。如例3-1中的delay函数。编写时,需要注意以下几点。函数的首部(函数的第1行),包括函数名、函数类型、函数属性、函数参数(形式参数)名、参数类型。例如:void Delay(uns
38、igned int i)函数体,即函数首部下面的花括号“ ”内的部分。如果一个函数体内有多个花括号,则最外层的一对“ ”为函数体的范围。C51区分大小写,例如Delay与delay,编译时是不同的两个名称。每个语句最后必须有一个分号,分号是C语句的必要组成部分。从函数的定义的形式上划分可以有三种形式:无参数函数、有参数函数和空函数。(1)无参数函数 此种函数在被调用时,既无参数输入,也不返回结果给调用函数,只是为完成某种操作而编写的。(2)有参数函数 调用此种函数时,必须提供实际的输入函数,必须说明与实际参数一一对应的形式参数,并在函数结束时返回结果,供调用它的函数使用。(3)空函数函数体内无
39、语句,是空白的。调用空函数时,什么工作也不做,不起任何作用。定义空函数的目的,是为以后程序功能的扩充。程序最初设计时,往往只涉及最基本的功能模块的函数,其他模块的功能函数可以在以后补上。因此先将非基本模块的功能函数定义成空函数,用一个空语句“;”占好位置,并写好注释,以后再用一个编好的函数代替它。3. 函数调用程序设计者的任务就是编写一系列的用户自定义函数模块,并在需要的时候调用这些函数以及库函数,实现程序所要求的功能。调用格式为:函数名(实际参数1,实际参数2,)例如,例3-1中主函数main ( )里的子函数调用语句“delay(800);”,其中800为实际参数。3.2.4 C51的运算
40、符在程序中实现运算,要熟悉常用的运算符。本节对C51中用到的标准C运算符进行回顾,为C51的程序设计打下基础。1. 算术运算符如表3-3所示。表3-3 算术运算符及其说明符 号说 明加法运算减法运算*乘法运算/除法运算【商】%取模运算【余数】自增1自减1对于“/”和“%”这两个符号都涉及除法运算,但“/”运算是取商,而“%” 运算为取余数。例如“5/3”的结果(商)为1,而“5%3”的结果为2(余数)。表3-3中的自增和自减运算符是使变量自动加1或减1,自增和自减运算符放在变量前和变量之后是不同的。+i,-i:在使用i之前,先使i值加(减)1。i+,i-:在使用i之后,再使i值加(减)1。例如
41、:若i=4,则执行x=+i时,先使i加1,再引用结果,即x=5,运算结果为i=5,x=5。再如:若i=4,则执行x=i+时,先引用i值,即x=4,再使i加1,运算结果为i=5,x=4。2. 逻辑运算符逻辑运算符及其说明如表3-4所示。表3-4 逻辑运算符及其说明符号说 明&&逻辑与|逻辑或!逻辑非3. 关系运算符判断两个数之间的关系。关系运算符及其说明如表3-5。表3-5 关系运算符及其说明符号说 明>大于<小于>=大于或等于<=小于或等于=等于!=不等于4. 位运算C51中的位运算符及其说明如表3-6所示。表3-6 位运算其说明符号说 明&按位
42、与按位或按位异或按位取反<<左移>>右移【例】设a=0x54=01010100B,b=0x3b=00111011B,则a&b、a|b、ab、a、a<<2、b>>2分别为多少?a=0x54=01010100Bb=0x3b=00111011B a&b=00010000b=0x10 a|b=01111111B=0x7f ab=01101111B=0x6f a=10101011B=0xab a<<2=01010000B=0x50 【a<<=2】 b>>2=00001110B=0x0e 【b>>
43、;=2】5 复合赋值运算符C51语言中支持在赋值运算符“=”的前面加上其它运算符,组成复合赋值运算符。下面是C51中支持的复合赋值运算符:+= 加法赋值 -+ 减法赋值*= 乘法赋值 /= 除法赋值%= 取模赋值 &= 逻辑与赋值 |= 逻辑或赋值 = 逻辑异或赋值= 逻辑非赋值 >>= 右移位赋值 <<= 左移位赋值复合赋值运算的一般格式如下: 变量 复合运算赋值符 表达式 它的处理过程:先把变量与后面的表达式进行某种运算,然后将运算的结果赋给前面的变量。其实这是C51语言中简化程序的一种方法,大多数二目运算都可以用复合赋值运算符简化表示。例如:a+=6相当于
44、a=a+6;a*=5相当于a=a*5;b&=0x55相当于b=b&0x55;x>>=2相当于x=x>>2。3.2.5 C51的分支与循环程序结构程序结构上可把程序分为三类,即顺序、分支和循环结构。顺序结构是程序的基本结构,程序自上而下,从main()的函数开始一直到程序运行结束,程序只有一条路可走,没有其他的路径可以选择。顺序结构比较简单和便于理解,这里介绍分支结构和循环结构。1. 分支结构程序(1) 只有两条分支的时候用If (条件) 分支1else 分支2(2) 分支较多时在分支较多时的情况下使用switch语句。switch ( ) case( )
45、:语句; break; case( ):语句;break;default:语句;break;注意:每个switch分支必须有一个break语句,否则程序并不能跳出switch,就会继续执行case后面的case语句。2. 循环结构程序循环语句有以下三种。(1)for循环格式为:for(循环体初始化;循环体执行条件;循环体执行后操作) 循环体 花括号中为循环体内容。(2)while循环格式为:while(循环体执行条件) 花括号中为循环体内容。 (3)do while循环格式为:do 花括号 中为循环体内容while(循环体执行条件)前两种循环是先判断循环条件是否满足,才决定循环体是否执行;而“
46、do while循环”是在执行完循环体后再判断条件是否满足,再决定循环体是否继续执行。三种循环中,经常使用的是for语句和while语句。下面来说明for语句的应用。关于循环,需说明的是,在无操作系统的控制器和处理器上运行的程序,主体通常采用轮询方式,即把所有的操作包含在一个while(1)中,如例3-1。这样的无限循环在面向通用计算机的软件设计中是不被允许的,然而嵌入式系统软件设计中,则由于其硬件构成和使用需求,常常采用这种无限循环。3.2.6 绝对地址访问使用C51运行库中预定义宏C51编译器提供了一组宏定义来对51系列单片机的code、data、pdata和xdata空间进行绝对寻址。规
47、定只能以无符号数方式访问,定义了8个宏定义,其函数原型如下:#define CBYTE (unsigned char volatile code *) 0)#define DBYTE (unsigned char volatile data *) 0)#define PBYTE (unsigned char volatile pdata *) 0)#define XBYTE (unsigned char volatile xdata *) 0)#define CWORD (unsigned int volatile code *) 0)#define DWORD (unsigned int v
48、olatile data *) 0)#define PWORD (unsigned int volatile pdata *) 0)#define XWORD (unsigned int volatile xdata *) 0)这些函数原型放在absacc.h文件中。使用时须用预处理命令把该头文件包含到文件中,形式为:#include <absacc.h>。其中:CBYTE以字节形式对code区寻址,DBYTE以字节形式对data区寻址,PBYTE以字节形式对pdata区寻址,XBYTE以字节形式对xdata区寻址,CWORD以字形式对code区寻址,DWORD以字形式对data区
49、寻址,PWORD以字形式对pdata区寻址,XWORD以字形式对xdata区寻址。访问形式如下: 宏名地址 宏名为CBYTE、DBYTE、PBYTE、XBYTE、CWORD、DWORD、PWORD或XWORD。地址为存储单元的绝对地址,一般用十六进制形式表示。【例4-7】绝对地址对存储单元的访问。#include <absacc.h> /将绝对地址头文件包含在文件中#include <reg51.h> /将寄存器头文件包含在文件中#define uchar unsigned char /定义符号uchar为数据类型符unsigned char#define uint u
50、nsigned int /定义符号uint为数据类型符unsigned intvoid main(void)uchar var1;uint var2;var1=XBYTE0x0005; /XBYTE0x0005访问片外RAM的0005字节单元var2=XWORD0x0002; /XWORD0x0002访问片外RAM的0002字单元xval=XBYTE0x0002; /把外部存储区地址0x0002的数据存入变量xval中XWORD0x0002=0x2000; /把0x2000送到外部存储区地址为0x0002的单元#define DAC0832 XBYTE0x7fff /定义DAC0832的端口地
51、址DAC0832=0x80; /启动一次D/A转换.while(1);在上面程序中,其中XBYTE0x0005就是以绝对地址方式访问的片外RAM 0005字节单元;XWORD0x0002就是以绝对地址方式访问的片外RAM 0002字单元。3.2.7 使用C51扩展关键字“_at_” 使用_at_对指定的存储器空间的绝对地址进行访问,一般格式如下: 存储器类型 数据类型说明符 变量名 _at_ 地址常数; 其中,存储器类型为data、bdata、idata、pdata等C51能识别的数据类型,如省略则按存储模式规定的默认存储器类型确定变量的存储器区域;数据类型为C51支持的数据类型。地址常数用于
52、指定变量的绝对地址,必须位于有效的存储器空间之内;使用“_at_”定义的变量必须为全局变量。【例】通过_at_实现绝对地址的访问。#define uchar unsigned char/定义符号uchar为数据类型符unsigned char#define uint unsigned int /定义符号uint为数据类型符unsigned intvoid main(void)data uchar x1 _at_ 0x40; /在data区中定义字节变量x1,它的地址为40Hxdata uint x2 _at_ 0x2000; /在xdata区中定义字变量x2,它的地址为2000Hx1=0xff
53、;x2=0x1234;.while(1);3.2.7 C51中断服务函数的定义 由于标准C没有处理单片机中断的定义,为直接编写中断服务程序,C51编译器对函数的定义进行了扩展,增加了一个扩展关键字interrupt,使用该关键字可以将一个函数定义成中断服务程序。由于C51编译器在编译时对声明为中断服务程序的函数自动添加了相应的现场保护、阻断其他中断、返回时恢复现场等处理的程序段,因而在编写中断服务函数时可不必考虑这些问题,减轻了用汇编语言编写中断服务程序的繁琐程度,而把精力放在如何处理引发中断请求的事件上。中断服务函数的一般形式为:void 函数名(void)interrupt n using m在函数声明时,用“interrupt n”语句,可以把所声明的函数定义为一个中断服务程序。从定
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 商业领域中的数字化转型战略研究
- 冀教版一年级语文下册期末测试题及答案
- 2025年铁垫项目市场调查研究报告
- 教育机构数字化办公的全方位安全保障
- 如何设计有效的数字化员工激励方案
- 探索数字化时代下的计量工具销售新模式
- 干扰素-α联合益血生胶囊治疗慢性乙型肝炎的持续疗效探究
- 小学生社交退缩现象剖析:亲子与同伴关系的深度影响
- 大学生创业态度与创业意向的关联及驱动因素研究
- 以数字化引领开放教育资源新未来
- 2020年高考英语试卷(新课标Ⅰ)(含解析版)
- DB34∕T 4410-2023 灿型水稻苗期耐热性鉴定技术规程
- 水利水电工程施工(CB)、监理(JL)表格大全
- SJG 171-2024 建筑工程消耗量标准
- 上海研学旅行课程设计
- DB1331T019-2022 雄安新区岩土基准层划分导则
- 电力拖动自动控制系统(第5版)阮毅课后习题答案
- 幼儿园小班安全活动《认识消防员》课件
- NB/T 11546-2024煤矿用5G通信系统通用技术条件
- 2023年高考数学试卷(上海)(秋考)(解析卷)
- 腾讯00后研究报告
评论
0/150
提交评论