首页 理论教育 C51语言编程基础:入门指南

C51语言编程基础:入门指南

时间:2023-06-28 理论教育 版权反馈
【摘要】:机器语言仅仅使用0和l这两个二进制代码表示指令、数字和符号,直接用机器语言编写的程序称为机器语言程序。3)支持直接采用C语言编写8051单片机的中断服务程序。C51程序结构与标准的C语言程序结构相同,也是采用函数结构。用C51语言设计的程序的基本结构如下:C51语言的编程基础1)C51语言中的常用标识符和关键字C51标识符的意义及用途与ANSIC相同,是用来标识源程序中某个对象名字的。在C51中,变量名与变量值的使用规则与ANSIC相同。

C51语言编程基础:入门指南

(1)程序设计语言

51系列单片机的程序设计语言主要有3种:机器语言汇编语言和高级语言(C51)。

在单片机中,完全面向机器的,能被单片机直接识别和执行的语言称为机器语言。机器语言仅仅使用0和l这两个二进制代码表示指令、数字和符号,直接用机器语言编写的程序称为机器语言程序。

汇编语言是一种符号化语言。为了克服机器语言的一些缺点,汇编语言采用英文字符代替二进制代码,我们将这些英文字符称为助记符。所有指令都采用助记符来描述和标识的语言就称为汇编语言,用汇编语言编写的程序即为汇编程序。

汇编语言其实也是面向机器的,是一种低级语言,但汇编语言编写的程序必须翻译为二进制机器语言后才能送给机器执行。值得注意的是,每一系列单片机都有自己的汇编语言指令系统,相互之间并不通用。

以C语言为例,高级语言优点很多,它易于读写和掌握、针对性较强、表达方式灵活、编写程序方便快捷、移植性好,且可进行结构化设计、方便多人合作项目。但使用高级语言编写出来的代码质量比汇编语言的差,代码量也大。

C语言和汇编语言一样,所编写程序都必须翻译为二进制机器语言才能送给机器执行。两种语言相较而言,各有各的优点。汇编产生的代码少,程序占用单片机空间小,速度运行快,可移植性差。C语言学习起来较为容易,可移植性强,相对于汇编程序产生的代码多,占用空间大,运行速度稍微慢些。汇编语言是面向机器的语言类型,和底层硬件结合紧密,掌握了汇编语言程序设计,就能真正理解单片机的工作原理及软件对硬件的控制关系。初学者一般从汇编语言开始学起,汇编语言学好了以后再学C语言就很容易上手。以下主要介绍MCS-51单片机的C语言程序设计(C51)的基本数据类型、存储类型、C51的特点、编程基础、基本的程序设计方法以及典型模块设计案例,读者如果可以在学习单片机汇编语言程序设计的基础上再阅读以下内容,对于理解和掌握会事半功倍。

(2)C51的特点及其结构

为了提高单片机应用程序设计的效率,改善程序的可读性和可移植性,采用C语言是一种好的选择。C51符合ANSI标准,具有以下特点:

1)支持9种基本数据类型,其中包括32位长的浮点类型。

2)变量可存放在不同类型的存储空间中。

3)支持直接采用C语言编写8051单片机的中断服务程序。

4)充分利用8051工作寄存器组。

5)可以保留源程序中的所有符号、类型信息,调试方便。

C51程序结构与标准的C语言程序结构相同,也是采用函数结构。函数由函数说明和函数体两部分组成,一个程序由一个或多个函数组成,其中有且只能有一个主函数main(),主函数是程序的入口,在主函数中调用库函数和用户定义的函数,主函数中的所有语句执行完毕,则程序结束。

用C51语言设计的程序的基本结构如下:

978-7-111-51028-4-Chapter05-112.jpg

(3)C51语言的编程基础

1)C51语言中的常用标识符和关键字

C51标识符的意义及用途与ANSIC相同,是用来标识源程序中某个对象名字的。这些对象可以是函数、变量、常量、数组、数据类型、存储方式、语句等。标识符的定义非常灵活,但要遵循以下几个规则:

①标识符必须由字母(a~z,A~Z)或下划线“”开头。

②标识符的其他部分可以由字母、下划线或数字(0~9)组成。

③标识符是区分大小写的。

④标识符的长度不能超过32个字符。

⑤标识符不能使用C51的关键字。

关键字是已定义的具有固定名称和特定含义的特殊标识符,又称为保留字。它们具有固定的名称和含义,在使用C51编写程序时,用户命名的标识符不能与关键字相同,在C51中的关键字除了ANSIC标准中的32个关键字外还根据51单片机的特点扩展了相关的关键字,C51扩展的关键字见表5-5。

表5-5 C51扩展的关键字

978-7-111-51028-4-Chapter05-113.jpg

此外,下列标识符虽然不属于关键字,但由于它们属于预处理命令,用户不要在程序中随便使用,这些标识符包括define、undef、include、ifdef、ifndef、endif、line、elif。

2)C51语言中的数据类型

C51具有ANSIC的所有标准数据类型。基本数据类型有char、int、short、long、float、double等。对于C51编译器来说,short型与int型相同,double型与float型相同。针对MCS-51系列单片机,C51扩展了bit、sfr、sfr16、sbit等特殊数据类型。C51的数据类型见表5-6。

表5-6 C51的数据类型

978-7-111-51028-4-Chapter05-114.jpg

(续)

978-7-111-51028-4-Chapter05-115.jpg

3)C51的常量和变量、存储器类型及存储区

常量是指在程序执行过程中其值不能改变的量。C51支持整型常量、浮点型常量、字符型常量和字符串型常量。而变量是指在程序运行过程中其值可以改变的量。与AN-SIC一样,在C51中,变量必须先定义再使用,定义时须指出该变量的数据类型和存储模式,以便编译系统为它分配相应的存储空间。在C51中,变量名与变量值的使用规则与ANSIC相同。除此之外,C51中,还使用了两个与单片机相关的变量。

①特殊功能寄存器变量(sfr、sfr16)

8051单片机芯片内有许多特殊功能寄存器,通过这些特殊功能寄存器可以控制单片机的定时器、计数器、串行口、I/O及其他内部功能部件,每一个特殊功能寄存器在单片机片内RAM中都对应着一个字节单元或两个字节单元。

在C51中,允许用户对这些特殊功能寄存器进行访问,访问时需先通过关键字sfr或者sfr16对特殊功能寄存器进行定义,并在定义时指明它们所对应的片内RAM单元的地址,定义格式如下:

sfr特殊功能寄存器名=地址

sfr16特殊功能寄存器名=地址

其中,sfr用于对51系列单片机中单字节地址的特殊功能寄存器进行定义,如I/O口P0、P1、P2、P3、程序状态字(PSW)等;sfr16则用于对双字节地址的特殊功能寄存器进行定义,如DPTR寄存器。举例如下:

978-7-111-51028-4-Chapter05-116.jpg

②位变量(bit、sbit)

在C51中,允许用户通过位类型符定义位变量。位类型符有两个,即bit和sbit,可以定义两种位变量。bit位类型符用于定义一般的可处理位变量,格式如下:

bit位变量名

sbit位类型符用于定义可位寻址字节或特殊功能寄存器中的位,定义时需要指明其位地址,可以是位直接地址,也可以是可位寻址变量带位号,还可以是特殊功能寄存器(SFR)名带位号,格式如下:

sbit位变量名=地址值

sbit位变量名=SFR名称^变量位地址值

sbit位变量名=SFR地址值^变量位地址值

如可以用以下三种方法定义PSW中的溢出位OV:

978-7-111-51028-4-Chapter05-117.jpg

为了方便使用,C51编译器把8051单片机的常用的特殊功能寄存器和特殊位进行了定义,放在一个名为reg51.h的头文件中,用户要使用时,只需在用户程序的起始处使用预处理命令“#include<reg51.h>”把这个头文件包含到用户程序来即可。需要注意的是不同版本的编译器该头文件的名字和内容可能会稍有差异,使用时请稍加留意。

存储器类型是用来指明变量所处的单片机的存储器区域。C51编译器对于程序存储器提供存储器类型标识符code,用户的应用程序以及各种表格常数被定位在code空间。数据存储器RAM用于存放各种变量,通常应尽可能将变量存放在片内RAM中以加快操作速度。C51对于片内RAM提供3种存储器类型标识符:data、idata和bdata。对于片外RAM,C51提供两个存储器类型标识符:xdata和pdata。C51可识别的存储器类型见表5-7。

表5-7 C51可识别的存储器类型

978-7-111-51028-4-Chapter05-118.jpg

如果在定义变量时没有明确指出该变量的存储器类型,则按C51编译器采用的编译模式来确定变量的默认存储器空间。C51提供三条编译模式控制命令:SMALL、COMPACT和LARGE。

4)绝对地址访问

在C51中,既可以通过变量的形式访问51系列单片机的存储器,也可以通过绝对地址来访问存储器。对于通过绝对地址访问,访问形式有以下三种:

①使用C51运行库中的预定义库

C51编译器提供了一组宏定义来对51系列单片机的存储器空间进行绝对寻址,并规定只能以无符号数方式来访问。定义了以下8个宏定义,函数原型如下:

978-7-111-51028-4-Chapter05-119.jpg

978-7-111-51028-4-Chapter05-120.jpg

上述宏定义用来对51系列单片机的存储器空间进行绝对地址访问,可以作为字节寻址。CBYTE寻址code区,DBYTE寻址data区,PBYTE寻址分页pdata区,XBYTE寻址xdata区。

上述函数原型放在C51的库函数absacc.h中,使用时只需要使用预处理命令#in-clude<absacc.h>把它包含到文件中即可使用,例如:

978-7-111-51028-4-Chapter05-121.jpg

②使用C51扩展关键字at

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

[存储类型]数据类型变量名at地址常数

其中,存储器类型为data、bdata、idata、pdata、xdata之一,如果省略则按存储器模式规定的默认存储器类型确定变量的存储器区域;数据类型为C51支持的数据类型;地址常数用于指定变量的绝对地址,必须位于有效的存储器空间之内;使用at定义的变量必须为全局变量。例如:

978-7-111-51028-4-Chapter05-122.jpg

③使用指针访问

利用基于存储器的指针也可以指定变量的存储器绝对地址。具体方法是先定义一个基于存储器的指针变量,然后对该变量赋以存储器绝对地址值。例如:

978-7-111-51028-4-Chapter05-123.jpg

5)C51语言常用运算符

运算符是完成某种特定运算的符号,C51语言的运算符可分为赋值运算符、算术运算符、关系运算符、逻辑运算符、位运算符、复合赋值运算符、指针和地址运算符、强制类型转换运算符和Sizeof运算符。按其在表达式中与运算对象的关系,又可分为单目运算符、双目运算符和多目运算符。单目运算符只有一个操作数,双目运算符有两个操作数,多目运算符则有多个操作数。

①赋值运算符

赋值运算符“=”的作用是将一个数据的值赋给一个变量,利用赋值运算符将一个变量与一个表达式连接起来的式子称为赋值表达式,在赋值表达式的后面加一个分号“;”便构成了赋值语句,赋值语句的格式如下:

变量=表达式;

该语句的意义是先计算右边表达式的值,然后将该值赋给左边的变量。上式中的表达式还可以是一个赋值表达式,即允许进行多重赋值。例如:

978-7-111-51028-4-Chapter05-124.jpg

都是合法的赋值语句。在使用赋值运算符“=”时应注意不要与关系运算符“==”(两个等号)相混淆,运算符“=”用来给变量赋值,运算符“==”用来进行相等关系运算。

②算术运算符

基本的算术运算符见表5-8。

表5-8 基本的算术运算符

978-7-111-51028-4-Chapter05-125.jpg

注意,增量运算(自加运算)符“++”和减量运算(自减运算)符“--”只能用于变量,不能用于常教或表达式。

③关系运算符

C51语言中有6种关系运算符见表5-9。

表5-9 关系运算符

978-7-111-51028-4-Chapter05-126.jpg

④逻辑运算符

逻辑运算符用来求某个条件表达式的逻辑值,C51语言中有3种逻辑运算符见表5-10。

表5-10 逻辑运算符

978-7-111-51028-4-Chapter05-127.jpg

⑤位运算符

能对运算对象进行按位操作是C语言的一大特点,正是由于这一特点使C语言具有了汇编语言的一些功能,从而使之能对计算机的硬件直接进行操作。C51语言中共有6种位运算符,见表5-11。

表5-11 位运算符

978-7-111-51028-4-Chapter05-128.jpg

⑥复合赋值运算符

在赋值运算符“=”的前面加上其他运算符,就构成了复合赋值运算符,见表5-12。

表5-12 复合赋值运算符

978-7-111-51028-4-Chapter05-129.jpg

⑦指针和地址运算符

在C语言的数据类型中专门有一种指针类型。变量的指针就是该变量的地址,还可以定义一个指向某个变量的指针变量。为了表示指针变量和它所指向的变量地址之间的关系,C语言提供了取内容运算符∗和取地址运算符&。一般形式为:变量=∗指针变量或指针变量=&目标变量。取内容运算的含义是将指针变量所指向的目标变量的值赋给左边的变量;而取地址运算的含义是将目标变量的地址赋给左边的指针变量。

⑧强制类型转换运算符

强制类型转换运算符“()”的作用是将表达式或变量的类型强制转换成为所指定的类型。强制类型转换运算符的一般使用形式为:(类型)表达式。

⑨sizeof运算符

用于求取数据类型、变量及表达式的字节数的运算符sizeof,该运算符的一般使用形式为:sizeof(表达式)或sizeof(数据类型)。

(4)C51语言程序设计

1)C51语句和程序结构

①程序的基本结构

C语言程序是由若干条语句组成,语句以分号结束。C语言是一种结构化程序设计语言,从结构上可以把程序分为顺序结构、分支结构和循环结构。

C51语言中,有一组相关的控制语句,用来实现分支结构与循环结构:

分支控制语句if、switch、case;

循环控制语句for、while、do-while、goto。

②顺序结构程序的设计

例5-4 片内RAM的30H单元存放着一个0~9之间的数,用查表法,求出该数的平方值并放入片内RAM的31H单元。

C51语言实现程序如下:

978-7-111-51028-4-Chapter05-130.jpg

例5-5 使用C51编程实现a∗b,b∗c,b/c,b%c运算,其中a=45,b=1000,c=300。

对于单(多)字节数乘除法,使用C51话言编程的时候需要注意数据类型的数值范围。

程序如下:

978-7-111-51028-4-Chapter05-131.jpg

③循环结构程序的设计

循环控制语句(又称重复结构),是程序中的另一个基本结构。在C语言中用来构成循环控制语句的有while语句、dowhile语句、for语句和goto语句。

例5-6 编程将片内30H~39H单元的数据传送到片外RAM的1000H~1009H单元中。

C51语言实现程序:

978-7-111-51028-4-Chapter05-132.jpg

④分支结构程序的设计

分支结构是一种基本的结构,其基本特点是程序的流程由多路分支组成,在程序的一次执行过程中,根据不同的情况,只有一条支路被执行,而其他分支上的语句被直接跳过。

C语言的分支选择语句有以下几种形式:(www.xing528.com)

a.if(条件表达式)语句

其含义是:若条件表达式的结果为真(非0值),就执行后面的语句;反之,若条件表达式的结果为假(0值),就不执行后面的语句。

b.switch(表达式)

978-7-111-51028-4-Chapter05-133.jpg

执行过程是:将switch后面表达式的值与case后面各个常量表达式的值逐个进行比较,如相等,就执行相应的case后面的语句,然后执行break语句。break语句又称间断语句,它的功能是终止当前语句的执行,使程序跳出switch语句。如无相等的情况,则执行default后面的语句。其中常量表达式一般为整型、字符型或者枚举类型,而且所有的常量表达式的值不能相同。

例5-7 片内RAM的30H单元存放着一个有符号数x,函数yx有以下关系式:

978-7-111-51028-4-Chapter05-134.jpg

编程实现该函数。

假设y存放于片内31H单元,C51程序如下:

978-7-111-51028-4-Chapter05-135.jpg

978-7-111-51028-4-Chapter05-136.jpg

2)C51语言中常用库函数

C51编译器的运行库中含有丰富的库函数,使用库函数可以简化程序设计工作,提高工作效率。由于51系列单片机本身的特点,某些库函数的参数和调用格式与ANSIC标准有所不同。每个库函数都在相应的头文件中给出了函数原型声明,用户如果需要使用库函数,必须在源程序的开始处采用编译预处理命令#include将有关的头文件包含进来。C51的库函数又分为本征库函数和非本征库函数。

C51提供的本征函数是指编译时直接将固定的代码插入当前行,而不是用ACALL和LCALL语句来实现,这样就大大提供了函数访问的效率,而非本征函数则必须由ACALL及LCALL调用。C51的本征库函数只有9个,见表5-13。

表5-13 C51的本征库函数

978-7-111-51028-4-Chapter05-137.jpg

如果要使用本征函数,在程序中使用#include<intrins.h>这条语句即可。

在使用C51进行程序设计时,还经常使用以下非本征库函数。

①专用寄存器头文件。51系列单片机有不同的生产厂家以及不同的系列产品,如仅ATMEL公司就有AT89C2051、AT89C51/52、AT89S51/52等。它们都是基于8051系列的芯片,唯一不同之处在于内部资源,如定时器、中断、I/O等数量以及功能的不同。为了实现这些功能,只需将相应的功能寄存器的头文件加载在程序中即可。另外,在使用头文件的时候,要注意所使用的单片机的生产厂家和所使用的KeilμVision版本,因为不同厂家和不同版本的KeilμVision下的头文件的内容会有所不同。如在KeilμVi-sion4中,ATMEL公司的AT89x051.H头文件中已经包含了P0~P3I/O端口的位定义,用户在使用时,只需在程序开头使用语句:#include<AT89x051.H>把头文件包含进来,在主程序中无需再进行位定义。而如果使用的是其他单片机,则可能需要进行位定义。

②绝对地址访问文件absacc.h。该文件包含了允许直接访问8051不同存储区的宏定义,以确定各存储空间的绝对地址。通过包含此头文件,可以定义直接访问扩展存储器的变量。

③动态内存分配函数,位于stdlib.h头文件中。

④输入/输出流函数,位于头文件stdio.h中。流函数通过8051的串行口或用户定义的I/O口读写数据,默认为8051串行口。

3)C51语言程序常用编译预处理命令

在C编译器系统对程序进行编译之前,先要对这些程序进行预处理。然后再将预处理的结果和源程序一起进行正常的编译处理得到目标代码。常用的预处理命令有宏定义、文件包含及条件编译。通常的预处理命令都用“#”开头。例如:

978-7-111-51028-4-Chapter05-138.jpg

①宏定义

宏定义,即#define指令,它的作用是用一个字符串来进行替换。这个字符串既可以是常数,也可以是其他任何字符串,宏定义又分为带参数的宏定义和不带参数的宏定义。

a.带参数的宏定义

带参数的宏定义不是进行简单的字符串替换,还要进行参数替换。其定义的形式如下:

978-7-111-51028-4-Chapter05-139.jpg

例如:

978-7-111-51028-4-Chapter05-140.jpg

宏定义后,程序中可以使用宏名,并将形参换成实参。如:

978-7-111-51028-4-Chapter05-141.jpg

预处理时将换成area=5∗4。

b.不带参数的宏定义

不带参数的宏定义又称符号常量定义,是指用一个指定的标识符来表示一个字符串,表示形式如下:

978-7-111-51028-4-Chapter05-142.jpg

其中,标识符是所定义的宏符号名,它的作用是在程序中使用所指定的标识符来代替所指定的常量表达式。例如:

978-7-111-51028-4-Chapter05-143.jpg

宏定义后,PI作为一个常量使用,在预处理时将程序中的PI替换为3.1415926。所以使用不带参数的宏定义可以减少程序中的重复书写,且可以提高程序的可读性。

②文件包含

文件包含是指一个程序文件将另外一个指定文件的全部内容包含进来,作为一个整体进行编译。文件包含命令的一般格式如下:

978-7-111-51028-4-Chapter05-144.jpg

文件包含命令#include的功能是将指定文件的全部内容替换该预处理行。在进行较大规模程序设计时,文件包含命令是十分有用的。为了模块化编程的需要,可以将C语言程序的各个功能函数分散到多个程序文件中,分别由若干人员进行编程,然后再用#include命令将它们嵌入到一个总的程序文件中去。

还可以将一些常用的符号常量、带参数的宏以及构造类型的变量等定义在一个独立的文件中,当某个程序需要时再将其包含进来,从而可以减少重复劳动,提高程序的编制效率。

C51提供了丰富的库函数和相应的头文件,只需用#include命令包含相应的库函数和头文件,就可以使用库函数中定义的函数或者头文件中定义的寄存器。

4)C51程序的常用仿真调试工具

Keil μVision是目前比较流行的基于Windows的兼容51系列单片机的C语言集成开发系统,是目前最流行的51系列单片机开发软件,该软件提供了一个集成开发环境(Integrated Development Environment,IDE),它包括C编译器、宏汇编、链接器、库管理和一个功能强大的仿真调试器。将程序编辑、编译、汇编、链接、调试等各阶段都集成在一个环境中。该软件已成为使用C51开发单片机系统的首选。

(5)程序应用举例

1)并行输入/输出端口

例5-8 8只发光二极管在圆周上均匀分布,控制原理图如图5-43所示,编写控制程序实现单一发光点的顺转和逆转,点亮间隔为50ms,重复循环。

978-7-111-51028-4-Chapter05-145.jpg

图5-43 例5-8控制原理图

C51语言实现程序如下:

978-7-111-51028-4-Chapter05-146.jpg

978-7-111-51028-4-Chapter05-147.jpg

例5-9 如图5-44所示,用MCS-51单片机的P1口驱动一个LED显示器,在显示器上依次显示字符0~F。

978-7-111-51028-4-Chapter05-148.jpg

图5-44 单片机驱动共阴极LED显示器电路

常用的LED显示器由8个发光二极管组成,也称8段LED显示器,LED数码显示器共有共阳极和共阴极两种连接方法。为了显示数字或符号,需要为LED显示器提供显示字形代码。LED显示器的字形各代码位的对应关系如下:

978-7-111-51028-4-Chapter05-149.jpg

当显示器采用共阴极接法时,若显示数字“0”时,则须点亮a、b、c、d、e、f段。

C51语言实现程序如下:

978-7-111-51028-4-Chapter05-150.jpg

978-7-111-51028-4-Chapter05-151.jpg

2)中断服务程序设计

C51支持在C语言源程序中直接编写8051单片机的中断服务程序(ISR),从而可以减轻采用汇编语言编写中断服务程序的繁琐程度。为了在C语言源程序中直接编写中断服务程序的需要,C51编译器对函教的定义进行了扩展,增加了一个扩展关键字interrupt,它是函数定义时的一个选项,加上这个选项即可将一个函数定义成中断服务函数。定义中断服务函数的一般形式为

978-7-111-51028-4-Chapter05-152.jpg

关键字interrupt后面的n是中断号,取值范围为0~31(有些51单片机有多达32个中断源),具体的中断号n和中断向量取决于单片机芯片型号,[]表示括号内的内容是可选项。8051单片机的中断号、中断源和中断向量关系见表5-14。

表5-14 8051单片机的中断号、中断源和中断向量关系

978-7-111-51028-4-Chapter05-153.jpg

usingm指明该中断服务程序所使用的工作寄存器组,取值范围是0~3。指定工作寄存器组的缺点是,所有被中断调用的过程都必须使用同一个寄存器组,否则参数传递会发生错误。通常不设定usingm,除非能保证中断程序中未调用其他子程序。另外需要注意的是,关键字using和interrupt后面都不允许跟带运算符的表达式。

使用中断函数时应遵循以下规则:

①中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译失败。中断函数也没有返回值,如果定义一个返回值将得到一个不正确的结果。因此,在定义中断函数时应将其定义为void类型,以明确说明没有返回值。

②在任何情况下都不能直接调用中断函数,否则会产生编译错误。因为中断系统的返回是通过RETI指令完成的,而RETI指令影响单片机的硬件中断系统,如果在没有中断请求的情况下直接调用中断函数,则会产生严重的错误。

③在中断函数中如果调用了其他函数,则被调函数所使用的寄存器必须与中断函数相同,否则会产生不正确的结果,因此,通常不设定usingm。

另外,在使用C51编写中断服务程序时,无需像汇编语言那样,对A、B、DPH、DPL、PSW等寄存器进行保护,C51编译器会根据上述寄存器的使用情况在目标代码中自动压栈和出栈。

例5-10 利用定时器/计数器T0的方式2对外部信号计数。要求每计满100个数,将P1.0引脚信号取反。

分析:外部信号由T0(P3.4)引脚输入,每发生一次负跳变计数器加1,每输入100个负跳变,计数器产生一次中断,在中断服务程序中将P1.0引脚信号取反。定时器/计数器T0工作于方式2计数模式,计数初始值X=256-100=156=9CH,则TH0=TL0=9CH,方式控制字设定为TMOD=00000110B(06H)。

C51语言实现程序如下:

978-7-111-51028-4-Chapter05-154.jpg

978-7-111-51028-4-Chapter05-155.jpg

例5-11 如图5-45所示电路,设外部中断信号为负脉冲,将该信号引入外部中断1引脚。要求每中断一次,从P1.4~P1.7输入外部开关状态,然后从P1.0~P1.3输出。

978-7-111-51028-4-Chapter05-156.jpg

图5-45 外部中断1使用

C51语言实现程序如下:

978-7-111-51028-4-Chapter05-157.jpg

978-7-111-51028-4-Chapter05-158.jpg

3)定时器/计数器C51程序设计

例5-12 利用定时器/计数器定时产生周期信号。要求使用定时器T0定时,在P1.7引脚上输出频率为50Hz的方波,设晶振频率为12MHz。

按题意分析可得,方波周期T=1/(50Hz)=20ms,可用定时器0工作于方式1定时t=10ms,使P1.7每隔10ms取反一次,即可得到周期为20ms(50Hz)的方波。

初值计算:fosc=12MHz,则机器周期为1μs,初值X=216-fosct/12=55536=0xd8f0;即有TH0=0xd8,TL0=0xf0。

采用中断法,C51程序如下:

978-7-111-51028-4-Chapter05-159.jpg

978-7-111-51028-4-Chapter05-160.jpg

采用查询法,C51程序如下:

978-7-111-51028-4-Chapter05-161.jpg

另外需要说明的是,在使用C51语言的时候,如果在编译程序的时候遇到“error C231:‘PXX’:redefinition”这样的问题,则说明在头文件reg51.h中已包含有所使用的I/O引脚的位定义,用户在程序中无需再进行定义;如果头文件没有进行相应的位定义,则用户既可以在程序中进行位定义,也可以将位定义程序置于头文件中。

8032/8052单片机增加了一个定时器/计数器2,定时器/计数器2可以设置成定时器,也可以设置成外部事件计数器,并具有三种工作方式:16位自动重装载定时器/计数器方式、捕捉方式和串行口波特率发生器方式。

例5-13 利用定时器/计数器T2定时产生周期信号。要求定时器T2定时,在P1.7引脚上输出周期为1s的方波,设晶振频率为12MHz。

程序如下:

978-7-111-51028-4-Chapter05-162.jpg

978-7-111-51028-4-Chapter05-163.jpg

例5-14 利用定时器/计数器T2的捕捉方式,对脉冲周期进行测量。

解:由题意分析,外部脉冲由P1.1引脚输入,可设T2工作于捕捉工作方式,计数初值为0,T2在脉冲信号下降沿进行捕捉,如图5-46所示。利用信号两下降沿计时时间之差即可计算出被测脉冲的周期,采用中断方式。

工作控制字为T2CON=0x09;计数初值TH2=TL2=0x00。

978-7-111-51028-4-Chapter05-164.jpg

图5-46 捕捉示意图

C51程序如下:

978-7-111-51028-4-Chapter05-165.jpg

978-7-111-51028-4-Chapter05-166.jpg

4)串行接口C51程序设计举例

①串行口方式1用于点对点的异步通信(单工方式)

例5-15 异步通信硬件连接如图5-47所示,A机发送,B机接收,波特率为2400bit/s,晶振为6MHz,T1作为波特率发生器,串行口为工作方式1,A机送出内部RAM50H开始的16B数据,B机接收数据存放在外部RAM3000H~300FH单元中。

978-7-111-51028-4-Chapter05-167.jpg

图5-47 异步通信硬件连接

采用查询方式,A机发送程序如下:

978-7-111-51028-4-Chapter05-168.jpg

978-7-111-51028-4-Chapter05-169.jpg

采用查询方式,B机接收程序如下:

978-7-111-51028-4-Chapter05-170.jpg

978-7-111-51028-4-Chapter05-171.jpg

②串行口方式1用于点对点的异步通信(双工方式)

例5-16 异步通信硬件连接如图5-47所示,将A机的片内RAM中30H~37H的8个单字节数据发送到B机的片内RAM中的30H~37H单元。为了保证通信的畅通与准确,在通信中作如下约定:通信开始时,A机发送一个信号01H,B机接收到一个正确信号后回答FFH,表示同意接收;A机收到FFH后,就可以发送后续数据,数据发送完后发送一个校验和;B机接收到数据后,用已接收的数据产生校验和并与接收到的检验和比较,如相同,表示接收无误,B机发送00H,表示接收正确,否则,B机发送BBH,请求A机重发。

A机程序如下:

978-7-111-51028-4-Chapter05-172.jpg

978-7-111-51028-4-Chapter05-173.jpg

B机程序如下:

978-7-111-51028-4-Chapter05-174.jpg

978-7-111-51028-4-Chapter05-175.jpg

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈