第三章单片机程序设计(C51程序设计)_第1页
第三章单片机程序设计(C51程序设计)_第2页
第三章单片机程序设计(C51程序设计)_第3页
第三章单片机程序设计(C51程序设计)_第4页
第三章单片机程序设计(C51程序设计)_第5页
已阅读5页,还剩144页未读 继续免费阅读

下载本文档

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

文档简介

**1单片机原理与接口技术上海大学第三章MCS-51单片机

C51程序设计**2熟悉C51语法基础和程序结构;掌握C51结构化程序设计;掌握C51对单片机硬件的访问方法;掌握C51函数定义与调用;了解汇编语言和C51的混和编程。本章教学要求第3章MCS-51单片机C51程序设计**33.1C51概述3.2C51语法基础3.2.1标识符和关键字3.2.2数据类型3.2.3运算符和表达式3.2.4程序结构第3章MCS-51单片机C51程序设计本章目录3.3C51对MCS-51单片机的存储器访问3.3.1存储类型3.3.2存储模式3.3.3对特殊功能寄存器的访问3.3.4对存储器和并行口的访问3.3.5位地址访问**43.4C51函数3.4.1函数的分类3.4.2函数的定义3.4.3函数的调用3.4.4对被调函数的说明3.4.5中断函数3.5C51结构化程序设计3.5.1顺序结构程序3.5.2选择结构程序第3章MCS-51单片机C51程序设计本章目录3.5.3循环结构程序3.5.4查表程序3.6C51程序设计实例3.6.1单片机内/外部资源应用程序设计3.6.2C51语言和MCS-51汇编语言混合编程3.6.3编程优化的概念习题与思考题**53.1C51概述C语言是一种通用的程序设计语言,其代码率高,数据类型及运算符丰富,位操作能力强,适用于各种应用的程序设计。使用C语言进行单片机应用系统开发,具有编程灵活、调试方便、目标代码编译效率高的特点。C语言也是目前使用最广的单片机应用系统编程语言。由C语言编程的单片机应用程序,称为单片机C语言程序。MCS-51系列单片机开发系统的编译软件可以对51单片机C语言源程序进行编译,称为C51编译器。在C51编译软件中可进行51单片机C语言程序的调试。------C51编译器**61)扩展了专门访问MCS-51单片机硬件的数据类型;2)存储类型按MCS-51单片机存储空间分类;3)存储模式遵循存储空间选定编译器模式;4)指针分为通用指针和存储器指针;5)函数增加了中断函数和再入函数。3.1C51概述

------C51特点C51编译器针对MCS-51单片机硬件在下列几方面对ANSIC进行了扩展。**7使用具有C51编译扩展功能的C语言进行MCS-51单片机应用系统的开发编程,简称C51编程。C51编程具有以下特点。1)可管理内部寄存器和存储器的分配,编程时,无需考虑不同存储器的寻址和数据类型等细节问题;2)程序由若干函数组成,具有良好的模块化结构、可移植性好、便于项目维护管理;3)有丰富的子程序库可直接引用,从而大大减少用户编程工作量,提高编程效率;4)与汇编语言交叉编程。用汇编语言编写与硬件有关的程序,用C51编写与硬件无关的运算程序,充分发挥两种语言的长处,提高开发效率。3.1C51概述

------C51特点**8C51编程和汇编语言编程过程一样。单片机C语言源程序经过编辑、编译、连接后生成目标程序(.BIN和.HEX)文件,然后运行即可。调试51单片机C语言程序可用KeilC51编译器。注意,使用C51编程可以取代繁琐的汇编语言编程,但仍需要了解MCS-51单片机的硬件结构。所以对于单片机系统的开发应采用汇编语言与C51混合编程的方法更为有效。3.1C51概述------C51特点**93.2C51语法基础

标识符用来标识源程序中某个对象的名字,这些对象可以是语句、数据类型、函数、变量、数组等。标识符由字符串、数字和下划线等组成,应该注意的是第一个字符必须是字母或下划线,不能用数字开头,如“1_a”是错误的,编译时会有错误提示。在C51编译器中,只支持标识符的前32位为有效标识。C51语言是区分大小写的一种高级语言,如“a_1”和“A_1”是两个完全不同的标识符。3.2.1标识符和关键字------标识符**10C51中有些库函数的标识符是以下划线开头的,所以一般不要以下划线开头命名用户自定义标识符。标识符在命名时应当简单,含义清晰,这样有助于阅读理解程序。关键字则是编程语言保留的特殊标识符,它们具有固定的名称和含义,在程序编写中不允许将关键字另做他用。C51中的关键字除了有ANSIC标准的32个关键字外,还根据MCS-51单片机的特点扩展了相关的关键字。C51关键字如表5-1所示。在C51的文本编辑器中编写C程序,系统可以把保留关键字以不同颜色显示,如int关键字的默认颜色为天蓝色。3.2.1标识符和关键字------关键字**113.2.1标识符和关键字------关键字列表**123.2.1标识符和关键字------关键字列表**133.2.1标识符和关键字------关键字列表**143.2.2数据类型

C51具有ANSIC的所有标准数据类型。其基本数据类型包括:char、int、short、long、float和double。

对C51编译器来说,short类型和int类型相同,double类型和float类型相同。-----C51的数据类型**15

除此之外,为了更加有利地利用MCS-51的结构,C51还增加了一些特殊的数据类型,包括bit、sbit、sfr、sfr16。数据类型如表5-2所示。3.2.2数据类型

-----C51的数据类型**16char类型的长度是1B,通常用于定义处理字符数据的变量或常量。

unsignedchar类型用字节中所有的位表示数值,可以表达的数值范围是0~255。

signedchar类型用字节中最高位表示数据的符号,0表示正数,1表示负数,负数用补码表示,能表示的数值范围是-128~+127。unsignedchar常用于处理ASCII字符或用于处理小于或等于255的整型数。1.char字符类型3.2.2数据类型

----char字符类型**172.int整型

int整型长度为2B,用于存放一个双字节数据。

signedint表示的数值范围是-32768~+32767,字节中最高位表示数据的符号,0表示正数,1表示负数。

unsignedint表示的数值范围是0~65535。3.2.2数据类型

-----int整型**18

long长整型长度为4B,用于存放一个四字节数据。分有符号long长整型signedlong和无符号long长整型unsignedlong,默认值为signedlong类型。

signedlong表示的数值范围是-2147483648~+2147483647,字节中最高位表示数据的符号,0表示正数,1表示负数。

unsignedlong表示的数值范围是0~4294967295。3.long长整型3.2.2数据类型

----long长整型**194.float浮点型

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

-----float浮点型**205.*指针型

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

-----*指针型**21bit位标量是C51编译器的一种扩充数据类型,利用它可定义一个位标量。它的值是一个二进制位,不是0,就是1,类似一些高级语言中的boolean型数据的True和False。bit访问MCS-51单片机片内20H~2FH范围内的位对象。C51编译器提供了一个bdata存储器类型,允许将具有bdata类型的对象放入MCS-51单片机片内可位寻址区。6.bit位标量3.2.2数据类型

-----bit位标量**227.sfr特殊功能寄存器

sfr是一种C51扩充数据类型,占用一个内存单元,值域为0~255。利用它可以访问MCS-51单片机内部的所有特殊功能寄存器。如用sfrP1=0x90定义一个特殊功能寄存器变量“P1”,0x90是指51单片机的P1端口地址90H,变量P1即指51单片机的P1端口。在后面的语句中可以用P1=255(对P1端口的所有引脚置高电平)之类的语句操作特殊功能寄存器。3.2.2数据类型

-----sfr特殊功能寄存器**238.sfr1616位特殊功能寄存器

sfr16也是一种C51扩充数据类型,用于定义存在于MCS-51单片机内部RAM的16位特殊功能寄存器,如定时器T0和T1。

sfr16型数据占用2个内存单元,取值范围为0~65535。3.2.2数据类型

-----16位特殊功能寄存器**24

sbit也是一种C51扩充数据类型,利用它可以访问芯片内部RAM中的特殊功能寄存器中的可寻址位。定义方法有如下三种:(1)sbit位变量名=位地址将位的绝对地址赋给位变量,位地址必须位于80H~FFH(特殊功能寄存器的位地址)之间。9.sbit可寻址位3.2.2数据类型

-----sbit可寻址位**25(2)sbit位变量名=特殊功能寄存器名^位位置当可寻址位位于特殊功能寄存器中时,可采用这种方法。位位置是一个0~7之间的常数。(3)sbit位变量名=字节地址^位位置这种方法是以一个常数(字节地址)作为基地址,该常数必须在80H~FFH(特殊功能寄存器的字节地址)之间。位位置是一个0~7之间的常数。9.sbit可寻址位3.2.2数据类型

-----sbit可寻址位**26MCS-51单片机中的特殊功能寄存器及其可寻址位,已被预先定义放在文件reg51.h中,在程序的开头只需加上#include<reg51.h>或#include<reg52.h>即可。

3.2.2数据类型

-----reg51.h**27

sbit和bit的区别:sbit定义特殊功能寄存器中的可寻址位;而bit则定义了一个普通的位变量,一个函数中可包含bit类型的参数,函数返回值也可为bit类型。3.2.2数据类型

-----sbit和bit**283.2.3运算符和表达式C51算术运算符有五种。

+ 加法运算符或正号

- 减法运算符或负号 * 乘法运算符

/ 除法运算符

% 模(求余)运算符优先级:先乘除,后加减,先括号内,再括号外。结合性:自左至右方向。模运算即求余数,如7%3,结果是7除以3所得余数1。1.C51的算术运算符-----算术运算符**29

C51关系运算符有六种。

< 小于

> 大于

<= 小于等于

>= 大于等于

== 相等

!= 不相等优先级:前四个高,后两个“==”和“!=”级别低。结合性:自左至右方向。关系表达式的结果是逻辑值“真”或“假”,C51中以“1”代表真,“0”代表假。2.C51关系运算符3.2.3运算符和表达式------关系运算符**30C51逻辑运算符有三种。

&& 逻辑与

|| 逻辑或

! 逻辑非优先级:逻辑非“!”最高。结合性:“&&”和“||”自左至右方向。“!”自右至左方向。运算符的两边为关系表达式。逻辑表达式和关系表达式的值相同,以“0”代表假,以“1”代表真。3.C51逻辑运算符3.2.3运算符和表达式------逻辑运算符**31C51按位操作运算符有六种。

& 按位与

| 按位或

^ 按位异或

~ 位取反

<< 位左移

>> 位右移注:移位操作为补零移位。位运算符只能对整形和字符型运算,不能对实型数据运算。如:chara=0x0f;表达式a=~a值为0xf0。如:chara=0x22;表达式a<<2值为0x88,即a值左移两位,移位后空白位补0。-----4.位操作运算符3.2.3运算符和表达式**32

++ 自增1 -- 自减1

自增、自减运算符可以在变量的前面或后面使用。如:++i或--I,意为在使用i之前,先使i值加1或减1。如:i++或i--,意为在使用变量i之后,再使i值加1或减1。例如,定义整型变量:inti=6,并有j=++i,则j值为7,i值也为7。而如有j=i++,则j值为6,i值为7。5.自增、自减运算符3.2.3运算符和表达式-----++--运算符**336.赋值运算符

= 赋值将“=”右边的值赋给“=”左边的变量(注:不是相等运算符)。3.2.3运算符和表达式-----赋值运算符**34C51提供了十种复合赋值运算符。+= -= *= /= %=<<= >>= &= ^= |=

采用复合赋值运算的目的是为了简化程序,提高C51程序的编译效率。例:a+=b相当于a=a+b。a>>=b相当于a=a>>b。7.复合赋值运算符3.2.3运算符和表达式----复合赋值运算符**358.对指针操作的运算符 & 取地址运算符 * 指针运算符注意&与*的用法意义如下:

1)“&”与按位与运算符的差别。如果“&”为“与”运算,&运算符的两边必须为变量或常量,如a=c&b。“&”是取地址运算时,如a=&b。3.2.3运算符和表达式-----指针操作的运算符**362)“*”与指针定义时指针前的“*”的差别。如char*pt,这里的“*”只表示pt为指针变量,不代表间接地址取内容的运算。而c=*b,是将以b的内容为地址的单元内容送c变量。

C51运算的优先级如下所示。!(非)→算术运算→关系运算→&&和||→赋值运算8.对指针操作的运算符3.2.3运算符和表达式-----指针操作的运算符**373.2.4程序结构

和ANSIC一样,C51的程序是一个函数定义的集合,可以由任意个函数构成,其中必须有一个主函数main()。程序的执行是从主函数main()开始的,调用其他函数后返回主函数main(),最后在主函数中结束整个程序,而不管函数的排列顺序如何。-----函数定义的集合**38

全局变量说明 /*可被各函数引用*/

类型说明main() /*主函数*/ {

声明部分 语句部分

}

类型说明函数名1(形式参数表) /*函数1*/ {

声明部分 语句部分

}

类型说明函数名n(形式参数表) /*函数n*/ {

声明部分 语句部分

}3.2.4程序结构-----程序的组成**393.3C51对MCS-51单片机的存储器访问MCS-51单片机的存储器分为片内数据存储器、特殊功能寄存器、片外数据存储器、片内程序存储器和片外程序存储器。在C51中访问这些存储器时,是通过定义不同存储类型的变量,以说明该变量所访问的存储器位置。3.3.1存储类型----C51访问存储器**401.data直接寻址片内RAM

直接寻址片内数据存储区RAM(128字节),访问速度快。2.bdata位寻址片内RAM

可位寻址片内数据存储区RAM(16个字节),允许位与字节混合访问。3.idata间接寻址片内RAM

间接寻址内部数据存储区,可访问全部内部地址空间(00~FFH,256字节)。3.3.1存储类型-----定义存储类型**414.pdata分页寻址片外RAM

分页(256Byte)外部数据存储区RAM(256字节),由操作码MOVX@Ri访问。5.xdata寻址片外RAM

寻址片外数据存储区RAM(64K字节),由操作码MOVX@DPTR访问。6.code寻址ROM

寻址片内外程序存储区ROM(64K字节),由操作码MOVC@A+DPTR访问。3.3.1存储类型-----定义存储类型**423.3.2存储器模式

存储器模式决定了变量的默认存储类型和参数传递区,变量定义不明确存储区类型时使用默认值。

C51有三种存储器模式:

SMALL、LARGE和COMPACT。-----变量的存储类型**433.3.2存储器模式存储模式说明小编译模式SMALL参数及局部变量放入可直接寻址的片内数据存储区(最大128B,默认存储类型是data),因此访问十分方便。另外所有对象,包括栈,都必须嵌入片内RAM。栈长很关键,因为实际栈长依赖于不同函数的嵌套层数。紧凑编译模式COMPACT参数及局部变量放入分页片外数据存储区(最大256B,默认的存储类型是pdata),通过寄存器R0和R1间接寻址,栈空间位于内部数据存储区中。大编译模式LARGE参数及局部变量直接放入片外数据存储区(最大64KB,默认存储类型为xdata),使用数据指针DPTR来进行寻址。用此数据指针访问的效率较低,尤其是对两个或多个字节的变量,这种数据存储类型的访问机制直接影响代码的长度,不方便之处在于这种数据指针不能对称操作。-----变量的存储类型**44有两种方式:预处理命令和编译控制命令。(1)使用预处理命令设定数据存储模式需在程序的第一句加预处理命令。如:#pragmasmall/*设定数据存储模式为小编译模式*/#pragmacompact/*设定数据存储模式为紧凑编译模式*/#pragmalarge/*设定数据存储模式为大编译模式*/数据存储模式的设定3.3.2存储器模式-----存储模式的设定**45(2)使用编译控制命令设定数据存储模式用C51编译程序对C51源程序进行编译时,使用编译控制命令,格式如下:C51源程序名SMALLC51源程序名COMPACTC51源程序名LARGE 3.3.2存储器模式-----存储模式的设定**46例如:C51源程序为file1.C,若使程序中的变量存储类型和参数传递区限定在外部数据存储区,即设定数据存储模式为COMPACT(紧凑编译模式)。方法1:在程序的第一句加预处理命令:#pragmacompact。方法2:用C51对file1.C进行编译时,使用编译控制命令:C51file1.CCOMPACT。3.3.2存储器模式-----存储模式的设定**473.3.2存储器模式#pragmasmall/*默认存储类型为MCS-51直接寻址片内RAM*/chardatai,j,k;/*在MCS-51片内直接寻址RAM中定义了3个变量,默认为自动变量*/chari,j,k;/*未指明存储类型,由#pragmasmall决定,与前一句完全等价*/intxdatam,n;/*在MCS-51片外RAM中定义了两个动态变量*/staticcharm,n;/*在MCS-51片内直接寻址RAM中定义了两个静态变量*/unsignedcharxdataram[10];/*在MCS-51片外RAM中定义了大小为10B的数组变量*/---【例5-1】变量和函数的存储模式设置**483.3.2存储器模式intfunc1(inti,intj)large /*指定函数中变量是LARGE模式*/{ return(i+j);}intfunc2(inti,intj) /*未指明存储模式,按默认的SMALL模式*/{ return(i-j);}---【例5-1】变量和函数的存储模式设置**493.3.3特殊功能寄存器的访问MCS-51系列单片机片内有21个特殊功能寄存器(SFR),分散在片内RAM区的0x80~0xFF地址范围内。对SFR的操作只能用直接寻址方式。为了能直接访问这些特殊功能寄存器,C51提供了定义sfr的方法。这与ANSIC不兼容,只适用于MCS-51系列单片机。-----定义sfr的方法**50----1.sfr数据类型

特殊功能寄存器数据类型来实现。定义特殊功能寄存器名的语法如下:

sfr特殊功能寄存器名=整型常量;3.3.3特殊功能寄存器的访问1.sfr数据类型**51----1.sfr数据类型3.3.3特殊功能寄存器的访问sfrPSW=0xD0; /*定义程序状态字PSW,因MCS-51单片机的PSW地址为D0H*/sfrTMOD=0x89;/*定义定时/计数器方式控制寄存器TMOD,因MCS-51单片机的TMOD地址为89H*/sfrP1=0x90; /*定义P1口,因MCS-51单片机的P1口地址为90H*/sfrSCON=0x98; /*定义串口控制寄存器SCON,因MCS-51单片机的SCON地址为8H*/**522.用sbit数据类型访问可位寻址的特殊功能寄存器中的位MCS-51系列单片机片内21个特殊功能寄存器(SFR)中有11个特殊功能寄存器是可位寻址的。访问这些可位寻址的特殊功能寄存器中的位的方法可由关键字sbit定义特殊功能寄存器位寻址数据类型来实现。定义特殊功能寄存器位名的语法有下列三种:

sbit特殊功能寄存器位名=特殊功能寄存器名^整型常量其中,特殊功能寄存器名是已由sfr定义了的特殊功能寄存器名,整型常量是位可寻址特殊功能寄存器中的位(是一个0~7之间的常数)。3.3.3特殊功能寄存器的访问----2.sbit数据类型**53sbit特殊功能寄存器位名=整型常量1^整型常量2

其中,整型常量1是指可位寻址特殊功能寄存器的字节地址(在80H~FFH之间),整型常量2是指该寄存器中的位(是一个0~7之间的常数)。

sbit特殊功能寄存器位名=整型常量其中,整型常量是可位寻址特殊功能寄存器的绝对位地址(位于80H~FFH之间)。3.3.3特殊功能寄存器的访问---定义方法**54标准SFR在reg51.h、reg52.h等头文件中已经被定义,只要用文件包含做出申明即可使用。3.3.3特殊功能寄存器的访问sfrPSW=0xD0;/*首先定义程序状态字PSW,

因MCS-51单片机的PSW地址为D0H*/sbitOV=PSW^2;/*在前面定义了PSW后,OV位于PSW的第2位*/sbitAC=0xD0^6;/*D0H是程序状态字PSW的字节地址,

辅助进位标志位AC位于PSW的第6位*/sbitRS0=0xD0^3;/*工作寄存器组控制位RS0位于PSW的第3位*/sbitCY=0xD7;/*进位标志位Cy的绝对位地址为D7H*/----实例**55例5-2

特殊功能寄存器的访问。#include”reg51.h”sbitP10=P1^0; /*定义P10为P1口第0位,即P1.0口*/sbitP12=P1^2; /*定义P12为P1口第2位,即P1.2口*/

voidmain() { P10=1; /*置位P1.0口*/ P12=0; /*复位P1.2口*/ PSW=0x08; /*程序状态字置0x08*/

…… }3.3.3特殊功能寄存器的访问----应用实例**563.3.4存储器和并行口的访问MCS-51单片机片内有128个字节的RAM区(00H~7FH),可扩展片外64KB的ROM和RAM,有P0、P1、P2、P3四个8位双向并行I/O口,每个端口可以按字节输入或输出,也可以按位进行输入或输出,四个口共32根口线。使用C51编程时,片内/外存储器、片内I/O口与片外扩展I/O口可以统一在头文件中定义,也可以在程序中进行定义(一般在程序开始的位置)。C51定义存储器、并行口方法如下。----在头文件中定义**571.对存储器使用绝对地址访问C51编译器提供了一组宏定义用来对MCS-51系列单片机的CODE、DATA、PDATA和XDATA空间进行绝对地址访问。函数原型如下:#defineCBYTE((unsignedcharvolatile*)0x50000L)#defineDBYTE((unsignedcharvolatile*)0x40000L)#definePBYTE((unsignedcharvolatile*)0x30000L)#defineXBYTE((unsignedcharvolatile*)0x20000L)#defineCWORD((unsignedintvolatile*)0x50000L)#defineDWORD((unsignedintvolatile*)0x40000L)#definePWORD((unsignedintvolatile*)0x30000L)#defineXWORD((unsignedintvolatile*)0x20000L)这些函数原型放在absacc.h文件中。3.3.4存储器和并行口的访问-----绝对地址访问**58CBYTE以字节形式对CODE区寻址,DBYTE以字节形式对DATA区寻址,PBYTE以字节形式对PDATA区寻址,XBYTE以字节形式对XDATA区寻址,CWORD以字形式对CODE区寻址,DWORD以字形式对DATA区寻址,PWORD以字形式对PDATA区寻址,XWORD以字形式对XDATA区寻址。3.3.4存储器和并行口的访问-----绝对地址访问**59例5-3使用绝对地址访问存储器#include<absacc.h>#include<reg52.h>#defineuintunsignedint#defineucharunsignedcharvoidmain(void){ uintui_var1; ucharuc_var1;ui_var1=XWORD[0x0000];/*访问外部RAM的0000H~0001H地址的内容*/uc_var1=XBYTE[0x0002];/*访问外部RAM的0002H地址的内容*/ 3.3.4存储器和并行口的访问-----绝对地址访问**60例5-3使用绝对地址访问存储器XWORD[0x0000]=0xAABB;/*将0xAABB送入外部RAM的000H~0001H地址中*/XBYTE[0x0002]=0xAA;/*将0xAA送入外部RAM的0002H地址中*/

……for(;;); }3.3.4存储器和并行口的访问-----绝对地址访问**612.对存储器使用指针或_at_扩展关键字访问例5-4

使用指针访问存储器。#defineucharunsignedchar#defineuintunsignedintvoidtest_memory(void){ucharidataivar1;/*定义一个指向idata存储空间的变量*/ucharxdata*xdp;/*定义一个指向XDATA存储器空间的指针*/chardata*dp;/*定义一个指向DATA存储器空间的指针*/

采用指针的方法,可实现在C51程序中对任意指定的存储器的绝对地址进行操作。3.3.4存储器和并行口的访问---指针访问**62ucharidata*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; /*数据16H送到IDATA区的变量ivar1所在的

地址单元中,等价于ivar1=0x16*/ }3.3.4存储器和并行口的访问---指针访问*3.3.4存储器和并行口的访问---指针访问2.对存储器使用指针或_at_扩展关键字访问采用_at_扩展关键字的方法,可实现在C51程序中对任意指定的存储器的绝对地址进行操作。例:voidmain(void){charxdadatemp_at_0x4000;charxdada*xdp;chardata*dp;xdp=0x2000;temp=*xdp;*xdp=0xAA;dp=0x30;*dp=0xBB}**643.C51定义片内I/O口单片机内部并行口可用关键字sfr定义,I/O口定义格式举例:sfrP0=0x80; /*定义P0口,地址80H*/sfrP1=0x90; /*定义P1口,地址90H*/3.3.4存储器和并行口的访问----sfr定义片内I/O**65----例5-5操作片内I/O口

sfrP1=0x90; /*定义P1口,地址90H*/ sfrP3=0xB0; /*定义P3口,地址B0H*/ sbitDIPswitch=P1^4; /*P1口第4位(P1.4口)为DIP开关的输入*/ sbitLEDgreen=P3^5; /*P3口第5位(P3.5口)为LED的输出*/ voidmain() {unsignedcharinval=0; for(;;){if(DIPswitch==1)/*检查P1.4口输入是否为高*/ {inval=P1&0x0F;/*读P1口0~3位*/ LEDgreen=0; /*置P3.5口输出为低*/ } else{LEDgreen=1; /*置P3.5口输出为高*/ } P3=(P3&0x0F)|inval;/*P1口0~3位输入与P3口的0~3位相或输出*/ } }3.3.4存储器和并行口的访问**664.C51定义外部并行口

对片外扩展的I/O口,则根据其硬件译码地址,将其看作片外数据存储器的一个单元,使用#define语句进行定义。用指针定义,指针的定义在absacc.h头文件中。3.3.4存储器和并行口的访问----#define语句定义片外I/O**67----例5-6操作片外I/O口#include“absacc.h”#definePAXBYTE[0xffec] /*将PA定义为外部I/O口,地址为0xffec*/voidmain(){PA=0x5A; /*将数据5AH写入地址为0xffec的存储单元或I/O端口*/}3.3.4存储器和并行口的访问**68----例5-6操作片外I/O口

在头文件或程序中对片内/外I/O口进行定义以后,在程序中就可以使用这些口了。定义口地址的目的是为了便于C51编译器按MCS-51单片机系统的实际硬件结构建立I/O口变量名与其实际地址的联系,以便程序员能用软件模拟MCS-51单片机系统的硬件操作。3.3.4存储器和并行口的访问**693.3.5位地址访问C51对位变量的定义有3种方法:1.用bit关键字定义C51位变量例如:

bitlock; /*将lock定义为位变量*/ bitdirention;/*将direction定义为位变量*/ bitdisplay; /*将display定义为位变量*/注意:不能定义位变量指针;也不能定义位变量数组。----对位变量的定义**70例如:

bitfun(bita1,bita2) {

…… return(a1); }3.3.5位地址访问2.函数可包含bit的参数和返回值----函数的定义**713.可位寻址存储区的位变量定义3.用sbit关键字定义数据类型为bdata的变量的位变量C51编译器允许数据类型为bdata的变量放入片内RAM可位寻址区中。例如:先定义变量的数据类型和存储类型,然后使用sbit定义位变量。bdataintibdata;/*ibdata定义为bdata整型变量*/bdatacharcarry[5];/*carry定义为bdata字符数组*/sbitmybit0=ibdata^0;/*mybit0定义为ibdata的第0位*/sbitmybit15=ibdata^15;/*mybit15定义为ibdata的第15位*/ 3.3.5位地址访问**723.可位寻址存储区的位变量定义sbitarrybit07=carry[0]^7;/*arrybit07定义为carry[0]的第7位*/sbitarrybit37=carry[3]^7;/*arrybit37定义为carry[3]的第7位*/arrybit37=0; /*carry[3]的第7位赋值为0(位寻址)*/carry[0]=’A’; /*carry[0]赋值为’A’(字节寻址)*/

位置(^操作符)后的最大值取决于指定的基本数据类型。对于char而言是0~7;对于int而言是0~15;对于long而言是0~31。3.3.5位地址访问**733.4C51函数C51程序是由一个个函数构成的,在构成C51程序的若干个函数中,必须有一个主函数main(),主函数可根据需要来调用其它函数。同一个函数可以在不同的地方被调用。**743.4.1函数的分类

从用户使用角度划分,函数分为库函数和用户自定义函数。库函数是编译系统为用户设计的一系列标准函数,用户只需调用,而无需自己去编写这些复杂的函数。在调用前要先使用#include包含命令包含和该函数有关的头文件,然后才能调用。如前面所用到的头文件reg51.h等,每一种头文件中包括一系列函数。**75

用户自定义函数是用户根据任务编写的函数。从函数定义形式上可划分为三种:无参函数、有参函数和空函数。

无参函数:函数中无参数定义,该函数调用时无参数传递。

有参函数:函数中定义形式参数。在调用函数时,实际参数值传递给形式参数,调用后返回结果给调用它的函数使用。空函数:函数中无参数,也无语句。该函数可以调用但没有任何功能,该函数是为了开发程序时将一些非基本模块的功能函数定义成空函数,先占好位置,以后再用编好的函数替换它。3.4.1函数的分类-----无参函数、有参函数和空函数**763.4.2函数的定义函数类型函数名() {

函数体语句

}

如果函数没有返回值,可以将返回值类型设为void,函数以“{”开始,以“}”结束。1.无参函数的定义----函数的定义**77例5-7无参函数的定义与调用。

#include<stdio.h> voidfun1() { printf(“ThisisaC51Program\n”); } voidmain() { fun1(); }3.4.2函数的定义----函数的定义**782.有参函数的定义函数类型函数名(形式参数表列) {

函数体语句

return(返回形参名)

}其中形式参数表列的各项要用","隔开,通过return语句将需返回的值返回给调用函数。3.4.2函数的定义----函数的定义**79intfun2(inta,intb){ intsum; sum=a+b; returnsum;}voidmain(){intx=123,y=456,sum; sum=fun2(x,y);}3.4.2函数的定义例5-8有参函数的定义与调用。**803.空函数的定义函数类型函数名() {}函数可以将返回值类型设为void。例5-9空函数的定义与调用。

voidfun3() {} voidmain() { fun3(); }3.4.2函数的定义3.空函数的定义**813.4.3函数的调用3.函数名(实际参数表列);函数的调用方式有三种:1)把被调函数作为主调函数中的一个语句。例如fun1();2)把被调函数作为表达式的一个运算对象。例如sum=2*fun2(x,y);3)把被调函数作为另一个函数的参数。例如printf(“sumis%d\n”,fun2(x,y));----函数调用的形式**823.4.4对被调函数的说明1)被调用函数必须是已经存在的函数(库函数和用户自定义函数)。2)调用库函数需要#include包含和该函数有关的头文件,然后才能调用。3)调用用户自定义函数,如果被调函数出现在主调函数之后,在主调函数前应对被调函数作声明。形式为:

函数类型函数名(形参表列);----函数调用条件**83voidmain() /*主函数*/{ intfun1(inta,intb); /*函数声明*/ intd,u=3,v=2; d=2*fun1(u,v);}intfun1(inta,intb){ intc; c=a+b; return(c);}3.4.4对被调函数的说明----例5-10函数的定义与声明**84 intfun1(inta,intb){ intc; c=a+b; return(c);}voidmain(){ intd,u=3,v=2; d=2*fun1(u,v);}3.4.4对被调函数的说明---函数的调用上例中被调函数在主调函数之后,在主调函数一开始对被调函数进行了声明。若被调函数出现在主调函数之前时,可以不对被调函数进行声明。上例可修改如下。**853.4.5中断函数

中断服务程序在C51程序中是以中断函数的形式出现的,中断函数的格式为:

void函数名()interruptnusingm {

函数体语句 }

interrupt是中断函数的关键字,n是中断号,MCS-51的中断号与中断源的对应关系如表5-5所示。

using是指定中断函数中选用工作寄存器组的关键字,m是0~3范围的常数,若不用该选项,编译器会自动选择默认工作寄存器组(0组寄存器)。-----中断函数的格式**86表5-5MCS-51中断源和中断的关系中断号中断源入口地址0外中断00003H1定时/计数器0000BH2外中断10013H3定时/计数器1001BH4串行口中断0023Hvoid函数名()interruptnusingm3.4.5中断函数-----中断函数的中断号**87void函数名()interruptnusingm例如:

voidT0_srv(void)interrupt1using1 /*定时/计数器0中断函数*/ {

……

/*定时/计数器0中断服务程序*/ }中断号中断源入口地址0外中断00003H1定时/计数器0000BH2外中断10013H3定时/计数器1001BH4串行口中断0023H3.4.5中断函数-----中断函数的格式**881)中断函数不能进行参数传递。2)中断函数没有返回值,应定义为void型。3)禁止对中断函数的直接调用。4)如果中断函数调用了其他函数,被调函数与中断函数使用相同的寄存器组。5)中断函数最好写在程序尾部。void函数名()interruptnusingm3.4.5中断函数-----编写中断函数要点**893.5C51结构化程序设计C51程序是一种结构化程序,由若干模块组成,每个模块中包含若干个基本结构,而每个基本结构中可以有若干条语句。基本结构有三种,顺序结构、选择结构和循环结构。3.5.1顺序结构程序顺序结构是一种最基本、最简单的程序结构。在这种结构中,语句被依次逐条地顺序执行。-----顺序结构程序**90例5-11

设计一乘法程序,乘积放在外部RAM中的0000H单元。 voidmain() { unsignedlongxdata*p; /*设定p是指向外部RAM区的unsignedlong指针*/ unsignedlongx=12345,y=67890,mum; mum=x*y; p=0x0000; /*p指向外部RAM区0000H单元*/ *p=mum; /*乘积存入外部RAM区0000H单元*/ }3.5.1顺序结构程序-----顺序程序设计**913.5.2选择结构程序

用if语句可以构成选择结构。它根据给定的条件进行判断,以决定执行某个分支程序段。C语言的if语句有三种基本形式。1.单分支语句

if(条件表达式)语句组;

其语义是:如果条件表达式的值为真,则执行其后的语句组,否则不执行其后的语句组。单分支语句执行过程可表示为图5-1所示。-----单分支程序**92例5-12寻找两个数中的大数输出

voidmain(){unsignedxdata*p; unsignedinta=35,b=78,max; max=a; if(max<b)max=b; p=0;/*p指向外部RAM区0000H单元*/ *p=max; /*最大值存入外部RAM区0000H单元*/}3.5.2选择结构程序例5-12寻找两个数中的大数输出**932.双分支语句

if(条件表达式)语句组1; else语句组2;

其语义是:如果条件表达式的值为真,则执行语句组1,否则执行语句组2。其执行过程可表示为图5-2所示。3.5.2选择结构程序-----双分支程序**94例5-13

寻找两个数中的大数输出。#include“reg51.h”voidmain(){ unsignedxdata*p; unsigneda=35,b=78,max; if(a>b) max=a; else max=b; p=0; /*p指向外部RAM区0000H单元*/ *p=max;/*最大值存入外部RAM区0000H单元*/}3.5.2选择结构程序-----双分支程序设计**953.多分支语句当有多个分支选择时,可采用if-else-if语句结构,其一般形式为:

if(条件表达式1)

语句组1; elseif(条件表达式2)

语句组2; elseif(条件表达式3)

语句组3;

… elseif(条件表达式n)

语句组n; else

语句m;3.5.2选择结构程序-----多分支程序**96例5-14

如图5-3所示,单片机P1口的P1.0和P1.1各接一个开关K1、K2,P1.4、P1.5、P1.6和P1.7各接一只发光二极管。由K1和K2的不同状态来确定哪个发光二极管被点亮。3.5.2选择结构程序-----多分支程序设计**97例5-14

#include“reg51.h” voidmain() { chara; a=P1; a=a&0x03;/*屏蔽高6位*/ if(a==0)P1=0x7F; elseif(a==1)P1=0xBF; elseif(a==2)P1=0xDF; elseP1=0xEF; }3.5.2选择结构程序-----多分支程序设计**984.开关选择switch语句switch语句结构的一般形式为:

switch(表达式) { case常量表达式1:语句组1; case常量表达式2:语句组2;

… case常量表达式n:语句组n; default:语句组n+1; }3.5.2选择结构程序-----多分支程序**99【例5-15】

用switch语句完成例5-14任务。程序如下。#include<reg51.h>voidmain(){ chara; a=P1; a=a&0x03; /*屏蔽高6位*/ switch(a) { case0:P1=0x7F;break; case1:P1=0xBF;break; case2:P1=0xDF;break; default:P1=0xEF; }}3.5.2选择结构程序-----多分支程序设计**100在使用switch语句时还应注意以下几点。(1)在case后的各常量表达式的值不能相同,否则会出现错误。(2)在case后,允许有多条语句,可以不用{}括起来。(3)各case和default子句的先后顺序可以变动,而不会影响程序执行结果。(4)default子句可以省略不用。(5)在每一case语句之后增加break语句,使每一次执行之后均可跳出switch语句,这样才能实现多分支结构。3.5.2选择结构程序----注意**1013.5.3循环结构程序

其特点是,在给定条件成立时,反复执行某程序段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。C语言提供了多种循环语句,可以组成各种不同形式的循环结构。C语言提供的循环语句有:1)用while语句;2)用do-while语句;3)用for语句。----C语言提供的循环语句**1021.while循环语句while循环语句的一般形式为:

while(表达式)语句组其中表达式是循环条件,语句组为循环体。while语句的语义是:计算表达式的值,当值为真(非0)时,执行循环体语句组。3.5.3循环结构程序----while循环语句**103【例5-16】

前面的例5-15程序只能执行一遍,用while语句使其无穷循环执行。程序如下。#include<reg51.h>voidmain(){ chara; while(1)/*循环条件表达式的值始终为1,无穷循环*/ { a=P1; a=a&0x03; /*屏蔽高6位*/ switch(a) { case0:P1=0x7F;break; case1:P1=0xBF;break; case2:P1=0xDF;break; case3:P1=0xEF; } }}3.5.3循环结构程序----while循环语句**104【例5-17】

用do-while语句实现例5-16。程序如下。#include<reg51.h>voidmain(){ chara; do { a=P1; a=a&0x03; /*屏蔽高6位*/ switch(a) { case0:P1=0x7F;break; case1:P1=0xBF;break; case2:P1=0xDF;break; case3:P1=0xEF; } }while(1);/*循环条件表达式的值始终为1,无穷循环*/}3.5.3循环结构程序----do-while循环语句应用**105----3.for循环语句for(表达式1;表达式2;表达式3)语句组for循环语句的执行过程如下:1)先求解表达式1。2)求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面第3步;若其值为假(0),则转到第5步,结束循环。3.5.3循环结构程序**106----3.for循环语句3)求解表达式3。4)转回上面第2步继续执行。5)循环结束,执行for语句体后面的一个语句。for循环语句的执行过程如图5-6所示。3.5.3循环结构程序**1071)for循环中的“表达式1(循环变量赋初值)”、“表达式2(循环条件)”和“表达式3(循环变量增量)”都是选择项,即可以缺省,但“;”不能缺省。2)省略了“表达式1(循环变量赋初值)”,表示不对循环控制变量赋初值。3.5.3循环结构程序----for循环语句使用说明**1083)省略了“表达式2(循环条件)”,则不做其它处理时便成为死循环。4)省略了“表达式3(循环变量增量)”,则不对循环控制变量进行操作,这时可在语句体中加入修改循环控制变量的语句。3.5.3循环结构程序----for循环语句使用说明**1095)“表达式1(循环变量赋初值)”和“表达式3(循环变量增量)”可同时省略,结果如同前面第2、4两种情况。6)3个表达式都可同时省略,结果如同前面第2、3、4三种情况的综合效果。7)表达式2一般是关系表达式或逻辑表达式,但也可是数值表达式或字符表达式,只要其值非零,就执行循环体。3.5.3循环结构程序----for循环语句使用说明**110例5-18

用for语句实现例5-16。#include“reg51.h”voidmain(){ chara; for(;;)/*无循环条件,无穷循环*/ { a=P1;/*读P1口的值*/ a=a&0x03; /*屏蔽高6位*/ switch(a) {case0:P1=0x7F;break; case1:P1=0xBF;break; case2:P1=0xDF;break; case3:P1=0xEF; } }}3.5.3循环结构程序----for循环程序设计**1114.break语句break语句通常用在循环语句和开关语句中。当break用于开关语句switch中时,可使程序跳出switch而执行switch以后的语句。当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环结构后面的语句,通常break语句总是与if语句联在一起。即满足条件时便跳出循环。3.5.3循环结构程序-----break语句**112----5.continue语句continue语句的作用是跳过循环体中剩余的语句而强行开始执行下一次循环。continue语句只用在for、while、do-while等循环体中,常与if条件语句一起使用,用来加速循环。

3.5.3循环结构程序**1133.5.4查表程序

在许多单片机嵌入式应用系统中,经常采用查表法代替数学公式的计算。特别是对传感器的非线性补偿的场合,使用查表法比采用复杂的曲线拟合效果更好。可以将预先计算好的数据随程序装入到EPROM的一块指定区间,形成数据表。查表程序可以用数组实现。**114例5-19#defineuchunsigenedchar uchcodetem[]={32,34,36,37,39,41}; uchf_to_c(uchdeg) { returntem[deg]; } voidmain() { uchx; x=f_to_c(3); }3.5.4查表程序

编写一个将摄氏温度转换为华氏温度的查表程序,已知摄

温馨提示

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

评论

0/150

提交评论