资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,作者:夏路易,电子工业出版社所有,*,单片机技术基础教程与实践,第2章 51单片机程序的C语言描述,使用C语言进行51单片机编程是单片机系统开发的发展方向,C语言是通用计算机程序设计语言,但现在也广泛用于单片机开发,C语言与汇编语言相比具有使用容易、可移植性好、可以直接操作硬件的特点,特别是在单片机上采用操作系统,则必须采用C语言编程。,对于初学单片机来说,采用C语言入门单片机也是一个好的选择,使用C语言可以避免汇编语言需要记忆大量指令的缺点,快速学会单片机。,Keil软件是一个简单易学的单片机C语言开发工具,Keil软件具有使用简单,功能强的特点。Keil软件加上C语言,是开发51单片机的利器,也是初学单片机必须掌握的单片机开发手段。,作者:夏路易,2.1 51单片机的存储器,51单片机具有如下所示的不同的存储空间,每个存储空间包括从0到最大存储范围的连续字节地址。在C51中按照存储数据的类型,将51单片机的存储器分为不同区域,下面简单介绍如下。,作者:夏路易,3.,特殊功能寄存器,SFR,SFR中很多寄存器都可位寻址,而且可以通过名字进行引用,例如如果要对中断使能寄存器IE中的EA 位进行寻址,可使用EA或IE.7或0AFH,SFR中包含控制定时/计数器、串行口中断源及中断优先级等寄存器,他们的寻址方式和DATA区中的其它字节和位一样可位寻址。,4.IDATA,区,51系列中的一些单片机,如8052,有附加的128字节的内部RAM,位于从80H开始的地址空间中,被称为IDATA。虽然IDATA区的地址和SFR的地址是重叠的,但因为IDATA区只能通过间接寻址来访问,所以可以分别寻址。,作者:夏路易,2.2 C语言基础知识,2.2.1 C语言的标识符和关键字,标识符用于标识语句、数据类型、函数、变量、数组、存储方式等对象,也就是这些对象的名字,在C语言中,标识符大小写敏感,就是大写与小写代表的对象是不同的。需要注意的是标识符号的第一个字母必须是下划线或是英文字母。,关键字是具有固定名称与特定含义的特殊标识符,也称为保留字,在C语言中不允许用户自定的标识符与关键字相同。,C语言中的关键字如下:,atuo break case const等,C51关键字如下:,bit sbit sfr sfr16 data bdata idata pdata 等,作者:夏路易,(1)char字符类型,char类型的长度是一个字节,通常用于定义处理字符数据的变量或常量。分无符号字符类型unsigned char和有符号字符类型signed char,默认值为signed char类型。,signed char类型用字节中最高位字节表示数据的符号,0表示正数,1表示负数,负数用补码表示。所能表示的数值范围是128+127。unsigned char常用于处理ASCII字符或用于处理小于或等于255的整型数。正数的补码与原码相同,负数的补码等于它的绝对值按位取反后加1。,unsigned char类型用字节中所有的位来表示数值,所可表达的数值范围是0255;非常适合51单片机使用,因为51单片机每次处理8位数据。,(2)int 整型,整型长度为两个字节,用于存放一个双字节数据。分有符号int整型数signed int和无符号整型数unsigned int,默认值为signed int类型。signed int表示的数值范围是32768+32767,字节中最高位表示数据的符号,0表示正数,1表示负数。unsigned int表示的数值范围是065535。,作者:夏路易,(3),long 长整型,长整型长度为四个字节,用于存放一个四字节数据。分有符号long长整型signed long和无符号长整型unsigned long,默认值为signed long类型。signed int表示的数值范围是2147483648+2147483647,字节中最高位表示数据的符号,0表示正数,1表示负数。unsigned long表示的数值范围是04294967295。,(4)float 浮点型,浮点型符合IEEE754标准的单精度浮点型数据,占用四个字节(32位二进制数)。,(5)*指针型,指针型本身就是一个变量,在这个变量中存放指向另一个数据的地址。这个指针变量要占据一定的内存单元,对不同的处理器长度也不尽相同,在C51中它的长度一般为13个字节。指针变量也具有类型。,(6)bit 位标量,位标量是C51编译器的一种扩充数据类型,利用它可定义一个位标量,但不能定义位指针,也不能定义位数组。它的值是一个二进制位,不是0就是1,类似一些高级语言中的Boolean类型中的True和False。与51单片机有关的位操作必须定位在片内RAM中的位寻址空间。,作者:夏路易,(7)sfr 特殊功能寄存器,特殊功能寄存器也是一种扩充数据类型,占用一个内存单元,值域为0255。利用它可以访问51单片机内部的所有特殊功能寄存器。例如sfr P1=0 x90这一语句定义P1标识符代表单片机P1端口在片内的寄存器(地址0 x90),在后面的语句中可以用P1=255(对P1端口的所有引脚置高电平)之类的语句来操作特殊功能寄存器。,用法:sfr 特殊功能寄存器名=地址常数;,作者:夏路易,(9)sbit 可寻址位,sbit是C51中的一种扩充数据类型,利用它可以访问芯片内部的RAM中的可寻址位或特殊功能寄存器中的可寻址位。,例如,sfr P0=0 x80;/因P1端口的寄存器是可位寻址的,所以我们可以定义 sbit P0_1=P01;/P1_1为P1中的P1.1引脚 /同样我们可以用P1.1的地址去写,如sbit P1_1=0 x91;,这样在以后的程序语句中就可以用P1_1来对P1口的引脚1进行读写操作了,,以上所述的数据类型中,只有bit与unsigned char两种数据类型可以直接机器指令。,作者:夏路易,2.2.3 常量,在程序运行过程中,数值不改变的量称为常量。,(1)整型常量可以表示为十进制如123,0,89等。十六进制则以0 x开头如0 x34,-0 x3B等。长整型就在数字后面加字母L,如104L,034L,0 xF340等。(2)字符型常量是单引号内的字符,如a,d等,不可以显示的控制字符,可以在该字符前面加一个反斜杠组成专用转义字符。,作者:夏路易,(3)字符串型常量由双引号内的字符组成,如test,OK等。当引号内的没有字符时,为空字符串。在使用特殊字符时同样要使用转义字符如双引号。在C中字符串常量是作为字符类型数组来处理的,在存储字符串时系统会在字符串尾部加上“o”转义字符以作为该字符串的结束符。字符串常量A和字符常量A是不同的,前者在存储时多占用一个字节的空间。,(4)符号常量,代替常量的标识符,称为符号常量。例如,语句#define DATA 60中,DATA就是代表常数60的符号常量。符号常量不是变量,常用大写字母书写,而变量常用小写字母书写。,符号常量的定义:,#difine False 0 x0;/用预定义语句可以定义常量,作者:夏路易,2.2.4 变量,1.变量的定义,在C语言中,定义变量需要四方面的内容:,(1)变量的数据类型,例如int,char 等,(2)变量的作用范围,与变量声明的位置有关,(3)变量的存储种类,就是在变量的存储方法,不同的存储方法,影响变量的存在时间。,(4)变量的存储类型,就是确定变量的存储在哪类存储器中。,2.变量的定义格式,定义一个变量的格式如下:,存储种类 数据类型 存储类型 变量名表,(1)在定义格式中除了数据类型和变量名表是必要的,其它是可选项。,(2)变量的存储类型,按照变量的有效作用范围,可以将变量划分为局部变量和全局变量,还可以按照变量的存储种类对变量进行划分。,作者:夏路易,变量分为:内部变量(自动变量(auto)、静态变量(static)、寄存器变量(register)外部变量(全局变量、静态变量),自动变量:,在变量前加存储种类说明符号 auto 则该变量是自动变量。在函数体内部定义的变量,如果没有存储类型说明,都是自动变量。自动变量的作用范围在定义它的函数体内部。,自动类变量在动态存储器中分配单元,调用函数时,建立该变量存储单元,函数返回时,该变量存储单元自动放弃。,外部变量:,使用存储类型说明符号extern定义的变量为外部变量,凡是在所有函数之前,在函数外部定义的变量都是外部变量,定义时可以没有说明符号extern,但是一个函数体内说明一个已经定义过的外部变量时,则必须有说明符号extern。一个外部变量被定义后,就为它分配了固定的内存空间,外部变量的生存期是整个程序执行时间,一直占用存储单元,因此外部变量是全局变量。各个函数使用的外部变量,只需要在一个函数中定义,在使用该变量的函数中用extern说明就可以使用了。,若一个源文件中要引用其他源文件中定义的全局变量,就需要在文件的开头用关键字extern说明引进的变量,例如,extern int x;则说明x是其他文件中已经定义的全局变量。,作者:夏路易,静态变量:,使用存储种类说明符号static定义的变量称为静态变量,在函数体外定义静态全局变量与在函数体内部定义的静态局部变量,都占用存储单元不释放,直到程序结束。也就是,在函数返回时存储器中仍保留该变量位置,使其值具有连续性,静态局部变量的默认初值为0。,静态全局变量的有效范围为定义点到程序的结束,而且只有在定义它的程序模块文件中有效(这一点与全局变量有区别),其他文件不能改变其内容。静态,全局变量的默认值是0。,寄存器变量:,C语言允许使用频率高的变量定义为寄存器变量,这样的变量前需要加存储类型符号register,其实这只是给编译器一个建议,原因是寄存器数量有限,需要编译器根据实际情况决定。,(3)存储器类型的说明就是指定该变量在C51硬件系统中所使用的存储区域,并在编译时准确的定位。需要注意的是在AT89S51芯片中RAM只有低128位。,Keil软件所能区别的存储类型如下:,作者:夏路易,存储类型,说明,data,直接访问内部数据存储器,bdata,可位寻址内部数据存储器,idata,间接访问内部数据存储器,pdata,分页访问外部数据存储器,xdata,外部数据存储器(64KB外部RAM),,code,程序存储器(片内4kB)或(64KB片外FLASH),当使用data、bdata定义常量与变量时,C51编译器将其定位在片内存储器。,当使用code存储类型,C51编译器将其定位片内或片外FLASH存储器中。,当使用xdata存储类型,C51编译器将变量定位在片外RAM,寻址范围为64k。,如果省略变量的存储类型说明,C51编译器则会按存储模式SMALL,COMPACT或LARGE所规定的默认存储类型去指定变量的存储区域。,作者:夏路易,存储模式说明:,SMALL存储模式,把变量和堆栈都放在51单片机片内RAM(128字)中,默认数据类型是data。,COMPACT存储模式,把变量和数据定位在51单片机的分页片外存储区(256字节),默认的存储类型是pdata。,LARGE存储模式,把变量都定位在8051系统的外部数据区外部数据区(64KB),默认存储类型是xdata。,作者:夏路易,3.定义特殊功能寄存器有关的变量,sfr,sbit定义变量的方法如下:,(1)sfr直接对51单片机的特殊寄存器进行定义,格式如下:,sfr 特殊功能寄存器名=特殊功能寄存器地址常数;,例如:sfr P0=0 x80;/定义P0 I/O口,其地址80H,sfr P1=0 x90;/定义P1 I/O口,其地址90H,sfr关键字后面是一个要定义的变量名字,可任意选取,但要符合标识符的命名规则,名字最好有一定的含义如P1口可以用P1为名,等号后面必须是常数,不允许有带运算符的表达式,而且要求常数必须在特殊功能寄存器的地址范围之内(80HFFH)。,作者:夏路易,(2)关键字sbit定义可位寻址空间的特殊位,格式如下:,格式1:sbit 位变量名位地址;例如:sbit P1_1=Ox91;相当于把特殊寄存器地址空间位寻址区的绝对地址0 x91赋给位变量P1_1。同sfr一样sbit的位地址必须位于地址80H-FFH之间。,格式2:sbit 位变量名特殊功能寄存器名位位置 位位置范围为07之间 例1:sft P1=0 x90;/首先定义字节变量P1 sbit P1_1=P1 1;/然后再指定位变量P1_1在字节变量P1中的位置 1。,格式3:sbit 位变量名字节地址位位置 例如:sbit P1_1=0 x90 1;,格式3和格式2是一样的,只是把字节的地址直接用常数表示。,作者:夏路易,2.2.5 数组,(1)一维数组,一维数组的声明格式为:,类型说明符 数组名常量表达式;,一维数组初始化:,显示十进制数字09的共阳数码管段译码数组:,unsigned char seg10=0 xC0,0 xF9,0 xA4,0 xB0,0 x99,0 x92,0 x82,0 xF8,0 x80,0 x90;,作者:夏路易,(2)二维数组,二维数组的格式为:,类型说明符 数组名下标1下标2;,unsigned int Table410=,0 x002,0 x040,0 x0BC,0 x138,0 x1B4,0 x230,0 x2AC,0 x328,0 x3A4,0 x420,0 x49C,0 x518,0 x594,0 x610,0 x68C,0 x708,0 x784,0 x800,0 x87C,0 x8F8,0 x974,0 x9F0,0 xA6C,0 xAE8,0 xB64,0 xBE0,0 xC5C,0 xC08,0 xD54,0 xDD0,0 xE4C,0 xEC8,0 xF44,0 xFC0,0XFFF ;,作者:夏路易,2.3 运算符,2.3.1 关系与逻辑运算符,关系运算,C,语言提供了6种关系运算符:,=,=,!=,其中:,2.,C,语言提供了三种逻辑运算:&(逻辑与),|(逻辑或),!(逻辑非)。,逻辑运算符举例:,a&b,若,a,b,都为真,则,a&b,为真,a|b,若,a,b,之一为真,则,a|b,为真,!,a,若,a,为真,则!,a,为假,作者:夏路易,2.3.2 赋值运算符,赋值运算符“=”是一个二元运算符,左边必须是变量或数组元素,右边是表达式。,复合算术运算:+=,=,*=,/=,%=,,复合位运算:=,=,|=,=,=,x+=a;等价于x=x+a,x=a;等价于x=xa,x*=a;等价于x=x*a,x/=a;等价于x=x/a,x%=a;等价于x=x%a,作者:夏路易,逻辑、算术、关系和赋值运算符之间的优先级关系:,运算种类,优先级,!(非),最高,算术运算符,关系运算符,逻辑“与”和逻辑“或”,赋值运算符,最低,作者:夏路易,2.3.3 逗号运算符,逗号运算符的作用是把几个表达式串在一起,成为逗号表达式。格式为:,表达式1,表达式2,表达式n,运算顺序为从左到右,整个逗号表达式的值是最右边表达式的值。例如:,x=(y=4,y+3),是将括号中的逗号表达式的值赋给x。结果x的值为7。使用逗号运算符一次可以实现几个赋值语句。,作者:夏路易,2.3.4?,与,:运算符(条件运算符),C语言提供了一个代替某些ifthenelse 结构的运算符“?”与“:”,这个运算符是三元的,其一般形式为:,表达式1:表达式2:表达式3,运算符“?”作用是在计算表达式1之后,如果表达式1为真,则计算表达式2,并将结果作为整个表达式的数值;如果表达式1的值是假,则计算表达式3,以它的结果作为整个表达式的值。,例如:y=ab?3:5;,作者:夏路易,2.3.5 数据类型转换,1.隐式转换,用运算符连接的操作数如果具有不同的数据类型,首先按照以下顺序转换:,float转double,char转int,然后按照从int、unsigned、long到double的顺序转换。,2.强制转换:,强制转换运算符的作用是将一个表达式转换成所需类型,格式为:,(类型名)(表达式),例如:,(int)a 将a转换为整型,作者:夏路易,2.3.6 位运算符,位运算符,含义,&,按位与,|,按位或,按位异或,位取反,右移位,作者:夏路易,1.按位与“&”运算符,参加运算的两个数据按位作与运算,相应的二进制位都是1结果为1,否则为0。,2.按位或“|”运算符,参加运算的两个数据按位作或运算,其中只要有一位为1,运算后该位仍为1。,3.按位异或“”运算符,参加运算的两个数据按位作异或运算,并且遵循相同为0,相异为1的原则。,4.位取反“”运算符,该运算符适合于单操作数运算,用来对二进制数按位取反。,5.位左移“”运算符,将二进制数右移若干位,右边移出得数舍弃,无符号数左边补0,有符号数左边补与符号位相同得数,一般为正数补0,负数补1。,位运算符与“=”的复合运算符相当于将位运算完成后,再赋值。,在ANSI C中,一般是通过读修改写的方法实现单个位操作:,可以与“0”相与,实现位清0,例如,将m变量的b0位清0,则可以写为m=m,2.3.7 自增自减运算符,自增自减运算符可以使变量值自动加1或减1。,例如,+j;在使用j之前,使j加1,j+;在使用j之后,使j加1,自增自减运算符只能用于变量。,作者:夏路易,2.4 C程序结构,2.4.1 C程序设计的三种基本结构,1.顺序结构,流程如图2-1。先执行A操作,再执行B操作,两者是顺序执行的关系。,2.选择结构,流程如2-2图所示。P代表一个条件,当P条件成立(或称为“真”)时执行A,否则P条件不成立(称为“假”)则执行B。注意,只能执行A或B之一。,3.循环结构,有两种循环结构:,(1)当型循环结构,见图2-3。当条件成立(“真”)时,反复执行操作。直到为“假”时才停止循环。,(2)直到型循环结构,见图2-4。先执行操作,再判断是否为“假”,若为“假”,再执行,如此反复,直到为“真”为止。,作者:夏路易,图2-1,图2-2,图2-3 当型循环结构,图2-4 直到型循环结构,作者:夏路易,2.4.2 条件与分支结构,1.条件(if)语句,C语言提供了三种形式的if语句:,(1)if(表达式)语句;,例如:if(xy)x=1;,(2)if(表达式)语句1;else 语句2;,例如:if(xy)x=1;,else x=5;,(3)if(表达式1)语句1;,else if(表达式2)语句2;,else if(表达式3)语句3;,else if(表达式m)语句m;,else 语句n;,作者:夏路易,2.分支(Switch)语句,Switch 语句是多分支选择语句,非常适合实际问题中需要用到多分支的选择。例如,学生成绩分类(90分以上为A等,8090分为B等,7079 分为C等,。);,switch语句的一般格式如下:,Switch(表达式),case 常量表达式1:语句1;break;,case 常量表达式2:语句2;break;,。,case 常量表达式n:语句n;break;,default :语句n+1;break;,只要switch括号中表达式的值与某一case语句后的常量表达式的值相等时,就执行其后的语句;若是所有case后的常量表达式值都不相同时,就执行default后的语句。,(3)每一个case后的常量表达式不能相同。,(4)case后语句的排列顺序,与程序执行结果无关。,作者:夏路易,对于switch语句,需要注意:,(1)常量表达式的值必须是整型,字符型或者枚举类型。,(2)break 语句用于跳出switch结构。,作者:夏路易,2.4.3 各种循环结构,C语言中有三种循环语句:while、for和do while语句。,1.for循环结构,C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替while语句。,for 语句的一般形式为,for(循环变量初始化表达式1;关系表达式2;循环变量运算表达式3;)语句,作者:夏路易,(1)for 语句一般形式中的“循环变量初始化表达式1”可以省略,此时应在for语句之前给循环变量赋初值。注意省略循环变量表达式1时,其后的分号不能省略。例如,,sum=0;,for(;i=100;i+),sum=sum+i;,(2)如果省略关系表达式2,即不判断循环条件,循环无终止的进行下去。,(3)循环变量运算表达式3也可省略,但其后必须添加相应语句使其正常执行。例如,,sum=0;,for(i=1;i=100;),sum=sum+1;,i+;/代替循环变量运算表达式,(4)for语句中的三个表达式都可以省,即for(;),此时该语句相当于while(1)语句。,(5)没有循环体的for语句,例如,for(j=0;j1000;j+);这种类型的for语句常用作时间延迟操作。,作者:夏路易,2.while 循环,while语句常用来实现“当型”循环结构。其一般格式如下:,while(表达式)循环体语句;,当表达式为非0值时执行while 语句中的内嵌语句。其特点是:先判断表达式,后执行语句。,需要注意:,(1)无限次循环的格式是while(1),因为while表达式中的值永远不是0。,作者:夏路易,3.do_while 循环,常用来实现“直到型”循环结构。其一般形式为:,do 语句;,while(表达式);,在一般情况下,用while语句和用do_while语句处理同一问题时,若二者的循环体部分是一样的,它们的结果也一样。但是while后面的表达式一开始就为假(0值)时,两种循环的结果是不同的,因为do while语句中的循环体已经执行了一次。,作者:夏路易,5.break 语句,在循环语句中,break语句的作用是在循环体中测试到应立即结束循环条件时,控制程序立即跳出循环结构,转而执行循环语句后的语句。,6.continue 语句,continue 语句只能用于循环结构中,作用是结束本次循环。一旦执行了continue语句,程序就跳过循环体中位于该语句后的所有语句,提前结束本次循环周期并开始新一轮循环。,作者:夏路易,2.5 函数,2.5.1 定义函数,C语言结构就是函数结构,一般分为主函数main()和普通函数,普通函数分为:,(1)标准库函数,编译软件提供的函数,使用这些函数,需要在C程序中包含库函数文件。,(2)用户自定义函数,就是用户自己根据需要编写的函数,这些函数分为:无参数函数、有参数函数和空函数(无语句,用于功能扩充)。,程序中只有一个主函数,在主函数中调用其他函数,一般来说主函数不断循环执行,因此也不断地调用其他函数。,作者:夏路易,1.函数的定义,函数的一般格式如下:,void 函数名(void)/无参数函数,函数类型说明 函数名(形式参数表)/有参数函数,就是调用函数向被调用函数传递参数,形式参数说明;,局部变量说明;,函数体语句;,return(返回参数值)/有参数返回函数的返回值语句,其中:,函数类型说明用于自定义函数返回值类型的说明。如果没有类型说明符,则默认返回值为整型。如果没有返回值,则需要使用关键字void来说明。,形式参数表列出了调用该函数时向该函数传递数据的形式参数,所谓参数其实就是该函数的输入量。如果没有形式参数,则需要在参数列表中输入关键字void。,作者:夏路易,2.5.2 调用函数,1.调用函数的条件,一个函数调用另一个函数必须具备如下条件:,(1)被调用的函数必须是已经存在的函数:,(2)如果是库函数,应该在程序开头用#include命令声明相应的库函数,例如:,#include 。,(3)如果是自定义函数,而且被调用函数与调用函数在同一文件内,则应该:,如果被调用函数在调用函数之后,一般需要在调用函数中的调用函数语句前声明被调用函数,声明格式为:返回值类型说明 被调用函数名();,作者:夏路易,2.函数调用语句,(1)函数作为语句,把函数作为一个语句,函数无返回值,只是完成某种操作。语句格式为:,函数名(参数),如果没有参数,可以用空括号。,例如,Init();/调初始化函数,(2)函数作为表达式,函数可以出现在一个表达式中,例如:,sum=c+add(a,b);/全加和等于进位加上本位半加和,(3)函数作为参数,被调用的函数作为另外一个函数的参数,例如:,sum=add(c add(a,b);/将add的返回值作为参数,作者:夏路易,(1)char字符类型,对于初学单片机来说,采用C语言入门单片机也是一个好的选择,使用C语言可以避免汇编语言需要记忆大量指令的缺点,快速学会单片机。,格式3:sbit 位变量名字节地址位位置 例如:sbit P1_1=0 x90 1;,1 C语言的标识符和关键字,第2章 51单片机程序的C语言描述,就是用户自己根据需要编写的函数,这些函数分为:无参数函数、有参数函数和空函数(无语句,用于功能扩充)。,正数的补码与原码相同,负数的补码等于它的绝对值按位取反后加1。,循环变量运算表达式3;,在变量前加存储种类说明符号 auto 则该变量是自动变量。,(2)清零外部数据存储器,unsigned char,可位寻址内部数据存储器,需要注意的是标识符号的第一个字母必须是下划线或是英文字母。,一个外部变量被定义后,就为它分配了固定的内存空间,外部变量的生存期是整个程序执行时间,一直占用存储单元,因此外部变量是全局变量。,(3)if(表达式1)语句1;,(1)中断服务函数的格式,函数类型 函数名(形式参数表)interrupt N using n,形式参数说明,局部变量定义,函数语句,51单片机的常用中断源和中断向量如下:,N,中断源,中断向量 8N+3,0,外中断0,0003H,1,定时器0,000BH,2,外中断1,0013H,3,定时器1,001BH,4,串行口,0023H,作者:夏路易,式中的n是内部RAM中的4个寄存器组的编号,每个寄存器组包含8个工作寄存器(R0R7),C51扩展了一个关键字using,专门用于选择寄存器组,using后的n是一个03的常数。若是不用该选项,则编译器自动选择一组寄存器。,1.中断函数不能进行参数传递,如果中断函数中包含任何参数声明将出现编译错误。,2.中断函数没有返回值,应该定义为void类型。,3.任何情况下不能直接调用中断函数,否则产生编译错误。,作者:夏路易,2.5.3 函数变量的作用域,按照变量的有效作用范围可划分为局部变量和全局变量。,1.局部变量,在函数内部定义的变量称为局部变量。局部变量仅在被定义的函数模块内部起作用。,2.全局变量,在所有函数模块中起作用的变量称为全局变量或是外部变量。全局变量定义在主函数的顶部,因此在主函数调用的所有函数模块中都有效。如果在一个程序模块文件中引用另一个程序模块文件中定义的变量时,需要用extern进行说明,外部变量的说明与定义不同,外部变量只能定义一次(在所有函数之外),但是可以说明多次,就是在引用该外部变量的函数中都需要说明。,(1)如果全局变量与某一函数中的局部变量同名,则局部变量优先于全局变量。,(2)全局变量一旦定义,就占用固定的存储空间,就是说在程序运行中,这些存储空间不能释放以供他用。,(3)全局变量在函数模块外定义,所以不利于函数移植。,(4)大量使用全局变量,使程序难以调试。,(5)全局变量的初始化语句,增加了程序的长度。,(6)全局变量的特点是多个函数共同使用,因此必须注意各函数对其值操作的顺序性。,作者:夏路易,2.6 其他C语句,C预处理器扩展了C编译环境的范围。所有的预处理指令以标志#开头,每一条预处理指令必须有它自己的一行。,1.#define,#define语句又称为宏定义语句。,#define指令用来定义一个标识符和一个字符序列,这些标识符与字符序列可以替代每一次在源文件中的碰到的标识符,该指令格式如下:,#define 标识符 常量表达式 /注意没有分号,例如:#define TRUE 1 /用TRUE表示1,一旦定义了一个标识符,则该标识符可以作为其他标识符的一部分:,例如:#define ONE 1,则有#define TWO ONE+ONE,通常,C程序中用大写字母代表被定义的标识符,这样就可以使阅读程序的时候,一目了然地知道这是一个宏替换。,#define语句还可以带有参数,格式如下:,#define 标识符(参数表)表达式,作者:夏路易,2.文件包含,#include语句可以在一个源文件A中包含其他源文件中的内容,这样源文件A就是由多个源文件组成,文件包含的格式如下:,#include,尖括号表示被包含文件的搜索方式由编译器控制,这意味着被包含文件在特殊的文件夹中。,#include“文件名”,双引号表示首先搜索当前工作文件夹,若是没有找到文件,则搜索尖括号情况下的文件夹。,经常使用的包含文件是后缀为h的文件,例如,51单片机的头文件:,#include,一般来说,对应每个C源文件,都有一个对应的扩展名为h文件,该文件中包含C文件中的常量、数据结构、函数、全局变量的声明等。,作者:夏路易,作者:夏路易,2.6.2 用typedef重定义数据类型,类型定义可以把已有的类型标识符定义成新的类型表示符,定义后,新的类型标识符就可以作为原标识符使用,相当于给老的类型标识符改了一个名字。,格式:,typedef 原类型名 新类型名;,例如:typedef int integer;,定义后,就可以用新类型名声明变量:,integer m,n;,作者:夏路易,2.7 C51编译过程中用到的文件,2.7.1 特殊功能寄存器头文件,51系列单片机中用到很多特殊功能寄存器,将这些寄存器地址以及寄存器中的位地址用关键字说明,则关键字与寄存器地址、寄存器中的位地址之间关系的说明文件就是头文件,因此每种类型的单片机头文件都是不同的,单片机生产厂家提供的头文件放在keilC51inc文件夹中,例如,Atmel公司芯片的头文件如图所示。,用户也可以自己编写头文件,例如使用某些公司的51内核单片机时,其特殊寄存器的大部分关键字都已经在标准51头文件定义了,则只需要在源文件中,直接定义其余关键字就可以了。,图2-6 配置文件所在的文件夹,作者:夏路易,2.7.2 C51编译器的配置文件,C51编译过程中,用到一些配置文件,如果只是开发一般的51单片机程序,用缺省的配置文件就可以满足需求,特别是对初学51单片机,用缺省配置文件完全满足需求。,作者:夏路易,STARTUP.A51文件放在如图示的Lib文件夹中,该文件在51单片机上电后立即执行,并进行如下操作。,(1)清零内部数据存储器,(2)清零外部数据存储器,(3)清零外部页数据存储器,(4)初始化SMALL模式下重入堆栈和栈指针,(5)初始化LARGE模式下重入堆栈和栈指针,(6)初始化COMPACT模式下重入堆栈和栈指针,(7)初始化51单片机的硬件堆栈指针,(8)将控制权主函数,启动代码随单片机的类型不同而不同,如下是一些厂商单片机的起动代码:,作者:夏路易,启动文件,说明,STARRUP.A51,标准51单片机的启动代码,START_AD.A51,ADuC83x and ADuC84x单片机,START4xx,Dallas DS89C420/430/440/450,START390.A51,Dallas 390/5240系列单片机,START_XC.A51,Infineon XC8xx,START751.A51,Philips公司8xC749/750/751/752系列单片机,START_MX.A51,Philips公司80C51MX系列单片机,start900,Philips LPC9xx,start950,Philips LPC95x,STARTLPC.A51,Philips公司LPC系列单片机,作者:夏路易,2.8 Intel HEX文件的格式,写入单片机的文件一般是Intel HEX文件格式,一个Intel HEX文件的一行称为一个记录,是由16进制字符组成,两个字符表示一个字节的值,Intel HEX文件通常由若干个记录组成,每个记录的格式如下:,;ll aaaa tt dd dd cc,其中:,;分号是记录开始标志,Intel HEX文件的每一行都是以分号“;”开头,ll 是记录长度,用来表示该记录的数据字节数。,aaaa 是装入地址,是该记录中第一个数据字节的16位地址值,是该记录在FLASH中的起始绝对地址。,tt 记录类型,00表示数据记录,01表示文件结束(EOF)。,dd dd 是记录的字节值,每个记录都有ll个字节的数值。,cc 是校验和,将cc值与记录中所有字节(包括记录长度ll)内容相加,结果应该为0。,作者:夏路易,所有记录类型为00型,只有最后一行的记录类型为01,内容为:00000001FF。下面是一个完整的Intel HEX文件:,:0300000002080DE6,:0C0800007F147E147DF8DDFEDEFADFF6CA,:01080C0022C9,:0C081900C2A0120800D2A012080080F457,:00000001FF,作者:夏路易,2.9 获得错误与警告信息,编写C程序不可能不出错误,在编译、链接操作结束,Keil软件会在信息窗口给出错误与警告信息,这时就应该在Keil软件的帮助菜单下找响应的错误与警告说明,找到Keil软件中帮助窗口,在该窗口可以找到编译器(Cx51 Compiler Users Guide)、链接器(BL51 Linker Users Guide)的用户手册,在这些手册中,可以找到有关错误与警告信息(Error Messages)的说明。,作者:夏路易,作者:夏路易,
展开阅读全文