C51程序设计语言课件_第1页
C51程序设计语言课件_第2页
C51程序设计语言课件_第3页
C51程序设计语言课件_第4页
C51程序设计语言课件_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C51程序设计语言基础

C51程序设计语言C51的运算符和表达式

C51的头文件与库函数

C51程序设计及应用

C51的应用技巧随着80C51单片机硬件性能的提升,尤其是片内程序存储器容量的增大和时钟工作频率的提高,已基本克服了高级语言产生代码长、运行速度慢、不适合单片机使用的致命缺点。由此C51已经得到广泛的推广和应用。采用C51程序设计语言,编程者只需了解变量和常量的存储类型与80C51单片机存储空间的对应关系,而不必深入了解单片机的硬件和接口。C51编译器会自动完成变量的存储单元的分配。

C51程序设计语言C51语言概述成于大气信达天下C51语言的特点C提供了很多数学函数并支持浮点运算,开发效率高,故可缩短开发时间,增加程序可读性和可维护性C语言程序本身不依赖于机器硬件系统,基本上不作修改就可将程序从不同的单片机中移植过来C语言作为一种非常方便的语言而得到广泛的支持,国内最通用的是KeilC51#include<reg51.h> /*文件包含,51寄存器说明*/main() /*主函数*/{intx,y,z; /*变量定义(变量类型)*/if(x>y)z=x; /*运算符,基本语句*/elsez=y; }★C51程序示例:C51的程序结构与一般C语言的结构相同,以main()函数为程序入口,程序体中包含若干语句还可以包含若干函数。C-51函数的一般格式

类型函数名(参数表)

{

数据说明部分语句执行部分

}①程序由函数组成(一个主函数,或一个主函数和若干自定义函数);②利用预处理命令对变量或函数进行集中定义或说明;③函数和变量都需遵循先定义后使用的基本原则;④主函数中的所有语句执行完毕,则程序结束。C51与标准C程序结构完全相同举例:LED闪烁控制功能预处理命令---------函数说明------------全局变量定义------

主函数------------调用函数------------局部变量定义---------

程序体

程序体------C51简单例题#include"AT89X51.H"//包含头文件voidmain(void)//主程序{while(1)//无限循环{P2_0=0;//亮灯P2_0=1;//灭灯}}成于大气信达天下一、C51中常用的头文件Reg52.h

(定义单片机的特殊功能寄 存器和端口)Stdio.h

(标准输入输出函数库)Math.h

(标准数学函数库)Absacc.h

(外部绝对地址访问函数库)Ctype.h

(字符函数库)Stdlib.h

(数学函数库)其它部分头文件:(1)头文件ctype.h字符处理函数本类别函数用于对单个字符进行处理,包括字符的类别测试和字符的大小写转换(2)头文件local.h

地区化本类别的函数用于处理不同国家的语言差异。(3)头文件math.h函数列表函数类别函数用途详细说明,如三角函数反余弦acos

反正弦asinC51常用头文件:(4)头文件signal.h信号处理该分类函数用于处理那些在程序执行过程中发生例外的情况(5)头文件stdio.h输入输出函数该分类用于处理包括文件、控制台等各种输入输出设备,各种函数以“流”的方式实现如:打开文件fopen格式化输入与输出函数格式输出fprintf格式输入fscanf格式输出(控制台)printf

格式输入(控制台)scanf宏定义

在C语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。宏定义的一般形式为:

#define标识符字符串“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、或含有参数的表达式、格式串等。在程序中多次使用宏,可以简化源程序的输入。与使用函数相比,会占用较多内存,但执行速度快。例如:

#defineM(y*y+3*y)文件包含命令

文件包含是C预处理程序的另一个重要功能。文件包含是用指定文件的全部内容替换该预处理命令行。即一个程序文件将另一个指定文件的内容完全包含进来。在程序设计中,文件包含是很有用的。一个大的程序可以分为多个模块,由多个程序员分别编程。有些公用的符号常量或宏定义等可单独组成一个文件,在其它文件的开头用包含命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量,从而节省时间,并减少出错。

#include"文件名"

或: #include<文件名>

。文件包含的对象最为常见的是头文件(扩展名.h)。在前面我们已多次用此命令包含过库函数的头文件。文件包含命令行的一般形式为:二、C51的标识符、常量和关键字标识符用来标识源程序中某个对象的名字,这些对象可以是语句、数据类型、函数、变量、数组等。标识符区分大小写,第一个字符必须是字母或下划线。C51中有些库函数的标识符是以下划线开头的,所以一般不要以下划线开头命名标识符。常量:凡以数字0开头的数字序列,一律作为八进制数处理;凡以0x开头,后面跟若干数字的,一律作为十六进制数处理;其它作为十进制数处理。关键字:ANSIC标准关键字和C51编译器的扩展关键字C51扩展的若干关键字一览表

变量名不得使用标准C语言和C51语言的关键字。C51的变量

在程序执行过程中,数值可以发生改变的量称为变量。变量名与存储单元地址相对应,变量值与存储单元的内容相对应。例如在哈佛结构的存储空间中如何建立变量概念?【存储种类】数据类型【存储类型】

变量名(标准C)(标准C)*括号项——可以缺省(但需有缺省值)C51变量定义的四要素:(C51特有)(标准C+C51)【存储种类】

数据类型【存储类型】变量名共有四个说明符:1、auto(自动型)——变量的作用范围在定义它的函数体或语句块内。执行结束后,变量所占内存即被释放。2、extern(外部型)——在一个源文件中被定义为外部型的变量,在其它源文件中需要通过extern说明方可使用。3、static(静态型)——利用static可使变量定义所在的函数或语句块执行结束后,其分配的内存单元继续保留。4、register(寄存器型)——将变量对应的储存单元指定为通用寄存器,以提高程序运行速度。缺省存储种类为auto(自动)型变量C51中数据声明的格式[类型说明符][修饰符]标识符[=初值]……例:unsignedchar

code

Flag=0x0f;类型说明符修饰符标识符初值这个定义给出的内容是:定义一个无符号的字符型变量,该变量的名字是Flag,初值为0x0f,该变量存放在ROM空间中。说明:如果在一个定义中,没有修饰符,即没有说明存放的位置,则默认存放在片内RAM中,即是一个data类型的变量。例如:unsignedcharcodeFlag=0x0f;就是声明一个无符号的char型变量Flag,并给他赋初值为0x0f;并且声明他所在的存储空间在片内统一编址的ROM中。声明中,如果没有修饰符,则数据默认的存储空间为data型,也就是在片内RAM中。C51的数据声明的一般格式如下[类型说明符][修饰符]标识符[=初值]……C51的数据类型数据的不同格式叫做数据类型*有符号数类型可以忽略signed标识符标准C语言的数据类型【存储种类】

数据类型

【存储类型】变量名成于大气信达天下C51中的数据类型类型符号关键字所占位数数据表示范围整型有(signed)int16-32768——32767(signed)shortint16-32768——32767(signed)longint32-2147483648~2147483647无unsignedint160——65535unsignedshortint160——65535unsignedlongint320——4294967295实型有float32-3.4e-38——3.4e+38有double32-1.7e-308——1.7e+308字符型有char8-128——127无unsignedchar80——255C语言中的数据类型类型符号关键字所占位数数据表示范围整型有(signed)int16-32768——32767(signed)shortint16-32768——32767(signed)longint32-2147483648~2147483647无unsignedint160——65535unsignedshortint160——65535unsignedlongint320——4294967295实型有float32-3.4e-38——3.4e+38有double32-1.7e-308——1.7e+308字符型有char8-128——127无unsignedchar80——255从上面两个表可以看出,C51中的数据类型和C语言中的数据类型完全一样。C51扩充数据类型:bit、sfr或sfr16、sbitbit型关键词bit用于定义一个位变量,语法规则:bitbit_name

[=0或1];例如:bitdoor=0;//定义一个叫door的位变量且初值为0标准C的变量定义举例:

inta=5; //定义一个初值为5的整形变量a

语法规则:intint_name[=常数];

注意:上述变量的物理地址是由编译器分配的sfr或sfr16型关键词sfr或sfr16用于定义SFR字节地址变量,语法规则:

sfr

sfr16sfr_name=字节地址常数;51MCU中有21个SFR,如何定义与这些单元相关的变量?例如,sfrP0=0x80;//定义P0口地址80H

sfrPCON=0x87;//定义PCON地址87H

sfr16DPTR=0x82;//定义DPTR的低端地址82H注意:SFR字节地址变量的物理地址是由MCU资源决定的sbit型部分SFR具有位地址,如何定义与这些位地址相关的变量?CYACF0RS1RS0OVF1PCYACF0RS1RS0OVF1PCYACF0RS1RS0OVF1PCYACF0RS1RS0OVF1PD0^7

D7HD6HD5HD4HD3HD2HD1HD0HD0HPSWD0^6

D0^5

D0^4

D0^3

D0^2

D0^1

D0^0

绝对位地址相对位地址字节地址两种位地址表达形式:绝对位地址、相对位地址1)将SFR的绝对位地址定义为位变量名

sbit

bit_name=位地址常数;例如,sbitCY=0xD7;3)将SFR的相对位位置定义位变量名sbitbit_name=sfr_name^位位置;例如,sbitCY=PSW^7;2)将SFR的相对位地址定义为位变量名

sbit

bit_name=sfr字节地址

^位位置;例如,sbitCY=0xD0^7;关键词sbit用于定义SFR位地址变量,三种定义形式:C51编译器在头文件“REG51.H”中定义了全部sfr/sfr16和sbit变量。用一条预处理命令#include<REG51.H>把这个头文件包含到C51程序中,无需重新定义即可直接使用它们的名称。应用举例:表1C51数据类型、长度和数值范围数据类型表示方法长度数值范围无符号字符型unsignedchar1字节0~255有符号字符型signedchar1字节-128~127无符号整型unsignedint2字节0~65535有符号整型signedint2字节-32768~32767无符号长整型unsignedlong4字节0~4294967295有符号长整型signedlong4字节-2147483648~2147483647浮点型float4字节±1.1755E-38~±3.40E+38特殊功能寄存器型sfrsfr161字节2字节0~2550~65535位类型bit、sbit1位0或1C-51的数据类型扩充定义例:sfrP1=0x90; sfr16T2=0xCC;sbitOV=PSW^2;

sbitP10=0x90^0;或sbitP10=P1^0;类型关键字所占位数数的表示范围特殊功能寄存器声明sfr1B(8bit)0~25516位特殊功能寄存器声明sfr162B(16bit)0~65535位变量数据声明bit1bit0或1可寻址位(特殊功能位)声明sbit1bit0或1对C51编译器来说,short和int是相同类型,double和float是同一类型;低地址存高字节,高地址存低字节;有符号数符号位在最低字节的最高位;C-51的数据类型扩充定义类型关键字所占位数数的表示范围特殊功能寄存器声明sfr1B(16bit)0~25516位特殊功能寄存器声明sfr162B(32bit)0~65535位变量数据声明bit1bit0或1可寻址位(特殊功能位)声明sbit1bit0或1sbit是对应可位寻址空间的一个位,可位寻址区20H~2FH或者特殊功能寄存器区0x80~0xFF。一旦用了sbitxxx=REGE^6的定义,这个sbit量就确定地址了。bit和sbit的最大区别在于,bit是定义一个变量;sbit经常用在寄存器中的,方便对寄存器的某位进行操作。sbit是对应可位寻址空间的一个位,可位寻址区20H~2FH或者特殊功能寄存器区0x80~0xFF。一旦用了sbitxxx=REGE^6的定义,这个sbit量就确定地址了。bit和sbit的最大区别在于,bit是定义一个变量;sbit经常用在寄存器中的,方便对寄存器的某位进行操作。例如:bitbit_name;//只是申明bit_name是一个位变量名,它只能是1或者0bitdoor=0;//申明door是一个位变量,并赋初值0。

这与charabc申明abc是一个char型变量类似。bit定义了一个普通的位变量,函数可包含bit类型参数,也可作为返回值。存储在哪儿我们并不关心。但是:sbitCY=0xD0^7;//将位的相对地址赋给变量。sbit定义的位变量只能位于可位寻址或特殊功能寄存器中,一旦定义,其地址就不能改变啦。36用sfr16定义16位特殊功能寄存器当16位寄存器的高8位地址紧排在低8位地址之后时,就可以定义一个16位特殊功能寄存器变量。定义格式为: sfr16

特殊功能寄存器名=16位特殊功能寄存器中低8位的地址例如: sfr16DPTR=0x82;/*指定DPTR寄存器地址为0x82,其中DPL的地址为0x82,DPH的地址为0x83*/注意:这种定义适用于所有新的16位SFR,但不能用于定时/计数器T0和定时/计数器T1的定义。数组类型:数组是一组数据,其中的每一个数据元素都属于同一类型,各元素可以用数组名和下标来唯一确定。定义格式类似于数据定义:数据类型数组名[常量表达式]多维数组的定义:数据类型数组名[常量表达式][常量表达式]

例:intxdataxx[15];charcodestr[]={“Howareyou?”};用户RAM区用户扩展RAM64K位寻址区4组通用寄存区特殊功能寄存器区7FH30H2FH20H1FH00HFFH80H高128字节区低128字节区FFFFH1000H0FFFH0000H内部ROM外部ROMEA=0只对外部ROM寻址范围为64KBEA=1先对内部ROM4K范围寻址超过0FFFH时自动寻找外部0000HFFFFH内部RAM外部RAM80C51存储器结构组成【存储种类】

数据类型【存储类型】变量名51单片机的三个逻辑存储空间:片内数据存储器,片外数据存储器和程序存储器。建立C51存储类型与存储空间的对应关系data区code区xdata区bdata区pdata区idata区C51的存储类型与存储空间对应关系表

SMALL系统COMPACT系统LARGE系统编译模式三种编译模式分别对应于三种缺省存储类型:【存储种类】

数据类型【存储类型】变量名C51编译器可根据当前采取的编译模式自动认定默认的存储类型约定:若无特殊声明,一般均为“SMALL编译模式”[例]变量的存储模式

#pragmasmall/*变量的存储模式为Small*/chark1;/*k1存储模式Small,存储器类型默认data*/intxdatam1;/*m1存储模式为Small,存储器类型xdata*/#pragmacompact/*变量的存储模式为Compact*/chark2;/*k2存储模式Compact,k2存储器类型默认pdata*/intxdatam2;/*m2存储模式Compact,存储器类型xdata*/intfunc1(intx1,inty1)large/*函数Large,x1和y1存储器类型xdata*/{return(x1+y1);}intfunc2(intx2,inty2)/*函数默认Small,x2和y2存储器类型data*/{return(x2-y2);}4.1.4变量的存储种类(属性)变量是一种在程序执行过程中,其数值不断变化的量。同ANSIC一样,C51规定变量必须先定义后使用。C51对变量的进行定义的格式如下:[存储种类]数据类型[存储器类型]变量名表其中,存储种类(属性)和存储器类型是可选项。存储种类是指变量在程序执行过程中的作用范围。变量的存储种类有四种,分别为:自动(auto)——默认值,变量为函数内有效。外部(extern)——变量对所有函数有效。静态(static)寄存器(register)——编译系统自动生成。存储种类是指变量在程序执行过程中的作用范围。C51变量的存储种类有四种,分别是自动(auto)、外部(extern)、静态(static)和寄存器(register)。(1).auto:

使用auto定义的变量称为自动变量,其作用范围在定义它的函数体或复合语句内部,当定义它的函数体或复合语句执行时,C51才为该变量分配内存空间,结束时占用的内存空间释放。自动变量一般分配在内存的堆栈空间中。定义变量时,如果省略存储种类,则该变量默认为自动(auto)变量。(2).extern:使用extern定义的变量称为外部变量。在一个函数体内,要使用一个已在该函数体外或别的程序中定义过的外部变量时,该变量在该函数体内要用extern说明。外部变量被定义后分配固定的内存空间,在程序整个执行时间内都有效,直到程序结束才释放。(3).static:使用static定义的变量称为静态变量。它又分为内部静态变量和外部静态变量。在函数体内部定义的静态变量为内部静态变量,它在对应的函数体内有效,一直存在,但在函数体外不可见,这样不仅使变量在定义它的函数体外被保护,还可以实现当离开函数时值不被改变。外部静态变量上在函数外部定义的静态变量。它在程序中一直存在,但在定义的范围之外是不可见的。如在多文件或多模块处理中,外部静态变量只在文件内部或模块内部有效。外部变量与全局静态变量的区别:(a)若程序由一个源文件构成时,全局变量与全局静态变量没有区别。(b)若程序由多个源文件构成时:全局静态变量为定义该变量的源文件所独享,对组成该程序的其它源文件是无效。(c)具有外部链接的静态;可以在所有源文件里调用;除了本文件,其他文件可以通过extern的方式引用;静态全局变量的作用:(a)不必担心其它源文件使用相同变量名,彼此相互独立。(b)在某源文件中定义的静态全局变量不能被其他源文件使用或修改。(c)只能在本文件中使用!具有内部链接的静态;不允许在其他文件里调用;static全局变量与普通的全局变量有什么区别?答:1)全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。2)从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。3)static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件综上所述:static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;

static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝(4).register:

使用register定义的变量称为寄存器变量。它定义的变量存放在CPU内部的寄存器中,处理速度快,但数目少。C51编译器编译时能自动识别程序中使用频率最高的变量,并自动将其作为寄存器变量,用户可以无需专门声明。C-51数据的存储类型三类存储器:——对应的存储器类型说明(1)程序存储器——code(2)片内数据存储器——bdata(位)、data(直接寻址128B)、idata(间接寻址256B)(3)片外数据存储器——pdata(分页寻址256B)、xdata(片外64KB)片内数据存储器分:(1)直接寻址区

(2)

间接寻址区[存储种类]数据类型[存储器类型]变量名表存储器类型长度数据范围存储空间位置描述data8位0~255直接寻址片内数据存储器低128B,访问速度最快bdata1位0/1可位寻址的片内数据存储器(地址20H~2FH共16B)允许位和字节混合访问idata8位0~255间接寻址片内数据存储器256B。允许访问片内全部地址,速度较快pdata片外8位0~255用Ri访问片外数据存储器256B,使用指令MOVX@Rn访问,需要2个指令周期速度较慢xdata片外16位0~65535用DPTR访问片外数据存储器64KB,使用指令MOVX@DPTR访问,速度最慢code16位0~65535寻址程序存储器区64KB,使用指令MOVC@A+DPTR访问例如MOVXA,@DPTR //xdata把数据指针DPTR中存的数作为地址,将该地址中的数(对应片外的64KB存储器中的某个数)送入累加器A中【例】变量定义存储种类和存储器类型相关情况。

chardatavarl;

/*在片内RAM低128B定义用直接寻址方式访问的字符型变量var1*/

intidatavar2;

/*在片内RAM256B定义用间接寻址方式访问的整型变量var2*/

autounsignedlongdatavar3;

/*在片内RAM128B定义用直接寻址方式访问的自动无符号长整型变量var3*/

externfloatxdatavar4;

/*在片外RAM64KB空间定义用间接寻址方式访问的外部实型变量var4*/

intcodevar5;

/*在ROM空间定义整型变量var5*/

unsigncharbdatavar6;

/*在片内RAM位寻址区20H~2FH单元定义可字节处理和位处理的无符号字符型变量var6*/直接寻址方式:(片内直接寻址data)例如:MOVA,30H;

其中,30H(无#号),是内存的一个单元地址。功能:把30H地址单元中的内容送累加器A。设30H单元中存放着一个数FFH,程序执行结果A=FFH。注意:直接地址只能表示专用寄存器、内部存储器及位地址空间间接寻址方式:(片内或片外间接寻址idata,pdata)例如MOV(或者MOVX)A,@R1

把工作寄存器R1中数作为地址,将该地址(对应片内或片外的256B存储器)中的数送入累加器A中。一个变量的存储器模式确定了未声明存储器类型的变量在内存中的地址空间。在SMALL模式下,该变量在80C51单片机的内部RAM中;在COMPACT和LARGE模式下,该变量在80C51单片机的外部RAM中。建议在编写源程序时,把存储模式设定为SMALL(默认,即对存储模式不作声明),再在程序中把xdata、pdata和idata等类型变量进行专门声明。C51编译器允许采用三种存储模式:小编译模式SMALL、紧凑编译模式COMPACT、大编译模式LARGE。C-51数据的存储模式存储器模式存储模式是指函数自变量、自动变量和没有明确规定存储类型的变量的默认存储器类型。通过在命令行中增加控制命令可以指定他们的存储器类型。主要三种模式:COMPACTdataLARGESMALLxdatapdata在程序中变量的存储模式的指定通过#pragma预处理命令来实现。函数的存储模式可通过在函数定义时后面带存储模式说明。如果没有指定,则系统都隐含为SMALL模式。【例】变量的存储模式。#pragmasmall/*变量的存储模式为SMALL*/chark1;intxdatam1;#pragmacompact/*变量的存储模式为compact*/chark2;intxdatam2;intfunc1(intx1,inty1)large/*函数的存储模式为LARGE*/{return(x1+y1);}intfunc2(intx2,inty2)/*函数的存储模式隐含为SMALL*/{return(x2-y2);}

程序编译时,k1变量存储器类型为data,k2变量存储器类型为pdata,而m1和m2由于定义时带了存储器类型xdata,因而它们为xdata型;函数func1的形参x1和y1的存储器类型为xdata型,而函数func2由于没有指明存储模式,隐含为SMALL模式,形参x2和y2的存储器类型为data。成于大气信达天下C51的基本语句与标准C语言基本相同:

if

选择语言

switch/case

多分支选择语言

while

循环语言

do-while

循环语言

for

循环语言指针类型:在C语言中为了能够实现直接对内存单元进行操作,引入了指针类型的数据。指针是专门用来确定其它数据类型的地址的。因此,一个变量的地址被称为该变量的指针。指针变量的定义格式为:数据类型[存储器类型]*标识符例如:“&a”为变量a的地址;“*p”为指针变量所指向的变量。其中,“标识符”为所定义的指针变量名;“数据类型”说明该指针变量所指向的变量的类型。指针变量的引用:指针有关的运算符有两个:地址运算符“&”和间接访问运算符“*”。用typedef重新定义数据类型的名称在C语言中为了简化输入,可以根据自己的需要,对前面介绍的数据类型重新定义。格式为:例如:typedefunsingedcharuchar ;即在之后的程序中都可以用uchar代表unsingedchar。

typedefunsingedlongulong ;即在之后的程序中都可以用ulong代表unsingedlongtypedef已有数据类型新的数据类型对data区的寻址是最快的,所以应该把使用频率高的变量放在data区,由于空间有限,必须注意使用data区,data区除了包含程序变量外,还包含了堆栈和寄存器组data区。在SMALL存储模式下,未说明存储器类型时,变量默认被定位在data区。如果在变量定义时省略了存储器类型标识符,C51编译器会选择默认的存储器类型。默认的存储器类型由SMALL、COMPACT和LARGE存储模式指令决定。1)data区当在DATA区的位寻址区定义变量,这个变量就可进行位寻址,并且声明位变量。这对状态寄存器来说十分有用,因为它可以单独使用变量的每一位,而不一定要用位变量名引用位变量。idata区也可以存放使用比较频繁的变量,使用寄存器作为指针进行寻址。在寄存器中设置8位地址进行间接寻址,与外部存储器寻址比较,它的指令执行周期和代码长度都比较短。2)bdata区3)idata区在这两个区声明变量和在其他区的语法是一样的,pdata区只有256B,而xdata区可达65536Bcode区即80C51的程序代码区,所以代码区的数据是不可改变的,80C51的代码区不可重写。一般代码区中可存放数据表,跳转向量和状态表4)pdata和xdata区5)code区存储器模式声明形式:voidfun(void)small{}SMALL所有变量都默认的位于51内部数据存储器,这和使用data指定存储器类型的方式一样COMPACT所有变量都呗默认为在外部数据存储器的页内,这和使用pdata指定存储器类型是一样的。LARGE所有变量都默认为位于外部数据存储器,与使用xdata指定存储器类型是一样的例:数据类型存储类型变量chardatavar1;bitdataflags;unsignedcharxdatavextor[10];4.1.6.使用C51扩展关键字_at_

使用_at_对指定的存储器空间的绝对地址进行访问,一般格式如下:

[存储器类型]数据类型说明符变量名_at_地址常数;其中,存储器类型为data、bdata、idata、pdata等C51能识别的数据类型,如省略则按存储模式规定的默认存储器类型确定变量的存储器区域;数据类型为C51支持的数据类型。地址常数用于指定变量的绝对地址,必须位于有效的存储器空间之内;使用_at_定义的变量必须为全局变量。【例】通过_at_实现绝对地址的访问。#defineucharunsignedchar/*定义符号uchar为数据类型符unsignedchar*/#defineuintunsignedint/*定义符号uint为数据类型符unsignedint*/voidmain(void){dataucharx1_at_0x40;/*在data区中定义字节变量

x1,它的地址为40H*/xdatauintx2_at_0x2000;/*在xdata区中定义字变量

x2,它的地址为2000H*/x1=0xff;x2=0x1234;......while(1);}运算符就是完成某种特定运算的符号。C51的数据运算操作与标准C语言基本相同,具有十分丰富的运算符,对数据有很强的表达能力:运算符按其表达式中与运算符的关系(含有运算符的数量)可分为单目运算符、双目运算符和三目运算符。三、C51的运算符和表达式1、C-51的运算符成于大气信达天下C51中的运算符与C语言基本相同:+,-,*,/

,%

(加减乘除求余)>,>=,<,<=

(大于大于等于小于小于 等于)==,!=

(测试等于测试不等于)&&,||,!

(逻辑与逻辑或逻辑非)>><<

(位右移位左移)&,|

(按位与按位或)^,~

(按位异或按位取反)算术运算符运算符范例说明+A+b加或取正值运算符-A-b减或取负值运算符*A*b乘运算符/A/b除运算符%A%b模(取余)运算符,如8%5=3++A++等同于A=A+1--A--等同于A=A-1赋值运算符使用“=”的赋值语句格式如下:注意“==”与“=”两个运算符和赋值运算符“=”结合后使用的区别。变量=表达式;注意“==”与“=”两个运算符和赋值运算符“=”结合后使用的区别。例1:

a=1; b=++a;其运算过程是a加1变为2,然后赋值给b,即:b=2,a=2。例2:

a=1; b=a++;其运算过程是赋值给b,然后a加1变为2,即:b=1,a=2。关系运算符C51中有6种关系运算符:>大于<小于>=大于等于<=小于等于==测试等于!=测试不等于关系表达式的值是真”和“假”,用“1”和“0”表示。逻辑运算符逻辑与:条件式1&&

条件式2。逻辑或:条件式1||

条件式2。逻辑非:!条件式。位运算符C51中共有6种位运算符:&按位与|按位或^按位异或~按位取反<<左移>>右移复合运算符就是在赋值运算符“=”的前面加上其他运算符。运算符范例说明+=加法赋值 A+=b等同于A=A+b-=减法赋值 *=乘法赋值 /=除法赋值 %=取模赋值<<=左移位赋值>>=右移位赋值&=逻辑与赋值|=逻辑或赋值^=逻辑异或赋值~=逻辑非赋值【例】如何点亮发光二极管(本程序的功能是:让奇数个发光二极管一亮一灭不停的在闪烁)#include<AT89X52.H>#defineuintunsignedint#defineucharunsignedcharsbitD1=P1^0;sbitD3=P1^2;sbitD5=P1^4;sbitD7=P1^6;voiddelay();voidmain(){ while(1) { D1=0; D3=0; D5=0; D7=0; delay(10); D1=1; D3=1; D5=1; D7=1; delay(10); }}voiddelay(){ uintx,y; for(x=10;x>0;x--) for(y=2000;y>0;y--);}C51中绝对地址的访问

C51中绝对地址的访问有三种方法:使用C51运行库中预定义宏,通过指针访问,使用C51扩展关键字_at_。1.使用C51运行库中预定义宏

C51编译器提供了一组宏定义来对MCS-51单片机的地址空间进行绝对寻址。规定只能以无符号数方式访问。在包含头文件absacc.h的前提下,可以使用预处理命令#define指令定义不同存储空间各个变量的绝对地址。形式为:

#include<absacc.h>访问形式:预定义宏名[地址]函数原型定义:

#define宏名((数据类型volatile*)0x存储单元的绝对地址)预定义宏名:

CBYTE——code区(字节)

DBYTE——data区(字节)

PBYTE——pdata区(字节)

XBYTE——xdata区(字节)

CWORD——code区(字)

DWORD——data区(字)

PWORD——pdata区(字)

XWORD——xdata区(字)

预定义宏名表示绝对地址所处的存储空间和数据长度。[例]绝对地址对存储单元的访问

#include<absacc.h>/*将绝对地址头文件包含在文件中*/#include<reg52.h>/*将寄存器头文件包含在文件中*/#defineucharunsignedchar/*定义符号uchar为数据类型符unsignedchar*/#defineuintunsignedint/*定义符号uint为数据类型符unsignedint*/voidmain(void){ucharvar1;uintvar2;var1=XBYTE[0x0005];/*访问片外RAM的0005字节单元*/var2=XWORD[0x0002];/*访问片外RAM的0002字单元*/......while(1);}2.使用指针采用指针的方法,可实现在C51程序中对任意指定的存储器地址进行操作。ucharidataivar1;ucharxdata*xdp;/*定义一个指向xdata存储器空间的指针*/chardata*dp;/*定义一个指向DATA存储器空间的指针*/ucharidata*idp;/*定义一个指向idata存储器空间的指针*/xdp=0x1000;/*xdata指针赋值,指向xdata存储器地址1000H处*/*xdp=0x5A;/*将数据5AH送到xdata的1000H单元*/dp=0x61; /*DATA指针赋值,指向DATA存储器地址61H处*/*dp=0x23; /*将数据23H送到DATA的61H单元*/idp=&ivar1; /*idp指向idata区变量ivar1*/*idp=0x16; /*等价于ivar1=0x16*/指针与地址运算符:

*(指针运算符),&(取地址运算符)

功能:

“*”放在指针变量前面,实现访问以指针变量的内容为地址所指向的存储单元。例如:指针变量p中的地址为2000H,则*p所访问的是地址为2000H的存储单元,x=*p,实现把地址为2000H的存储单元的内容送给变量x。“&”放在变量的前面,通过它取得变量的地址,变量的地址通常送给指针变量。例如:设变量x的内容为12H,地址为2000H,则&x的值为2000H,如有一指针变量p,则通常用p=&x,实现将x变量的地址送给指针变量p,指针变量p指向变量x,以后可以通过*p访问变量x。3.使用C51扩展关键字_at_使用_at_对指定的存储器空间的绝对地址进行定位,一般格式如下:

[存储器类型]数据类型标识符_at_常数ucharxdataxram[0x8000]_at_0x0000;/*在外部RAM空间0000H处定义了一个一维数组变量xram,数组的元素个数为32768(0x8000)*/例如使用_at_定义的变量只能为全局变量。使用C51扩展关键字_at_

使用_at_对指定的存储器空间对地址进行访问,一般格式如下:

[存储器类型]数据类型说明符变量名_at_地址常数;

其中,存储器类型为等C51能识别的数据类型,如省略则按存储器规定的默认存储器类型确定变量的存储区域;数据类型为C51支持的数据类型;

地址常数用于指定变量的绝对地址,必须位于有效的存储空间之内;使用_at_定义的变量必须为全局变量【例】通过_at_实现绝对地址的访问。

#defineucharunsingedchar//定义符号uchar为数据类型符unsignedchar

#defineuintunsignedint//定义符号uint为数据类型符unsignedint

voidmain(void){

dataucharx1_at_0x40;//在data区中定义字节变量,它的地址为40H

xdatauintx2_at_0x2000;//在xdata区中定义字变量,它的地址为2000H

x1=0xff;

x2=0x1234;

……

while(1);

}与一般C语言的结构相同,以main()函数为程序人口,程序体中包含若干语句还可以包含若干函数。C-51函数的一般格式

类型函数名(参数表)

{

数据说明部分语句执行部分

}§4-4C51程序设计及应用4.4.1C51的程序结构C语言的结构化特征非常明显:C语言源程序总是由若干个函数组成,以main()函数为程序入口,程序体中包含若干语句还可以包含若干函数调用。C语言中的函数很多可以重复利用,形成了函数库,程序员只需按照要求调用,极大地节省了开发者的时间和精力,大大降低了出错几率。§4-4C51程序设计及应用4.4.1C51的程序结构从程序控制语句以及函数的使用上来讲,C51与标准C几乎没有什么明显的区别。只是在函数的使用上,由于单片机系统的资源有限,它的编译系统不允许太多的程序嵌套。在前面已多次使用过以“#”号开头的预处理命令。如包含命令#include,宏定义命令#define等。凡是以“#”开头的均为预处理命令。在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为预处理部分。

所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。本章介绍常用的几种预处理功能。4.4.2文件预处理与头文件一、宏定义

在C语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。宏定义的一般形式为:

#define标识符字符串“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、或含有参数的表达式、格式串等。在程序中多次使用宏,可以简化源程序的输入。与使用函数相比,会占用较多内存,但执行速度快。例如:

#defineM(y*y+3*y)二、文件包含命令

文件包含是C预处理程序的另一个重要功能。文件包含是用指定文件的全部内容替换该预处理命令行。即一个程序文件将另一个指定文件的内容完全包含进来。在程序设计中,文件包含是很有用的。一个大的程序可以分为多个模块,由多个程序员分别编程。有些公用的符号常量或宏定义等可单独组成一个文件,在其它文件的开头用包含命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量,从而节省时间,并减少出错。

#include"文件名"

或: #include<文件名>

。文件包含的对象最为常见的是头文件(扩展名.h)。在前面我们已多次用此命令包含过库函数的头文件。文件包含命令行的一般形式为:C系统提供了丰富的系统文件,称为库文件。C51的强大功能及其高效率的重要体现之一在于,其提供了丰富的可直接调用的库函数。使用库函数使程序代码简单、结构清晰、易于调试和维护,

C的库文件分为两类,一类是扩展名为“.h”的文件,称为头文件,在前面的包含命令中我们已多次使用过。在“.h”文件中包含了常量定义、类型定义、宏定义、函数原型以及各种编译选择设置等信息。另一类是函数库,包括了各种函数的目标代码,供用户在程序中调用。为了使用51单片机的内部资源,如定时器、中断、I/O等,需要将说明相应的功能寄存器的头文件加载在程序中。如前面所使用的reg51.h等。因此,C51系列头文件集中体现了各系列芯片的不同功能。通常在程序中调用一个库函数时,要在调用之前包含该函数原型所在的".h"文件。部分库函数不适合单片机处理系统,因此被排除在外,如字符屏幕和图形函数。部分库函数的定义与标准C有很大不同,如printf和scanf函数,在C51中用于串口数据的发送和接收。C51与标准ANSIC库函数的不同:reg51.h,reg52.h——定义特殊功能寄存器和位寄存器;math.h——数学函数。本分类给出了各种数学计算函数stdio.h——输入输出函数。该分类用于处理包括文件、控制台等各种输入输出设备,各种函数以“流”的方式实现intrins.h——内部函数ctype.h——字符处理函数。本类别函数用于对单个字符进行处理,包括字符的类别测试和字符的大小写转换stdlib.h——实用工具函数。string.h——字符串处理。本分类的函数用于对字符串进行合并、比较等操作;absacc.h——绝对地址访问函数。C51常用库函数:93使用头文件,再直接用位名称 #include<STC12C5A.h> TR0=1;EA=1;TF0=0;//在文件中已定义了TR0、EA、 TF0……等位使用头文件及sbit定义符,用于无位名称的可位寻址位。 #include<STC12C5A.h> sbit P1_0=P1^0; sbit a_7=ACC^7;

由于在51内核单片机产品中特殊功能寄存器的数量和类型不尽相同,C51建立了一个头文件reg51.h(增强型为reg52.h),STC系列单片机的头文件有STC90.h、STC10.h、STC11.h、STC12C5A.h、STC12C52.h、STC12C54.h、STC12C56.h、STC15.h、STC89.h等。94 在这些头文件中对相应系列的所有特殊功能寄存器进行了sfr定义,对特殊功能寄存器中有位名称并且可位寻址位进行了sbit定义,只要使用了#include<STC12C5A.h>或#include<reg52.h>等包含语句,就可以直接引用该文件中已经定义过的特殊功能寄存器名及位名称。注意:在引用特殊功能寄存器名及位名称时必须大写。我们也可以用自己喜欢的名字写定义文件,使用时只要用包含语句#include“****.h”就可以直接引用已定义的特殊功能寄存器名和位名称。四、C-51的基本语句与标准C语言基本相同:if选择语言switch/case

多分支选择语言while

循环语言

do-while

循环语言for

循环语言1)第一种形式为基本形式:if

if(表达式)语句其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句。其过程可表示为下图。1、if语句的三种形式2)第二种形式为:if-elseif(表达式)

语句1;

else

语句2;其语义是:如果表达式的值为真,则执行语句1,否则执行语句2。例如:if(x>y){max=x;}else{max=y;}

本形式相当于双分支选择结构。3.当有多个分支选择时,可采用if-else-if语句,其一般形式为:if(表达式1)

语句1;

elseif(表达式2)

语句2;

elseif(表达式3)

语句3;

elseif(表达式m)

语句m;

else

语句n;其语义是:依次判断表达式的值,当出现某个值为真时,则执行其对应的语句。然后跳到整个if语句之外继续执行程序。如果所有的表达式均为假,则执行语句n。然后继续执行后续程序。【例5.5】例如:if(x>100){y=1;}elseif(x>50){y=2;}elseif(x>30){y=3;}elseif(x>20){y=4;}else{y=5;}99【例5.5】二、switch语句C语言还提供了另一种用于多分支选择的switch语句,其一般形式为:

switch(表达式){case常量表达式1:语句1;case常量表达式2:语句2;…case常量表达式n:语句n;default:语句n+1;}其语义是:计算表达式的值。并逐个与其后的常量表达式值相比较,当表达式的值与某个常量表达式的值相等时,即执行其后的语句,然后不再进行判断,继续执行后面所有case后的语句。如表达式的值与所有case后的常量表达式均不相同时,则执行default后的语句。例如:……switch(keynum){ case1: key1();break; //如果keynum为1,则执行函数key1() case2: key2();break; //如果keynum为2,则执行函数key2() case3: key3();break; //如果keynum为3,则执行函数key3() case4: key4();break; //如果keynum为4,则执行函数key4()

……

default:gotoinput}while语句的一般形式为:

while(表达式)语句其中表达式是循环条件,语句为循环体。

while语句的语义是:计算表达式的值,当值为真(非0)时,执行循环体语句。其执行过程可用下图表示。三、while语句 例如:

while((P1&0x80)==0){}do-while语句的一般形式为:

do

语句

while(表达式);这个循环与while循环的不同在于:它先执行循环中的语句,然后再判断表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while循环至少要执行一次循环语句。其执行过程可用下图表示。四、do-while语句

例:

do { sum+=sample[n];

n++;

}while(n<10);在C语言中,for语句使用最为灵活,它完全可以取代while语句。它的一般形式为:

for(表达式1;表达式2;表达式3)语句它的执行过程如下:先求解表达式1。求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面第3)步;若其值为假(0),则结束循环,转到第5)步。求解表达式3。转回上面第2)步继续执行。循环结束,执行for语句下面的一个语句。其执行过程可用下图表示。五、for语句for语句最简单的应用形式也是最容易理解的形式如下:for(循环变量赋初值;循环

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论