山科大_《单片机的C语言程序设计与运用(第2版)》期末复习题及答

更新时间:2024-06-04 22:14:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一、填空

1.KeiL C51软件中,工程文件的扩展名是____UV2______,编译连接后生成可烧写的文件扩展名是_____HEX_______。

2.C51支持的指针有 一般指针 和 存储器指针 。

3.C51中,没有专门的循环语句,我们可以用函数______crol_______完成一个字节的循环左移,用____irol_____完成二个字节的循环左移。 4. 函数 是C语言的基本单位。

5.C语言中输入和输出操作是由库函数 scanf 和 printf 等函数来完成。 6.若有说明int i,j,k;则表达式i=10,j=20,k=30,k*=i+j的值为__ 900______。 7. 数组 是一组有固定数目和相同类型成分分量的有序集合。

8.变量的指针就是变量的 地址 ;指针变量的值是 指针 。

9.在C语言中,把多个不同类型的变量结合在一起形成的一个组合型变量,称为 结构变量 ,简称 结构 。

10.C51的数据类型有 基本类型 、 构造类型 、 指针类型 、 空类型 。

11.C51的基本数据类型有 位型 、 字符型 、 整形 、 长整形 、 浮点型 、 双精度浮点型 。

12.C51的构造数据类型有 数组类型 、 结构类型 、 共用体型 、 梅举型 。 13.C51的存储类型有 data 、 bdata 、 idata 、 pdata 、 xdata 、 code 。 14.C51的存储模式有 SMALL 、 COMPACT 和 LARGE 。

15.C51程序与其他语言程序一样,程序结构也分为 顺序结构 、 选择结构(或分支结构) 、 循环结构 三种。

16.数组的一个很重要的用途就是 查表 。 17.

二、单项选择题:

1.89S51的内部程序存储器与数据存储器容量各为多少?(C) (A)64KB、 128B ( B)4KB、64KB (C)4KB、128B (D)8KB、256B

2.在8x51芯片里,哪个引脚用于控制使用内部程序存储器还是外部程序存储器?(B) (A)XTAL1 (B)/EA (C)/PSEN (D)ALE 3.下列哪个不是KeilC的预处理命令?(C)

(A)#include (B)#define (C)#exit (D)#if 4.下列哪个不是KeilC的数据类型?(B)

(A)void (B)string (C)char (D)float 5.在8x51的输入/输出端口里,哪个输入/输出端口执行在输出功能时没有内部上拉电阻(A) (A)P0 (B)P1 (C)P2 (D)P3 6.在KeilC的程序里,若要指定P0口的bit3,如何编写?(C)

(A)P0.3 (B)Port0.3 (C)P0^3 (D)Port^3 7.在8x51里,若要扩展外部存储器时,数据总线连接哪个输入/输出端口?(A) (A)P0 (B)P1 (C)P2 (D)P3 8.点亮一般的LED所耗的电流约为多少?(D)

(A)1~5uA (B)10~20uA (C)1~5mA (D)10~20mA

9.在8x51的程序里,若要将个输入/输出端口设置成输入功能,应如何处理?(A) (A)先输出高电平到该输入/输出端口 (B)先输出低电平到该输入/输出端口

(C)先读取该输入/输出端口的状态 (D)先保存该输入/输出端口的状态 10.根据实验统计,当操作开关时,其不稳定关态大约持续多久?(B)

(A)1~5ms (B)10~20ms (C)100~150ms (D)150~250us 11.在KeilC里,判读开关状态时,使用if_else if语句与使用switch语句有何差异?(B) (A)if-else if 语句较快 (B)if-else if语句有优先级 (C)switch语句可判读较多开关状态 (D)switch语句有优先级

12.对于低电平动作(低电平触发)的开关而言,下列哪个不是在输入口上连接一个上拉电阻VCC的目的?(A)

(A)提供足够的驱动电流 (B)防止确定状态 (C)保持输入高电平 (D)防止噪声干扰

13.中断功能具有什么好处?(C) (A)让程序更复杂 (B)让程序执行速度更快 (C)让程序更有效率 (D) 以上皆非

14.8x51的IP缓存器的功能为何?(A)

(A)设置中断优先级 (B)启用中断功能 (C)设置中断触发信号 (D)定义CPU的网址

15.在KeilC里,中断子程序与函数有何不同?(A)

(A)中断子程序不必声明 (B)函数不必声明 (C)中断子程序必须有形式参数 (D)中断子程序一定会有返回值

16.若要同时启用INT0及INT1中断功能,则应如何设置?(B)

(A)TCON=0x81 (B)IE=0x85 (C)IP=0x83 (D)IE=0x03 17.若要提高INT1的优先级,则应如何设置?(C)

(A)IP=0x01 (B)IE=0x01 (C)IP=0x04 (D)IE=0x04

18.在8x51的Timer里,若使用Mode 0,其最大计数值为多少个机器周期?(B) (A)65636 (B)8192 (C)1024 (D)256 19.12 MHz的8x51系统里,哪一种方式一次可定时5ms?(A) (A)Mode0及Mode1 (B)Mode1及Mode2 (C ) Mode2及Mode3 (D) Mode3及Mode1

20.8x51的定时器,在下列哪种方式下具有自动加载功能?(C) (A)Mode0 (B) Mode1 (C)Mode2 (D)Mode3 21.若将Timer0设置为外部启动,则可由哪个引脚启动?(A) (A)P3.2 (B)P3.3 (C)P3.4 (D)P3.5 22.下列哪个IC具有将串行数据转换成并行数据的功能?(B) (A)74138 (B)74164 (C)74165 (D)74168 23.在同一时刻,只能接收或发送信号者称为什么?(A)

(A)半双工 (B)全双工 (C)半单工 (D)单工 24‘在8x51的串行口里,在哪一种方式下,可利用Timer1产生波特率?(C) (A)Mode0 (B)Mode1 (C)Mode2 (D)Mode3

25.在8x51里,若通过串行端口传出数据,则只要将数据放入哪个寄存器,CPU就会自动将它会传出?(B)

(A)SMOD (B)SBUF (C)PCON (D)RBUF

26.在8x51里,若CPU完成串行端口数据的接收将会如何?(D)

(A)将TI标志变为0 (B)将RI标志为0 (C)将TI标志变为了 1 (D)将RI标志变为1

2

27.若要设置8x51串行端口方式,可在哪个寄存器中设置?(B) (A)SMOD (B)SCON (C)PCON (D)TCON 28.在共阳极8*8LED点阵里,其阳极如何连接?(C)

(A)各行阳极连接到行引脚 (B)各列阳极连接到列引脚 (C)各行阳极连接到列引脚 (D)各列阳极连接到行引脚 29.在共阳极8*8点阵里,其阴极如何连接?(A)

(A)各行阴极连接到行引脚 (B)各列阴极连接到列引脚 (C)各行阴极连接到列引脚 (D)各列阴极连接到行引脚 30.通常8*8LED点阵的驱动方式是什么?(B)

(A)直接驱动 (B)扫描驱动 (C)双向驱动 (D)以上皆非 31.若要对LCM下指令,则应如保设置?(A)

(A)RS=0,R/~W=0 (B)RS=1,R/~W=0 (C)RS=1,R/~W=1 (D)RS=0,R/~W=1

32.若要在LCM中显示些字符,则需把所要显示的字符放入何处?(B) (A)CG RAM (B)DDRAM (C)IRAM (D)GDRAM 33.若要将数据写入LCM,则应如何设置?(B)

(A)RS=0,R/~W=0 (B)RS=1,R/~W=0 (C)RS=1,R/~W=1 (D)RS=0,R/~w=1 341.利用下列( D )关键字可以改变工作寄存器组 A、interrupt B、sfr C、while D、using

35.C51中一般指针变量占用( C )字节存储。 A、一个 B、两个 C、三个 D、四个

36.使用宏来访问绝对地址时,一般需包含的库文件是( B ) A、reg51.h B、absacc.h C、intrins.h D、startup.h 37.执行#define PA8255 XBYTE[0x3FFC];

PA8255=0x7e;

后存储单元0x3FFC的值是(A )

A、Ox7e B、8255H C、未定 D、7e

38.设有int a[ ]={10,11,12},*p=&a[0];则执行完*p++;*p+=1;后a[0],a[1],a[2]的值依次是 (C)

A、10,11,12 B、11,12,12 C、10,12,12 D、11,11,12 A、1 B、2 C、3 D、4

三、判断题:(每小题1分,共10分。正确的在括号内打“√”,错误的打“×”。判对得分,不判、判错均不得分。)

1.若一个函数的返回类型为void,则表示其没有返回值。( √ )

2.特殊功能寄存器的名字,在C51程序中,全部大写。(√ ) 3.“sfr”后面的地址可以用带有运算的表达式来表示。( × ) 4.#include 与#include “reg51.h”是等价的。(√ )

5.sbit不可以用于定义内部RAM的可位寻址区,只能用在可位寻址的SFR上。(× ) 6.Continue 和break都可用来实现循环体的中止。( × )

3

7.所有定义在主函数之前的函数无需进行声明。( × ) 8.int i,*p=&i;是正确的C说明。( √ ) 9.7&3+12的值是15。( × )

10.一个函数利用return不可能同时返回多个值。( √ )

四、问答题

1.简述C51语言和汇编语言的比较

使用C51语言进行嵌入式系统的开发,有着汇编语言所不可比拟的优势: ① 编程调试灵活方便; ② 生成的代码编译效率高; ③ 模块化开发; ④ 可移植性好; ⑤ 便于项目的维护;

2.简述单片机的C语言和标准C的比较

答:单片机的C语言和标准C的比较主要有以下几点不同: ① C51中定义的库函数和标准的C语言定义的库函数不同; ② C51中的数据类型和标准C的数据类型也有一定的区别; ③ C51变量的存储模式与标准C中变量的存储模式不一样; ④ C51与标准C的输入/输出处理不一样;

⑤ C51与标准C语言在函数使用方面有一定的区别。

3.简述单片机的C语言的特点

单片机的C语言的特点主要体现在以下几个方面:

① 无需了解机器硬件及其指令系统,只需初步了解MCS-51的存储器结构; ② C51能方便的管理内部寄存器的分配、不同存储器的寻址和数据类型等细节问题,但对硬件控制有限;而汇编语言可以完全控制硬件资源;

③ C51在小应用程序中,产生的代码量大,执行速度慢;但在较大的程序中代码效率高;

④ C51程序由若干函数组成,具有良好的模块化结构,便于改进和扩充;

⑤ C51程序具有良好的可读性和可维护性;而汇编语言在大应用程序开发中,开发难度增加,可读性差;

4

⑥ C51有丰富的库函数,可大大减少用户的编程量,显著缩短编程与调试时间,大大提高软件开发效率;

⑦ 使用汇编语言编制的程序,当机型改变时,无法直接移植使用,而C语言程序是面向用户的程序设计语言,能在不同机型的机器上运行,可移植性好。

4.简述使用KeilC51开发工具开发软件的流程

使用Keil Software工具时,用户的项目开发流程和其它软件开发项目的流程极其相似,主要包括以下几个步骤:

① 创建一个项目,从器件库中选择目标器件并配置工具软件的设置; ② 用C语言或汇编语言创建源程序; ③ 用项目管理器生成用户的应用; ④ 修改源程序中的错误; ⑤ 调试链接后的应用。

一个完整的8051工具集的框图可以很好地表述此开发流程,如图1-1所示。

5

1.哪些变量类型是51单片机直接支持的?

答:C51编译器支持的数据类型有:位型(bit)、无符号字符型(unsigned char)、有符号字符型(signed char)、无符号整型(unsigned int)、有符号整型(signed int)、无符号长整型(unsigned long)、有符号长整型(signed long)、浮点型(float)和指针型等。

C51编译器支持的数据类型、长度和值域如表2-1所示。

表2-1 C51的数据类型

数据类型 bit unsigned char signed char unsigned int signed int unsigned long signed long float double 一般指针 长度/bit 1 8 8 16 16 32 32 32 64 24 长度/byte 1 1 2 2 4 4 4 8 3 值域 0,1 0~255 -128~127 0~65 535 -32 768~32 767 0~4 294 967 295 -2 147 483 648~2 147483 647 ±1.176E-38~±3.40E+38(6位数字) ±1.176E-38~±3.40E+38(10位数字) 存储空间 0~65 535

2.简述C51的数据存储类型

答:我们都知道,8051单片机存储区可分为内部数据存储区、外部数据存储区以及程序存储区。8051单片机内部的数据存储区是可读写的,8051派生系列最多可有256字节的内部数据存储区,其中低128字节可直接寻址,高128字节(从0x80到0xFF)只能间接寻址,从20H开始的16字节可位寻址。内部数据区可分为3个不同的存储类型:data、idata和bdata。

外部数据区也是可读写的,访问外部数据区比访问内部数据区慢,因为外部数据区是通过数据指针加载地址来间接访问的。C51提供两种不同的存储类型xdata和pdata访问外部数据。

6

程序存储区是只能读不能写。程序存储区可能在8051单片机内部或者在外部或者内外都有,这由8051单片机的硬件决定。C51提供了code存储类型来访问程序存储区。

每个变量可以明确地分配到指定的存储空间,对内部数据存储器的访问比对外部数据存储器的访问快许多,因此应当将频繁使用的变量放在内部存储器中,而把较少使用的变量放在外部存储器中。各存储区的简单描述如表2-2所示。

表2-2 C51存储类型与8051存储空间的对应关系

存储区 DATA BDATA IDATA XDATA 描述 片内RAM的低128字节,可在一个周期内直接寻址 片内RAM的位寻址区,16字节 片内RAM的256字节,必须采用间接寻址 外部数据存储区,使用DPTR间接寻址 外部存储区的256个字节,通过P0口的地址对其寻址。使用MOVX @Ri,需PDATA 要两个指令周期 CODE 程序存储区,使用DPTR寻址。

以上介绍的是C51的数据存储类型,C51存储类型及其大小和值域如表2-3所示。

表2-3 C51存储类型及其大小和值域

存储类型 data idata pdata code xdata

长度/bit 8 8 8 16 16 长度/byte 1 1 1 2 2 值域 0~255 0~255 0~255 0~65 535 0~65 535 3.简述C51对51单片机特殊功能寄存器的定义方法

答:MCS-51通过其特殊功能寄存器(SFR)实现对其内部主要资源的控制。MCS-51单片机有21个SFR,有的单片机还有更多的SFR,它们分布在片内RAM的高128字节中,其地址能够被8整除的SFR一般可以进行位寻址。关于MCS-51单片机的特殊功能寄存器参看附录A。对SFR只能用直接寻址方式访问。C51允许通过使用关键字sfr、sbit或直接引用编

7

译器提供的头文件来实现对SFR的访问。 (1)使用关键字定义sfr

为了能直接访问特殊功能寄存器SFR,C51提供了一种自主形式的定义方法。这种定义方法与标准的C语言不兼容,只适用于对8051系列单片机进行C编程。这种定义的方法是引入关键字“sfr”,语法如下:

sfr 特殊功能寄存器名字 = 特殊功能寄存器地址; 如:

sfr SCON=0x98; sfr TMOD=0X89;

/*串口控制寄存器地址98H*/

/*定时器/计数器方式控制寄存器地址89H*/

(2)通过头文件访问SFR

8051系列单片机的寄存器数量与类型是极不相同的,因此对单片机特殊功能寄存器的访问可以通过对头文件的访问来进行。

为了用户处理方便,C51编译器把MCS-51单片机的常用的特殊功能寄存器和特殊位进行了定义,放在一个“reg51.h”或“reg52.h”的头文件中。当用户要使用时,只需要在使用之前用一条预处理命令“#include ”把这个头文件包含到程序中,然后就可以使用特殊功能寄存器名和特殊位名称了。用户可以通过文本编辑器对头文件进行增减。 (3)SFR中位定义

在8051单片机的应用问题中,经常需要单独访问SFR中的位,C51的扩充功能使之成为可能,使用关键字“sbit”可以访问位寻址对象。特殊位(sbit)的定义,像SFR一样不与标准C兼容。

与SFR定义一样,用关键字“sbit”定义某些特殊位,并接受任何符号名,“=”号后将绝对地址赋给变量名。这种地址分配有三种方法:

第一种方法:

sbit 位名=特殊功能寄存器名^位置;

当特殊功能寄存器的地址为字节(8位)时,可使用这种方法。特殊功能寄存器名必须是已定义的SFR的名字。“^”后的“位置”语句定义了基地址上的特殊位的位置。该位置必须是0~7的数。如:

第二种方法:

sbit 位名=字节地址^位置;

这种方法是以一个整常数为基地址,该值必须在0x80~0xFF之间,并能被8整除,确

8

定位置的方法同上。

第三种方法: sbit 位名=位地址;

这种方法将位的绝对地址赋给变量,地址必须在0x80~0xFF之间。

4.简述C51对51单片机片内I/O口和外部扩展的I/O口的定义方法

答:

C51对51单片机片内I/O口的定义方法是将片内I/O口看成SFR。 C51对51单片机片外I/O的访问有两种比较常用的访问方法: (1)绝对宏

C51编译器提供了一组宏定义来对51系列单片机的code、data、pdata和xdata空间进行绝对寻址。在程序中,用“#include”即可使用其中声明的宏来访问绝对地址,包括CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD,具体使用方法参考absacc.h头文件。其中:

CBYTE以字节形式对code区寻址;CWORD以字形式对code区寻址; DBYTE以字节形式对data区寻址;DWORD以字形式对data区寻址; XBYTE以字节形式对xdata区寻址;XWORD以字形式对xdata区寻址; PBYTE以字节形式对pdata区寻址;PWORD以字形式对pdata区寻址; (2)_at_关键字

可以使用关键字_at_对指定的存储器空间的绝对地址进行访问,一般格式如下: [存储器类型] 数据类型说明符 变量名 _at_地址常数;

其中,存储器类型为C51能识别的数据类型,如省略则按存储器模式规定的默认存储器类型确定变量的存储器区域;数据类型为C51支持的数据类型;地址常数用于指定变量的绝对地址,必须位于有效的存储器空间之内;使用_at_定义的变量必须为全局变量。

5.简述C51对51单片机位变量的定义方法

答:除了通常的C数据类型外,C51编译器支持bit数据类型。 采用关键字“bit”进行定义。如: bit direction_bit; bit lock_pointer;

/* 将direction_bit定义为位变量 */ /* 将lock_pointer定义为位变量 */

9

bit display_invers; /* 将display_invers定义为位变量 */

6.C51 和Turbo C 的数据类型和存储类型有哪些异同点?

答:C51增加了位变量,取消了布尔变量。

7.C51 的data、bdata、idata 有什么区别?

答:data、bdata、idata是表明数据的存储类型, data是指片内RAM的低128字节,可在一个周期内直接寻址; bdata是指片内RAM的位寻址区,16字节;

idata是指片内RAM的256字节,必须采用间接寻址。

8.C51中的中断函数和一般的函数有什么不同?

答:C51编译器允许用C51创建中断服务函数,中断函数是由中断系统自动调用的。 中断函数的定义格式为:

函数类型 函数名 interrupt n using n 其中:

interrupt和using为关键字;

interrupt后面的n 为中断源的编号,即中断号; using后面的n所选择的寄存器组,取值范围为0~3。

定义中断函数时,using是一个选项,可以省略不用。如果不用using选项,则由编译

器选择一个寄存器组作为绝对寄存器组。

8051的中断过程通过使用interrupt关键字和中断号(0~31)来实现,中断号告诉编译器中断函数的入口地址。

9.C51采用什么形式对绝对地址进行访问?

答:绝对地址的访问包括片内RAM、片外RAM及I/O的访问。C51提供了两种比较常用的访问绝对地址的方法。

(1)绝对宏

C51编译器提供了一组宏定义来对51系列单片机的code、data、pdata和xdata空间进行绝对寻址。在程序中,用“#include”即可使用其中声明的宏来访问绝对地址,包括CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD,具体使

10

用方法参考absacc.h头文件。其中:

CBYTE以字节形式对code区寻址;CWORD以字形式对code区寻址; DBYTE以字节形式对data区寻址;DWORD以字形式对data区寻址; XBYTE以字节形式对xdata区寻址;XWORD以字形式对xdata区寻址; PBYTE以字节形式对pdata区寻址;PWORD以字形式对pdata区寻址; 如:

#include

#define PORTA XBYTE[0xFFC0]/*将PORT定义为外部I/O口,地址为0xFFC0,长度为8位*/

#define NRAM DBYTE[0x40] /*将NRAM定义为片内RAM,地址为40H,长度为8位*/

(2)_at_关键字

可以使用关键字_at_对指定的存储器空间的绝对地址进行访问,一般格式如下: [存储器类型] 数据类型说明符 变量名 _at_地址常数;

其中,存储器类型为C51能识别的数据类型,如省略则按存储器模式规定的默认存储器类型确定变量的存储器区域;数据类型为C51支持的数据类型;地址常数用于指定变量的绝对地址,必须位于有效的存储器空间之内;使用_at_定义的变量必须为全局变量。

10.按照给定的数据类型和存储类型,写出下列变量的说明形式

答:

(1)在data区定义字符变量val1

char data vall;

(2)在idata区定义整型变量val2

int idata val2;

(3)在xdata区定义无符号字符型数组val3[4]。 unsigned xdata val3[4];

(4)在xdata区定义一个指向char类型的指针px。 char xdata *px;

(5)定义可位寻址变量flag。

bit flag;

11

(6)定义特殊功能寄存器变量P3。

Sfr P3=0xB0;

11.break和continue语句的区别是什么?

答:break语句用于从循环代码中退出,然后执行循环语句之后的语句,不再进入循环。 Continue语句用于退出当前循环,不再执行本轮循环,程序代码从下一轮循环开始执

行,直到判断条件不满足为止。

和break的区别是该语句不是退出整个循环。

12.C51选择语句、循环语句包含那些?

答:参看课本P68~P77。

13.什么是重入函数?重入函数一般什么情况下使用,使用时有哪些需要注意的地方?

答: 多个函数可以同时使用的函数,称为重入函数。

通常情况下,C51函数不能被递归调用,也不能应用导致递归调用的结构。有此限制是由于函数参数和局部变量是存储在固定的地址单元中。重入函数特性允许你声明一个重入函数。即可以被递归调用的函数。 重入函数可以被递归调用,也可以同时被两个或更多的进程调用。重入函数在实时应用中及中断服务程序代码和非中断程序代码必须共用一个函数的场合中经常用到。

14.如何消除键盘的抖动?

答:由于按键是机械开关结构,所以当用手按下其中一个键时,往往会出现所按键在闭合位置和断开位置之间发生跳几下后才会稳定到闭合状态的情况。在释放一个键时,也会出现类似的情况,这就是键的抖动,抖动的持续时间不一,但通常不会大于10ms。 若抖动问题不解决,就会引起对闭合键的多次读入。对于键抖动最方便的解决方法就是当发现有键按下后,不是立即进行扫描,而是延时大约10ms后再进行。由于一个键按下的时间一般会持续上百毫秒,所以延迟10ms后再扫描处理并不迟。

15.在使用8051的定时器/计数器前,应对它进行初始化,其步骤是什么?

答: (1)确定T/C的工作方式——编程TMOD寄存器; (2)计算T/C中的计数初值,并装载到TH和TL;

(3)T/C在中断方式工作时,须开CPU中断和源中断——编程IE寄存器; (4)启动定时器/计数器——编程TCON中TR1或TR0位。

16.外部中断源初始化步骤是什么?

外部中断源初始化 2个外部中断源:

/INT0中断,外部中断0请求,占用P3.2引脚,其中断请求号为0。 /INT1中断,外部中断1请求,占用P3.3引脚,其中断请求号为2。 (1)TCO寄存器中的IT0、IT1位

12

(2)IP寄存器中的PX0、PX1位

(3)IE寄存器中的EA、EX0、EX1位

五、读程序、编程序

1.第四章 中断:例4-1 P104 例4-9 P116 例4-10 P117 定时:例4-16 P123 例4-17 P124 例4-18 P126 2.第五章 例5-9 P154 例5-10 P155 例5-11 P157 3.第六章 静态: 例6-1 P169 动态: 例6-3 P171 独立式键盘:例6-6 P178 矩阵式键盘:例6-7 P181 LED阵列:例6-10 P187 LCD1602:例6-12 P194 4.第七章 D/A:例7-4 P208 A/D:例7-6 P213

第四章

例4-1 P104

假设外部中断0和外部中断1均为下降沿触发,当外部中断0发生时,P0端口的电平反向,当外部中断1发生时,P1端口的电平反向。

中断类

13

#include

void IS0(void) interrupt 0 { P0=~P0;} //P0端口反向 void IS1(void) interrupt 2 { P1=~P1;} //P1端口反向 void main( )

{ P0=0x00; P1=0xFF; IT0=1; IT1=1; EX0=1; EX1=1; EA=1; while(1); }

【例4-9】外部中断示例

在本实例中,首先通过P1.7口点亮发光二极管D1,然后外部输入一脉冲串,则发光二极管D1亮、暗交替。

14

#include sbit P1_7=P1^7;

void interrupt0( ) interrupt 0 using 2 //外部中断0 { P1_7=!P1_7;} void main( )

{ EA=1; //开中断

IT0=1; //外部中断0脉冲触发 EX0=1; //外部中断0

P1_7=0; do{ }while(1); }

如果有3个脉冲,则灯亮、暗交替一次,可如下面编程: #include

15

Sbit P17=P1^7; unsigned char i=3; void main( )

{ EA=1; IT0=1; EX0=1; P17=0; do{ }while(1); }

void interrupt0( ) interrupt 0 { i=i-1; if(i==0)

{ P17=!P17; i=3; } }

【例4-10】如图4-18所示,8只LED阴极接至单片机P0口,两开关S0、S1分别接至单片机引脚P3.2()和P3.3()。编写程序控制LED状态。按下S0后,点亮8只LED;按下S1后,变为闪烁状态。

16

#include sbit P32=P3^2;

void delay(unsigned int d) //定义延时子函数 { while(--d>0); }

void main( )

{ P0=0xFF; //熄灭LED

IT0=1; IT1=1; //外中断0、1脉冲触发方式 EA=1; EX0=1; EX1=1; //开中断 for( ; ; ) //延时等待中断发生 {;} }

void INT0_ISR( ) interrupt 0//外中断0中断服务函数

17

{ P0=0x00; }

void INT1_ISR( ) interrupt 2//外中断1中断服务函数 { while(P32!=0) //如果有外部中断0,则退出 { delay(5000); P0=0x00; delay(5000); P0=0xFF; } } 定时类

【例4-16】设单片机的fosc=12MHz,要求在P1.0上产生周期为2ms的方波。

要在P1.0上产生周期为2ms的方波,定时器应产生1ms的周期性定时,定时到对P1.0取反。

要产生1ms的定时,应选择方式1,定时器方式。

TMOD的确定:选择定时器/计数器T0,定时器方式。方式1,GATE不起作用,高4位为0000,TMOD=01H。

TH、TL的确定:单片机的fosc=12MHz,则单片机的机器周期为1ms,1ms=1000ms,计数器的计数初值为65 536-1000,TH0=(65 536-1000)/256,TL0=(65 536-1000)%6。 ① 采用查询方式

18

程序如下: #include sbit P1_0=P1^0; void main(void) { TMOD=0x01; TR0=1; for(;;)

{ TH0=(65536-1000)/256; TL0=(65536-1000)%6; do{ }while(!TF0); P1_0=!P1_0; TF0=0; } }

② 采用中断方式 程序如下: #include sbit P1_0=P1^0;

void timer0(void) interrupt 1 using 1 { P1_0=!P1_0;

TH0=(65536-1000)/256; TL0=(65536-1000)%6;

19

}

void main(void) { TMOD=0x01; P1_0=0;

TH0=(65536-1000)/256; TL0=(65536-1000)%6; EA=1; ET0=1; TR0=1;

do{ } while(1); }

【例4-17】设系统时钟频率为12MHz,编程实现从P1.1输出周期为1s的方波。

要输出周期为1s的方波,应产生500ms的周期性定时,定时到则对P1.1取反即可实现。

20

由于定时时间较长,一个定时器/计数器不能直接实现,一个定时器/计数器最长定时时间为65ms多一点,可以用以下两种方法实现。 (1)方法一

用定时/计数器T0产生周期性为10ms的定时,然后用一个变量对10ms计数50次。系统时钟为12MHz,定时/计数器T0定时10ms,计数值N为10000,选方式1,方式控制字为00000001B(01H),则初值X为X=65 536-10 000。

AU1171615141312111028272625242322213233343536373839P3.7/RDP3.6/WRP3.5/T1P3.4/T0P3.3/INT1P3.2/INT0P3.1/TXDP3.0/RXDP2.7/A15P2.6/A14P2.5/A13P2.4/A12P2.3/A11P2.2/A10P2.1/A9P2.0/A8P0.7/AD7P0.6/AD6P0.5/AD5P0.4/AD4P0.3/AD3P0.2/AD2P0.1/AD1P0.0/AD0AT89C51P1.7P1.6P1.5P1.4P1.3P1.2P1.1P1.087654321BEAALEPSEN313029VCCRST9D1XTAL218R2470RXTAL119D0R1470R #include sbit P1_1=P1^1;

unsigned char i; //定义计数变量 void main( )

21

{ i=0; //初始化 TMOD=0x01;

TH0=(65536-10000)/256; TL0=(65536-10000)%6; EA=1; ET0=1; TR0=1; while(1); }

void time0_int(void) interrupt 1 //中断服务程序 { TH0=(65536-10000)/256; //重载初始值 TL0=(65536-10000)%6; //重载初始值

i++; //每发生一次中断,计数变量加1 if (i==50) //发生50次中断,定时0.5ms { P1_1=!P1_1;

i=0; //计数变量清零 } } (2)方法二

用定时/计数器T1计数实现,对10ms计数50次。定时/计数器T1工作于计数方式时,计数脉冲通过T1(P3.5)输入。设定时/计数器T0定时时间到对P1.0取反一次,则T1(P3.5)每10ms产生一

22

个计数脉冲,那么定时500ms只需计数25次,设定时/计数器T1工作于方式2,初值X=256-25=231,TH1=TL1=231。因为定时/计数器T0工作于方式1,定时方式,则这时方式控制字为01100001B(61H)。定时/计数器T0和T1都采用中断方式工作。

U1171615141312111028272625242322213233343536373839P3.7/RDP3.6/WRP3.5/T1P3.4/T0P3.3/INT1P3.2/INT0P3.1/TXDP3.0/RXDP2.7/A15P2.6/A14P2.5/A13P2.4/A12P2.3/A11P2.2/A10P2.1/A9P2.0/A8P0.7/AD7P0.6/AD6P0.5/AD5P0.4/AD4P0.3/AD3P0.2/AD2P0.1/AD1P0.0/AD0AT89C51P1.7P1.6P1.5P1.4P1.3P1.2P1.1P1.087654321VCCD1R2470REAALEPSEN313029A9B18RSTXTAL2XTAL119 #include sbit P1_1=P1^1; sbit P1_0=P1^0; void main( )

{ TMOD=0x61; //初始化 TH0=(65536-10000)/256; TL0=(65536-10000)%6; TH1=231;TL1=231; EA=1; ET0=1; ET1=1; TR0=1; TR1=1;

23

while(1); }

void time0_int(void) interrupt 1 //T0中断服务程序 { TH0=(65536-10000)/256; //重载初始值 TL0=(65536-10000)%6; //重载初始值 P1_0=!P1_0; }

void time1_int(void) interrupt 3 //T1中断服务程序 { P1_1=!P1_1; }

【例4-18】设系统时钟频率为12MHz,编程实现:P1.1引脚上输出周期为1s,占空比为20%的脉冲信号

根据输出要求,脉冲信号在一个周期内高电平占0.2s,低电平占0.8s,超出了定时器的最大定时间隔,因此利用定时器0产生一个基准定时配合软件计数来实现。取50ms作为基准定时,采用工作方式1,这样这个周期需要20个基准定时,其中高电平占4个基准定时。 #include sbit P1_1=P1^1;

unsigned char i; //定义计数变量 void main( )

{ i=0; //初始化 TMOD=0x01;

TH0=(65536-50000)/256;

24

TL0=(65536-50000)%6; EA=1; ET0=1; TR0=1; while(1); }

void time0_int(void) interrupt 1 //中断服务程序 { TH0=(65536-50000)/256; //重载初始值 TL0=(65536-50000)%6; i=i+1;

if(i==4) P1_1=0; //高电平时间到变低 else if(i==20) //周期时间到变高 { P1_1=1;

i=0; //计数变量清零 } }

25

{ uchar i; do

{ SBUF=0xAA; //发送联络信号 while(TI= =0); //等待一帧发送完毕 TI=0; //发送完毕,标志位清0 while (RI= =0); //等待乙机应答信号 RI=0;

} while (SBUF^0xBB!=0); //乙机未准备好,继续联络 do

{ pf=0; //校验和变量清0 for(i=0;i<10;i++){

SBUF=d[i]; //发送一个数据 pf+=d[i]; //计算校验和 while(TI= =0); TI=0;}

SBUF=pf; //发送校验和 while (TI= =0);TI=0;

while (RI= =0);RI=0; //等待乙机应答 }while (SBUF!=0); //回答出错,则重新发送 }

/*接收函数*/

void receive(uchar idata*d)

31

{uchar i; do

{ while(RI= =0); RI=0;

}while(SBUF^0xAA)!=0); //判断甲机是否请求 SBUF=0xBB; //发应答信号 while(TI= =0);TI=0; while(1){

pf=0; //清校验和 for(i=0;i<10;i++){

d[i] = SBUF; //接收数据 pf+=d[i];} //计算校验和 while(RI= =0);RI=0; //接收甲校验和 If((SBUF^pf)= =0){ //比较校验和 SBUF=0x00;break;} //校验和相等,发0x00 else{

SBUF=0xFF; //校验和不相等,发0Xff while(TI= =0);TI=0;

} } }

第六章

静态:【例6-1】利用单片机的并行口作为静态显示的输出口的示例

32

静态轮流显示“12”、“- -”和“AB”的C51源程序如下: #include #define uchar unsigned char uchar data dis_buf[2];//显示缓冲区 uchar code able[18]=

{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00}; void dl( ) { unsigned int i;

for(i=0;i<40000;i++); }

void display(void) //显示函数 { uchar segcode;

segcode=dis_buf[0];//P0口显示

33

//显示的代码表

segcode=table[segcode]; P0=segcode;

segcode=dis_buf[1]; //P3口显示 segcode=table[segcode]; P3=segcode; }

void main(void) //主函数 { while(1)

{ dis_buf[0]=1;dis_buf[1]=2; //显示12 display( ); dl();

dis_buf[0]=16;dis_buf[1]=16;//显示- - display( ); dl( );

dis_buf[0]=10;dis_buf[1]=11;//显示AB display( ); dl( ); } }

示例中的显示函数display( )可以再简单一些,如下面程序段: void display(void)

{ P0=table[dis_buf[0]]; //P0口显示 P3=table[dis_buf[1]]; //P3口显示 }

动态:【例6-3】利用MCS-51单片机的并行口作为动态显示的段口与

34

位口的示例

6位数码管动态显示“123456”的C51源程序如下 1)随机调用 #include #define uchar unsigned char uchar data dis_buf[6];//显示缓冲区 uchar code table[18]=

{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00};//代码表 void dl_ms() //延时1ms函数 { unsigned int j; for(j=0;j<200;j++) ; }

void display(void)//显示函数 { uchar segcode, bitcode, i;

35

bitcode=0xfe; //位码赋初值 for(i=0;i<6;i++)

{ segcode=dis_buf[i];//显示缓冲器内容查表 P0=table[segcode]; P3=bitcode; dl_ms( ); P3=0xff; //关闭显示

bitcode=bitcode<<1; //调整位码 bitcode=bitcode|0x01; } }

void main(void)

{ dis_buf[0]=1; dis_buf[1]=2; dis_buf[2]=3; dis_buf[3]=4; dis_buf[4]=5;dis_buf[5]=6; while(1) { display( ); } }

(2)定时调用

定时调用是通过定时器/计数器的定时功能来定时一定的时间(如20ms),定时时间到来调用显示函数。 void main(void) //定时调用 { TMOD=0x01;

36

TH0=-20000/256; TL0=-2000%6; EA=1;ET0=1; TR0=1;

dis_buf[0]=1;dis_buf[1]=2;dis_buf[2]=3; void time0_int( ) interrupt 1 { TH0=-20000/256; TL0=-2000%6; display( ); }

dis_buf[3]=4;dis_buf[4]=5;dis_buf[5]=6; while(1) ; }

【例6-6】独立式按键示例

C51源程序如下: #include

37

#define uchar unsigned char #define uint unsigned int uchar data key2; code uchar

dirtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80}; void dl_6( ) { uint i;

for(i=0;i<600;i++); }

void key( ) { uchar key1; P1=0xff; key1=P1; if(key1!=0xff)

{ dl_6( ); P1=0xff;key1=P1; if(key1!=0xff) { key1=P1; switch(key1)

{ case 0xff: key2=8; break; case 0xfe: key2=0; break; case 0xfd: key2=1; break; case 0xfb: key2=2; break;

38

case 0xf7: key2=3; break; case 0xef: key2=4; break; case 0xdf: key2=5; break; case 0xbf: key2=6; break; case 0x7f: key2=7; break; default:break; } } } }

void main( ) { key2=8; while(1) { key( );

P3=dirtab[key2]; } }

6-7】 4×4矩阵键盘示例

39

【例

#include

#define uchar unsigned char #define uint unsigned int uchar data dir_buf; code uchar

dirtab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40}; code uchar

keytab[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7, 0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77}; void delay(void); void keyscan( ); void dir( ); uchar key; void main(void)

40

本文来源:https://www.bwwdw.com/article/kij6.html

Top