第7章51单片机C语言简介7.1C语言的基本知识7.2C51程序设计的基本语法7.3C51程序设计7.4函数7.5模块化程序设计7.6C51编程实例7.1C语言的基本知识7.1.1C语言的特点与程序结构以前计算机的系统软件主要是用汇编语言编写的,对于单片机应用系统来说更是如此。由于汇编语言程序的可读性和可移植性都较差,采用汇编语言编写单片机应用系统程序的周期长,而且调试和排错也比较困难。为了提高编制计算机系统和应用程序的效率,改善程序的可读性和可移植性,最好采用高级语言编程。C语言既具有一般高级语言的特点,又能直接对计算机的硬件进行操作,并且采用C语言编写的程序能够很容易地在不同类型的计算机之间进行移植。与其它计算机高级语言相比,C语言具有它自身的特点:1.语言简洁,使用方便灵活。2.可移植性好。3.表达能力强。4.可进行结构化程序设计。5.可以直接操作计算机硬件。6.生成的目标代码质量高。尽管C语言具有很多的优点,但和其它任何一种程序设计语言一样,也有其自身的缺点,如不能自动检查数组的边界,各种运算符的优先级别太多,某些运算符具有多种用途等。C语言程序是由若干个函数单元组成的,每个函数都是完成某个特殊任务的子程序段。组成一个程序的若干个函数可以保存在一个源程序文件中,也可以保存语言源程序文件的文件名由程序设计人员根据某种俗成规则自己确定,其扩展名统一为“.C”。如A1-1.C、A2-1.C。C语言程序的开始部分通常是预处理命令,如程序中通常遇到的#include命令。这个预处理命令通知编译器在对程序进行编译时,将所需要的头文件读入后再一起进行编译。一般在“头文件”中包含有程序在编译时的一些必要的信息,通常C语言编译器都会提供若干个不同用途的头文件。头文件的读入是在对程序进行编译时才完成的。C语言程序是由函数所组成的。一个完整的C语言程序应包含一个主函数main()和若干个其它功能的函数。函数之间可以相互调用,但main()函数只能调用其它的功能函数,而不能被其它函数所调用。功能函数可以是C语言编译器提供的库函数,也可以由用户按实际需要自行编写的函数。不管main()函数处于程序中的什么位置,程序总是从main()函数开始执行。一个函数必须预先定义或声明后才能调用。函数定义或声明位于源程序的预处理命令之后的开始位置。函数定义部分包括有函数的存储类型、返回值数据类型、函数名、形式参数说明等,函数名后面必须跟一个圆括弧(),形式参数说明在圆括弧()内进行。函数也可以没有形式参数,如main()。函数的位置比较自由。可以由程序设计人员安排在函数定义后的任意位置。函数由函数名和一对花括弧“{}”组成,在“{}”里面的内容就是函数体,如果一个函数有多个“{}”,则最外面的一对“{}”为函数体的范围。函数体的内容为若干条语句,一般有两类语句,一类为说明语句,用来对函数中将要用到的变量进行定义;另一类为执行语句,用来完成一定的功能或算法处理。有的函数体仅有一对“{}”,其中既没有变量定义语句,也没有执行语句,这也是合法的,称为“空函数”。C语言源程序可以采用任何一种编辑器来编写,既可以是windows环境下的编辑器,如记事本(NOTEPAD)或写字板(WORDPAD),也可以是DOS环境下的编辑器,如EDIT或PE等。C语言程序的书写格式十分自由。一条语句可以写成一行,也可以写成几行;还可以在一行内写多条语句;但是需要注意的是,每条语句都必须以分号“;”作为结束符。另外,C语言区分大小写字母,C语言编译器在对程序进行编译时,对于程序中同一个字母的大小写作为不同的变量来处理。虽然C语言程序不要求具有固定的格式,但我们在实际编写程序时还是应该遵守一定的规则,一般应按程序的功能以“缩格”形式来写程序,同时还应在适当的地方加上必要的注释。注释对于比较大的程序来说是十分重要的,这有利于修改与读懂程序。C语言本身没有输入输出功能,C语言程序的输入和输出是通过函数调用来实现的。FranklinC51编译器提供的输入输出库函数scanf和printf是通过8051单片机的串行口实现的,在程序中使用这种输入输出库函数之前必须先对8051单片机的串行口进行初始化。但是对于单片机应用系统来说,由于具体要求的不同,应用系统的输入输出方式多种多样,不可能一律采用串行口作输入和输出。因此应该根据实际需要,由应用系统的研制人员自己来编写满足特定需要的输入输出函数,这一点对于单片机应用系统的开发研制人员来说是十分重要的。7.1.2C语言的标识符和关键字C语言的标识符是用来标识源程序中某个对象名字的。这些对象可以是函数、变量、常量、数组、数据类型、存储方式、语句等。一个标识符由字符串、数字和下划线等组成,第一个字符必须是字母或下划线,通常以下划线开头的标识符是编译系统专用的,因此在编写C语言源程序时一般不要使用以下划线开头的标识符,而将下划线用作分段符。C51编译器规定标识符最长可达255个字符,但只有前面32个字符在编译时有效,因此在编写源程序时标识符的长度不要超过32个字符。程序中对于标识符的命名应当简洁明了,含义清晰,便于阅读理解,如用标识符“max”表示最大值,用“TIMER0”表示定时器0等。关键字是一类具有固定名称和特定含义的特殊标识符,又称为保留字。在编写C语言源程序时一般不允许将关键字另作别用,换句话说就是对于标识符的命名不要与关键字相同。在C语言中,ANSIC标准一共规定了32个关键字,表7.1按用途列出了ANSIC标准的关键字。表7.1ANSIC标准的关键字关键字用途说明autobreakcasecharconstcontinuedefaultdodoubleelseenumexternfloatforgotoifintlongregisterreturnshortsignedsizeofstaticstructswitchtypedefunionunsignedvoidvolatilewhile存储类说明程序语句程序语句数据类型说明存储类型说明程序语句程序语句程序语句数据类型说明程序语句数据类型说明存储种类说明数据类型说明程序语句程序语句程序语句数据类型说明数据类型说明存储种类说明程序语句数据类型说明数据类型说明运算符存储种类说明数据类型说明程序语句数据类型说明数据类型说明数据类型说明数据类型说明数据类型说明程序语句用以说明局部变量退出最内层循环switch语句中的选择项单字节整型数或字符型数据在程序执行过程中不可能修改的变量值转向下一个循环switch语句中的失败选择项构成do...while循环结构双精度浮点数构成if...else选择结构枚举在其它程序模块中说明了的全局变量单精度浮点数构成for循环结构构成goto转移结构构成if...else选择结构基本整型数长整型数使用CPU内部寄存器的变量函数返回短整型数有符号数,二进制数据的最高位为符号位计算表达式或数据类型的字节数静态变量结构类型数据构成switch选择结构重新进行数据类型定义联合数据类型无符号数据无符号数据说明该变量在程序执行中可被隐含地改变构成while和do...while循环结构关键字用途说明bitsbitsfrsfr16databdataidatapdataxdatacodeinterruptUsingreetrant位标量声明位标量声明特殊功能寄存器声明特殊功能寄存器声明存储器类型声明存储器类型声明存储器类型说明存储器类型说明存储器类型说明存储器类型说明中断函数说明寄存器组定义再入函数声明声明一个位标量或位类型的函数声明一个可位寻址变量声明一个特殊功能寄存器(8位)声明一个16位的特殊功能寄存器直接寻址的8051内部数据存储器可位寻址的8051内部数据存储器间接寻址的8051内部数据存储器“分页”寻址的8051外部数据存储器8051外部数据存储器8051程序存储器定义一个中断函数定义8051工作寄存器组定义一个再入函数C51编译器除了支持ANSIC标准关键字以外,还扩展了如表7.2所示的关键字:表7.2C51编译器的扩展关键字7.1.3单片机C51程序的编译连接与调试FranklinC51交叉编译器是专为8051系列单片机设计的C语言编译器,它能在IBMPC及其兼容机上运行,使用非常方便。为了保证编译器能正常工作,PC机应具有512K以上的内存、一个软盘驱动器、一个硬盘,采用MSDOS3.0以上版本的操作系统。FranklinC51以软件包的形式提供,软件包中主要有C51交叉编译器、A51交叉汇编器、L51连接定位器、OHS51代码转换器和dScope一51软件仿真调试器以及其它一些实用软件程序。如果在PC机的硬盘C:上安装C51编译器,在安装之前应对PC机的配置文件CONFIG.SYS和自动批处理文件AUTOEXEC.BAT作如下修改:CONFIG.SYS:FIELS=20BUFFER=20AUTOEXEC.BAT:SETC51LIB=C:\C51\LIBSETC51INC=C:\CSI\INCSETPATH=C:\C51\BIN这样修改之后,C51编译器会当头文件不在当前目录时,能从C:\C51\INC子目录中找到头文件;L51连接器会自动为所有的编译模式及算术(尤其是浮点运算)功能从C:\C51\LIB于目录中找到所需要的库文件。C51编译器可根据不同的硬件环境由4个文件做出修改。下列配置文件包括在C51软件包中:STARTUP.A51:C51编译器的启动程序,所有的栈指针和存贮器,只要需要,将被初始化。INT.A51:在文件中已明确初始化了的变量作初始化。如果系统装了“看门狗”,该文件可包含附加的“看门狗”刷新。PUTCHAR.C:函数“printf”、“puts”等的字符输出核心程序,该程序可根据用户硬件加以修改(如LCD显示)。GETKEY.C:函数“getchar”、“scanf”等的字符输入核心程序,该程序可根据硬件加以修改(如矩阵键盘)所有文件都包含在C运行库中,因此,不能在连接时指定调用。如果用户改变一个文件,可将其编译后与其它目标文件一起连接,因而不必改动运行库。库中原文件自动忽略。例:L51MYMODUL1.OBJ,MYMODUL2.OBJ,STARTUP.OBJ,PUTCHAR.OBJ上例将用户建立的STARTUP.OBJ和PUTCHAR.OBJ连接起来。用C语言编写的程序必须通过编译和连接之后,才能生成可执行代码。C51编译器由命令“C51”启动,例如以EXI2.C为文件名的程序编译命令如下;C51EXI2.CCODEDEBUG(回车)C51是编译器启动命令,EXI2.C是程序文件名,CODE和DEBUG是编译控制指令。输入完命令后回车,即可进人编译过程。如果编译过程中未发现错误,屏幕上会显示出:C51COMPILATIONCOMPILETE,0WARING(S),0ERROR(S)并产生列表文件EXI2.LST和目标文件EXI2.OBJ。如果编译中发现任何错误,则不产生目标文件,而将所有的错误信息都在列表文件中表示出来。编译控制指令CODE使列表文件的后面附加一个汇编语言文件。编译控制指令DEBUG使目标文件中包含有进行源程序调试时需要的各种符号信息。目标文件中还包含有可再定位的目标码,以供L51连接器作进一步的处理。C51编译器提供了许多不同控制指令可以完成各种编译控制功能。7.2C51程序设计的基本语法C语言是一种程序设计语言,采用C语言进行程序设计时,需要遵循一定的语法规则。7.2.1C语言的数据类型C语言的数据结构是以数据类型出现的,数据类型可分为基本数据类型和复杂数据类型,复杂数据类型由基本数据类型构造而成。C语言中的基本数据类型有char,int,short,long,float和double。对于C51编译器来说,short型与int型相同,double型与float型相同。分别说明如下:1.char字符类型。有signedchar和unsignedchar之分,默认值为signedchar。对于signedcha