文档库 最新最全的文档下载
当前位置:文档库 › 单片机课后习题答案

单片机课后习题答案

习题 3
1.结合MCS-51系列单片机功能框图阐明其大致组成。
答: MCS-51系列单片机内部组成如图所示。
主要有 8031、8051、875l 三种机型,基于 HMOS 工艺,它们的指令系统与芯片引脚完
全兼容,只是片内程序存储器(ROM, Read Only Memory)有所不同。
51子系列的主要功能为:
● 8位CPU;
● 片内带振荡器及时钟电路;
● 128B片内数据存储器;
● 4KB片内程序存储器(8031/80C31无) ;
● 程序存储器的寻址范围为64KB;
● 片外数据存储器的寻址范围为64KB;
● 21B特殊功能寄存器;
● 4×8根I/O线;
● 1个全双工串行I/O接口,可多机通信;
● 两个16位定时器/计数器;
● 中断系统有5个中断源,可编程为两个优先级;
● 111条指令,含乘法指令和除法指令;
● 布尔处理器;
● 使用单+5V电源。
2.综述80C51系列单片机各引脚的作用。
答: 80C51 有 4 个 8 位并行 I/O 口,共 32 条端线: P0、P1、P2 和 P3 口。每一个 I/O 口都能用作输入或输出。
用作输入时,均须先写入“1” ;用作输出时,P0口应外接上拉电阻。
P0口的负载能力为8个LSTTL门电路; P1~P3口的负载能力为4个LSTTL门电路。
在并行扩展外存储器或I/O口情况下:
P0口用于低8位地址总线和数据总线(分时传送)
P2口用于高8位地址总线,
P3口常用于第二功能,
用户能使用的I/O口只有P1口和未用作第二功能的部分P3口端线。
3.80C51单片机内部包含哪些主要逻辑功能部件?各有什么主要功能?
答: 80C51 单片机内部包含含布尔(位)处理器的中央处理器、数据存储器和程序、并行输入/输出端口、中断系统、定时器/计数器,串行口、时钟电路、复位电路。
4.什么是ALU?简述MCS-51系列单片机ALU的功能与特点。
答: ALU是用于对数据进行算术运算和逻辑操作的执行部件,由加法器和其他逻辑电路(移位电路和判断电路等)组成。在控制信号的作用下,它能完成算术加、减、乘、除和逻辑与、或、异或等运算以及循环移位操作、位操作等功能。
5.如何认识:80C51存储器空间在物理结构上可划分为4个空间,而在逻辑上又可划分
为3个空间?
答:而 80C51 在物理结构上有 4 个存储空间:片内程序存储器、片外程序存储器、片内数据存储器和片外数据存储器。但在逻辑上,即从用户使用的角度上,80C51 有三个存储空间:片内外统一编址的64KB程序存储器地址空间(用16位地址) 、256 B片内数据存储器的地址空间(用8位地址)及64KB片外数据存储器地址空间(用16位地址)。在访问三个不同的逻辑空间时,应采用不同形式的指令(见指令系统),以产生不同的

存储空间的选通信号。
6.什么是指令?什么是程序?简述程序在计算机中的执行过程。
答:指令由操作码和操作数构成,分别表示何种操作和操作数的存储地址;
而程序则是:程序是可以连续执行,并能够完成一定任务的一条条指令的集合。
程序执行是由控制器控制的,控制器是CPU的大脑中枢,它包括定时控制逻辑、指令寄
存器IR、数据指针DPTR及程序计数器PC、堆栈指针SP、地址寄存器、地址缓冲器等。它的功能是对程序的逐条指令进行译码,并通过定时和控制电路在规定的时刻发出各种操作所需的内部和外部控制信号,协调各部分的工作,完成指令规定的操作。
7. 什么是堆栈?堆栈有何作用?在程序设计时,有时为什么要对堆栈指针SP重新赋值?
如果CPU在操作中要使用两组工作寄存器,你认为SP的初值应为多大?
答: 堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场。
它的特点是按照先进后出的原则存取数据,这里的进与出是指进栈与出栈操作。
80C51片内RAM的部分单元可以用做堆栈。有一个8位的堆栈指针寄存器SP,专用于
指出当前堆栈顶部是片内RAM的哪一个单元。80C51单片机系统复位后SP的初值为07H,
也就是将从内部 RAM 的 08H 单元开始堆放信息。但是,80C51 系列的栈区不是固定的,只要通过软件改变 SP寄存器的值便可更动栈区。为了避开工作寄存器区和位寻址区,SP 的初值可置为2FH或更大的地址值。
如果CPU在操作中要使用两组工作寄存器,如果不使用位变量, SP的初值至少应为0FH
或更大的值;如果使用位变量,SP 的初值至少应为 2FH 或更大的值;Keil C51 编译器会自动计算SP的初始设定值,无需编程者关心。
8.程序状态寄存器PSW的作用是什么?常用状态标识有哪几位?作用是什么?
答: PSW 是 8 位寄存器,用做程序运行状态的标识。
表4.7 PSW寄存器各位名称及地址
地址 D7H D6H D5H D4H D3H D2H D1H D0H
名称 C AC F0 RS1 RS0 OV F1 P
当CPU进行各种逻辑操作或算术运算时,为反映操作或运算结果的状态,把相应的标识
位置位或清 0。这些标识的状态,可由专门的指令来测试,也可通过指令读出。它为计算机
确定程序的下一步运行方向提供依据。PSW寄存器中各位的名称及地址如表4.7所示,下面
说明各标识位的作用。
●P:奇偶标识。该位始终跟踪累加器A的内容的奇偶性。如果有奇数个1,则置P为1,否则清0。在80C5l的指令系统中,凡是改变累加器A中内容的指令均影响奇偶标识位P。
● F1:用户标识。由用户置位或复位。
●OV:溢出标识。有符号数运算时,如果发

生溢出,OV置1,否则清0。对于1B的有
符号数,如果用最高位表示正、负号,则只有 7 位有效位,能表示-128~+127 之间
的数。如果运算结果超出了这个数值范围,就会发生溢出,此时,OV = l,否则OV
= 0。在乘法运算中,OV = l表示乘积超过 255;在除法运算中,OV = l表示除数为 0。
● RS0、RSl:工作寄存器组选择位。用于选择指令当前工作的寄存器组。由用户用软
件改变RS0 和RSl的组合,以切换当前选用的工作寄存器组,单片机在复位后, RS0
= RSl = 0,CPU自然选中第0组为当前工作寄存器组。根据需要,用户可利用传送指
令或位操作指令来改变其状态,这样的设置为程序中快速保护现场提供了方便。
●F0:用户标识位,同F1。
● AC:半进位标识。当进行加法(或减法)运算时,如果低半字节(位 3)向高半字
节(位 4)有进位(或借位) ,AC置 1,否则清 0。AC也可用于BCD码调整时的判别
位。
● CY:进位标识。在进行加法(或减法)运算时,如果操作结果最高位(位 7)有进
位,CY置1,否则清0。在进行位操作时,CY又作为位操作累加器C。
9.在 80C51 扩展系统中,片外程序存储器和片外数据存储器共处同一地址空间为什么
不会发生总线冲突?
答: 在80C51扩展系统中,片外程序存储器和片外数据存储器虽然共处同一地址空间,但是在物理上是两个独立的存储空间,这两个空间都使用相同的16位地址线和8位数据线,分别为两个64KB的寻址空间,它们的选通控制信号不同。程序存储器使用PSEN 作为取指令控制信号,数据存储器使用WR 、RD作为存取数据控制信号。所以不会发生总线冲突。
从指令周期角度来看,取指令周期访问片外程序存储器,PSEN 有效,执行指令周期则存
取数据,WR 、RD信号有效,访问的是片外数据存储器。
11.阐明“准双向口”这一名词之所以要加“准”字的理由。
答: ① 80C51的32条I/O线隶属于4个8位双向端口,每个端口均由锁存器(即特殊功能寄存器P0~P3) 、输出驱动器和输入缓冲器组成;
② P1、P2 和 P3 口均有内部上拉电阻,当它们用做通用 I/O 时,在读引脚状态时,各口
对应的锁存器必须置1,所以为准双向口;
③ P0口内部无上拉电阻,作为I/O口时,必须外部上拉电阻到电源。在读引脚状态时,
各口对应的锁存器必须置1,所以为准双向口;
80C51的32条I/O在读引脚状态时,各口对应的锁存器必须置1,即先写1,保证锁存器
的输出为1,然后再读引脚,方可读到正确的引脚状态。所以为准双向口。
12.何谓时钟周期、机器周期、指令周期?80C51 的时钟周期、机器周期、指令周期是
如何分配的

?当振荡频率为8MHz时,一个单片机机器周期为多少微秒?
答: 为了便于对CPU时序进行分析,人们按指令的执行过程规定了几种周期,即时钟周期、状态周期、机器周期和指令周期,也称为时序定时单位,下面分别予以说明。
时钟周期也称为振荡周期,定义为时钟脉冲频率(fosc)的倒数,是计算机中最基本、
最小的时间单位。
时钟周期经2分频后成为内部的时钟信号,用做单片机内部各功能部件按序协调工作的
控制信号,称为状态周期,用S表示。这样一个状态周期就有两个时钟周期,前半状态周期相应的时钟周期定义为P1,后半周期对应的节拍定义为P2。
完成一个基本操作所需要的时间称为机器周期,也称CPU周期。80C51有固定的机器周
期,规定一个机器周期有6个状态,分别表示为S1~S6,而一个状态包含两个时钟周期,那么一个机器周期就有12个时钟周期。
所以当振荡频率为8MHz时,
机器周期为 12×1/8MHZ=12×0.125μs=1. 5μs
13.复位的作用是什么?有几种复位方法?复位后单片机的状态如何?
答: 复位是单片机的初始化操作。单片机系统在上电启动运行时,都需要先复位,其作用是使CPU和系统中其他部件都处于一个确定的初始状态,并从这个状态开始工作。
单片机的外部复位电路有上电自动复位和按键手动复位两种。
当80C51通电,时钟电路开始工作,在80C51单片机的RST(DIP40封装第9脚)引脚
加上大于24个时钟周期以上的正脉冲,80C51单片机系统即初始复位。初始化后,程序计数器PC指向0000H,P0~P3输出口全部为高电平,堆栈指针写入07H,其他专用寄存器被清0。RST由高电平下降为低电平后,系统从0000H地址开始执行程序。
14.80C51有几种低功耗方式?如何实现?
答: 80C51 单片机除具有一般的程序执行方式外,还具有两种低功耗运行方式:待机(或称空闲)方式和掉电(或称停机)方式,备用电源直接由 VCC 端输入。第一种方式可使功耗减小,电流一般为1.7~5mA;第二种方式可使功耗减到最小,电流一般为5~50μA。可见,CHMOS型单片机特别适合于低功耗应用场合。
15. 何谓单片机最小系统?请分别画出由80C32单片机和89C52单片机组成的最小系统。
答: 单片机最小系统就是能使单片机工作的最少的器件构成的系统,是大多数控制系统必不可少的关键部分。80C32单片机和89C52单片机组成的最小系统如图4.2和图4.3所示。
习题4
1.80C51的指令系统具有哪些特点?
答 80C51指令系统由49条单字节指令、45条双字节指令和17条三字节指令组成,这样可以提高程序存储器的使用效率。对于大多数算术、逻辑运算和转移操作

,可选用短地址或长地址指令实现,以提高运算速度、编程效率和节省存储器单元。在111条指令中,有64条指令的执行时间为12个振荡器周期 (1个机器周期) , 45条为24个振荡器周期 (2个机器周期) ,
只有乘、除法指令需48个振荡周期(4个机器周期) 。当主频为12MHz时,典型指令的执行时间为1μs,运算速度是比较快的。
2.80C51单片机的指令系统按其功能可归纳为几大类?请写出各类名称。
答: 80C51单片机指令系统操作码助记符按功能可分为五大类。
(1)数据传送类指令(7种助记符)
(2)算术运算类指令(8种助记符)
(3)逻辑运算类指令(10种助记符)
(4)控制转移类指令(18种助记符)
(5)位操作指令(1种助记符)
3.何为寻址方式?80C51单片机有哪些寻址方式?
答: 80C51 单片机共有 7 种寻址方式:
● 寄存器寻址
● 寄存器间接寻址
● 直接寻址
● 立即寻址
● 基址寄存器+变址寄存器的间接寻址
● 相对寻址
● 位寻址
4.什么是源操作数?什么是目的操作数?通常在指令中如何加以区分?
答: 在双操作数的指令中,指令执行后的结果放在其中的一个操作数中,这个操作数是目的操作数,另外一个是源操作数。80C51 指令系统中,不靠近指令操作码的是源操作数,源操作数可以是立即数。80C51 指令系统中,紧跟在指令操作码之后是目的操作数,算术运算和大多数逻辑运算其目的操作数必须是累加器A,目的操作数不允许使用立即数寻址方式。
5.查表指令是在什么空间上的寻址操作?
答: 由于对程序存储器只能读而不能写,因此其数据传送是单向的,即从程序存储器读取数据,且只能向累加器A传送。这类指令共有两条,其功能是对存放于程序存储器中的数据表格进行查找传送,所以又称查表指令。
MOVC A,@A+DPTR
MOVC A,@A+PC
这两条指令都为变址寻址方式。前一条指令以DPTR作为基址寄存器进行查表,使用前
可先给 DPTR 赋予任何地址,因此查表范围可达整个程序存储器的 64KB 空间。后一条指令以PC作为基址寄存器,虽然也提供16位基址,但其值是固定的。由于A的内容为8位无符号数,所以这种查表指令只能查找所在地址以后256B范围内的常数或代码。
6.对80C51片内RAM的128~255字节区的地址空间寻址时,应注意些什么?对特殊
功能寄存器,应采用何种寻址方式进行访问?
答: 此空间有2类不同的物理存储空间,一个是特殊功能寄存器区,一个是RAM区。
直接寻址访问特殊功能寄存器,间接寻址访问RAM区。
7.写出完成下列要求的C语言程序。
(1)将地址为4000H的片外数据存储

单元内容,送入地址为30H的片内数据存储单元
中。
答: 可使用绝对地址访问函数实现 DBYTE[0x30] = XBYTE[0x4000];
(2)将地址为4000H的片外数据存储单元内容,送入地址为3000H的片外数据存储单
元中。
答: 可使用绝对地址访问函数实现 XBYTE [0x3000] = XBYTE[0x4000];
(3)将地址为0800H的程序存储单元内容,送入地址为30H的片内数据存储单元中。
答: 可使用绝对地址访问函数实现 DBYTE [0x30] = CBYTE[0x0800];
(4)将片内数据存储器中地址为30H与40H的单元内容交换。
答: unsigned char temp;
temp= DBYTE [0x40];
DBYTE [0x40]= DBYTE [0x30];
DBYTE [0x30]= temp;
此题答案不唯一,也可用指针运算或其他方案实现;
(5)将片内数据存储器中地址为30H单元的低4位与高4位交换。
答: 使用C51提供的本征函数_cror_实现;
#inclucle
_cror_(DBYTE [0x30],4);
8.将30H、31H单元中的十进制数与38H、39H单元中的十进制数做十进制加法,其和
送入40H、41H单元中,即(31H,30H)+(39H,38H)→(41H,40H)。
答: #include //片内寄存器定义
#include
/*********** main C **************/
void main (void)
{ unsigned int sum;
sum = DBYTE[0x30]+DBYTE[0x38];
if((sum&0x000f)>0x9) sum += 0x06; //个位十进制调整
if(sum>0x99) sum += 0x60;//十位十进制调整
DBYTE[0x40]= sum;//和低位字节
DBYTE[0x41] = (sum>>8) + DBYTE[0x31]+DBYTE[0x39];//和高位字节
if(DBYTE[0x41]>0x09) DBYTE[0x41] += 0x06;//百位十进制调整
while(1); /* 程序在此死循环 */
}
9.编写程序段完成下列乘法操作: (R4,R3)×(R5),(32H,31H,30H)。此式含义
是将R4、R3中的双字节被乘数与R5中的字节乘数相乘,乘积存放在地址为32H~30H
3个存储单元中((答案不惟一) 。
解: 涉及到寄存器,用汇编实现:
ORG 0000H
MOV SP,#49H
MOV A,R3
MOV B,R5
MUL AB
MOV R0,#30H
MOV @R0,A ;将低8位存入30H
INC R0
MOV R1,B
MOV A,R4
MOV B,R5
MUL AB
ADD A,R1
MOV @R0,A; 将中间8位存入31H
MOV A,B
ADDC A,#00H ; 将中间8位的进位加入A中
INC R0
MOV @R0,A ;将高8位存入32H
SJMP $ ;程序在此死循环
END
10.编写程序,用 30H 单元内容除以 40H 单元内容,商送入 50H 单元,余数送入 51H
单元。 (答案不惟一)
解: 涉及直接地址,用汇编实现:
ORG 0000H
MOV SP,#49H
MOV A,30H ;被除数
MOV B,40H;除数
DIV AB;A/B
MOV 50H,A ;商存50H单元
MOV 51H,B ;余存51H单元
SJMP $ ;程序在此死循环
END
11.已知: (30H)= 55H,(31H)= 0AAH。分别写出完成下列要求的指令,并写出32H
单元的内容。
解: (1)(30H)&(31H)→(32H); DBYTE[0x32]= DBYTE[0x30]& DBYTE[0x31];0x00
(2)(30H)|(31H)→(

32H); DBYTE[0x32]= DBYTE[0x30]| DBYTE[0x31];0xff
(3)(30H)^(31H)→(32H); DBYTE[0x32]= DBYTE[0x30]^DBYTE[0x31];0xff
12.十进制调整指令DA起什么作用?用在何处?
答: 十进制调整指令如下:
DA A
功能是把A中二进制码自动调整成二-十进制码(BCD码)。用于对BCD码的加法结果
进行调整。
13.80C51 指令系统中有了长跳转 LJMP、长调用 LCALL 指令,为何还设置了短跳转
AJMP、短调用ACALL指令?在实际使用时应怎样考虑?
答: LJMP addr16,LCALL addr16,指令码中的目标地址均是16位的,所以可以指向64KB
程序存储器空间任意位置。
AJMP addr11,ACALL addr11,指令码中的目标地址均是 12 位的,所以可以指向 2KB
程序存储器空间任意位置。
当使用的程序存储器空间在 2KB 之内或产生的代码长度在 2KB 之内时所有的跳转和调
用可以使用 AJMP ,ACALL 指令。否则建议使用 LJMP,LCALL。高级语言编译器根据所选目标器件和代码情况自动生成。
14.写出下列短跳转指令中标号L00的取值范围。
37FFH AJMP L00
答: 最大转移地址为:37FFH +2KB
15.设堆栈指针(SP)= 60H:
(1)2500H LCALL L00
…… ……
(2)2700H MOV A,#03H
…… ……
(3)2750H RET
执行(1)指令后:(SP)、((SP))、((SP-1))、(PC) 各为多少?执行(2)指令后:(SP)、(PC)
为多少?若将(1)指令改为ACALL L00,标号L00的取值范围是多少?
答:
执行(1)指令后,(SP)=62H,((SP))=25H,((SP-1))=03H,(PC)= L00;
执行(2)指令后,(SP)=60H,(PC)= 2702H;
若将(1)指令改为ACALL L00,标号L00的取值范围是当前PC的高5位,加上低11位
从全0变全1;例如:2500H ACALL L00,当前PC=2500H,PC高5位是00100,则L00
取值范围是:[00100, 00000000000~00100, 11111111111]
16.为什么SJMP指令的rel=$时,将实现单指令的无限循环?
答: $表示本指令所处地址, 该指令相当于:Here:SJMP Here
17.有程序如下:
CLR C
CLR RS1
CLR RS0
MOV A,#38H
MOV R0,A
MOV 29H,R0
SETB RS0
MOV R1,A
MOV 26H,A
MOV 28H,C
(1)区分哪些是伪操作指令?哪些是字节操作指令?
(2)写出程序执行后,片内RAM有关单元的内容。
(3)如fosc=12MHz,计算这段程序的执行时间。
答: (1)(2)
CLR C;答:位操作指令 (C)= 0
CLR RS1;答:位操作指令 (RS1)= 0
CLR RS0;答:位操作指令 (RS0)= 0
MOV A,#38H;答:字节操作指令 A=38H
MOV R0,A;答:字节操作指令R0=(A)=38H
MOV 29H,R0;答:字节操作指令 (29H)=(R0)=38H
SETB RS0;答:位操作指令 (RS0)=1
MOV R1,A;答:字节操作指令 R1=(A)=38H
MOV 26H,A;答:字节操作指令 (26H)=(A)=38H
MOV 28H,C;答:位操作指

令 (28H)=(C)=0
(3)如fosc=12MHz,这段程序的执行时间=11μs
18.请用位操作指令,求下列逻辑方程:
(1)P1.7 ACC.0&(B.0 P2.0) P3.0 =+ +
(2)PSW.5 P1.0&ACC B.6&P1.4 =+
(3)PSW.5 P1.7&B.4 C ACC&P1.0 =++
答: (1)P1_7=(ACC_0)&&(( B_0||P2_0)||(~P3_0));
答: (2)PSW_5=(P1_0&&(~ACC))||( B_6&&(~P1_4)) //此处实际上是取ACC.0
答: (3)PSW_5=(~(P1_7)&&B_4)||CY||((~ACC)&&P1_0) //此处实际上是取ACC.0
19.写出下列各条指令的机器码,并逐条写出依次执行每条指令后的结果和 PSW 的内
容:
(1)CLR A
(2)MOV A, #9BH
(3)MOV B, #0AFH
(4)ADD A, B
答: (1)CLR A //答案:机器码:E4 (A)=0 , (B)=0, PSW=0x00
(2)MOV A, #9BH //答案:机器码:749B (A)=0x9B , (B)=0, PSW:0x01
(3)MOV B, #0AFH //答案:机器码:75F0AF (A)=0x9B , (B)=0xAF, PSW:0x01
(4)ADD A, B //答案:机器码:25F0 (A)=0x4A , (B)=0xAF, PSW:0xc5
20.伪指令与汇编指令有何区别?说出常用的5种伪指令的作用。
答:
● 汇编指令,编译后产生机器码的指令;
● 伪指令,仅供汇编程序使用,编译后不产生机器码的指令。
常用的5种伪指令如下:
1.设置起始地址ORG(Origin)
指令格式:ORG nn
作用:将ORG nn后的程序机器码或数据存放在以nn为首地址的存储单元中。如伪指令
ORG 1000H,是将目标程序从地址1000H处开始存放的。
2.定义字节DB或DEFB(Define Byte)
指令格式:[LABEL] DB N1,N2,…,Nm
作用:将DB后的8位字节数据N1,N2,…,Nm依次存入以标号LABEL为首地址的
存储单元中。若无标号,则N1,N2,…,Nm依次存放在DB上一条指令之后的存储单元中。
3.定义字DW或DEFW(Define Word)
指令格式:[LABEL] DW NN1,NN2,…,NNm
作用:将DW后的16位字数据NN1,NN2,…,NNm依次存放到以标号LABEL为首
地址的存储单元中,若无标号,则 NN1,NN2,…,NNm 依次存放在 DW 上一条指令之后的存储单元中。
4.为标号赋值EQU(Equate)
指令格式:LABEL EQU nn(或n)
作用:将16位地址nn(或8位地址n)赋给标号LABEL。
5.结束汇编END
指令格式:END
作用:汇编程序编译源程序时,遇到伪指令END,不管其后是否还有其他指令都将停止
编译。
21.在单片机应用开发系统中,C语言编程与汇编语言编程相比有哪些优势?
答: 汇编语言有执行效率高的优点,但其可移植性和可读性差,并且它本身就是一种编程效率低的低级语言,这些都使它的编程和维护极不方便,从而导致了整个系统的可靠性也较差。而使用C语言进行单片机应用系统的开发,有着汇编语言编程不可比拟的优势。
(1)编程调试灵活方便
(2)生成的代码编译效率高
(3

)完全模块化
(4)可移植性好
(5)便于项目维护管理
22.在C51中有几种关系运算符?请列举。
答: C51中有6种关系运算符:
> 大于
< 小于
>= 大于等于
<= 小于等于
== 测试等于
!= 测试不等于
23.在C51中为何要尽量采用无符号的字节变量或位变量?
答: 采用无符号的字节变量或位变量可提高代码效率的方法就是减小变量的长度,使用ANSI C 编程时,一般习惯于对变量使用 int 类型,而对于像 80C51 这类 8 位的单片机来说这是一种极大的浪费。80C51 单片机机器指令只支持字节和位变量,所以应该仔细考虑所声明的变量值的可能的取值范围,然后选择合适的变量类型。尽可能地选择变量类型为char、unsigned
char 或bit,它们只占用1B或1位。
24.为了加快程序的运行速度,C51中频繁操作的变量应定义在哪个存储区?
答: 局部变量和全局变量可以被定义在任何一个存储区中,根据前面的讨论,把经常使用的变量放在内部RAM中时,可使程序的速度得到提高。除此之外,还缩短了程序代码,因为外部存储区寻址的指令,相对要麻烦一些。考虑到存取速度,推荐读者按 data→idata→pdata→xdata 的顺序使用存储器,当然要记得在idata空间中留出足够的堆栈空间。
25.为何在C51中避免使用float浮点型变量?
答: 在 80C51 单片机系统上使用 32 位浮点数是得不偿失的,这样做会浪费单片机大量的存储器资源和程序执行时间。一定要在系统中使用浮点数的时候,可以通过提高数值数量级或使用整型运算代替浮点运算。在运算时,可以进行定点运算的尽量进行定点运算,避免进行浮点运算。尽量减少乘除法运算,如*2n
或/2n,可以使用移位操作代替乘除法运算,这样不仅可以减少代码量,同时还能大大提高程序执行效率。处理ints和longs比处理doubles和floats要方便得多,代码执行起来会更快,C51编译器也不用连接处理浮点运算的模块。
26.如何定义C51的中断函数?
答: 80C51的中断系统十分重要,C51编译器允许在C语言源程序中声明中断和编写中断服务程序,从而减轻了采用汇编程序编写中断服务程序的烦琐程度。通过使用 interrupt 关键字来实现。定义中断服务程序的一般格式如下:
void 函数名( ) interrupt n [using m]
关键字interrupt后面的n是中断号,n的取值范围为0~31。编译程序从8n+3处产生中
断向量,即在程序存储器8n+3地址处形成一条长跳转指令,转向中断号n的中断服务程序。
中断号对应着 IE 寄存器中的使能位,换句话说 IE 寄存器中的 0 位对应着外部中断 0,相应的外部中断0的中断号是0。中断号0~4对应中断源的关系如主

教材表5.14所示。
中断号和中断源的对应关系
中 断 号 n 中 断 源 中 断 向 量
0 外部中断0 0003H
1 定时器0 000BH
2 外部中断1 0013H
3 定时器1 001BH
4 串行口 0023H
using m 指明该中断服务程序所对应的工作寄存器组,取值范围为 0~3。指定工作寄存
器组的缺点是所有被中断调用的过程都必须使用同一个寄存器组,否则参数传递会发生错误。
通常不设定using m,除非保证中断程序中未调用其他子程序。
设置一个定时器中断服务程序的例子如下:
#include
#include
#define RELOADTH 0x3C
#define RELOADTL 0xB0
extern unsigned int time0_counter;
void timer0(void) interrupt 1{
TR0=0; /*停止定时器0*/
TH0=RELOADTH; /* 50ms后溢出*/
TL0=RELOADTL;
TR0=1; /*启动T0*/
time0_counter++; /*中断次数计数器加1*/
printf("time0_counter=%05d\n",time0_counter);
}
使用C51编写中断服务程序,程序员无须关心ACC、B、DPH、DPL、PSW等寄存器的
保护,C51编译器会根据上述寄存器的使用情况在目标代码中自动增加压栈和出栈。
习题5
1.80C51 有几个中断源,各中断标识是如何产生、如何复 0 的?CPU 响应中断时,其
中断入口地址各是多少?
答: 80C5l共有3类5个中断源,分别是2个外部中断源、2个定时中断源、1个串行口接收/发送中断源。
要实现中断,首先中断源要提出中断请求,单片机内中断请求的过程是特殊功能寄存器
TCON 和 SCON 相关状态位——中断请求标识位置 1 的过程,当 CPU 响应中断时,中断请求标识位才由硬件或软件清0。
2 个外部中断源和 2 个定时中断源的标识由硬件自动复 0,串行口接收/发送中断由软件
清0。
中断入口地址如下表:
80C51中断向量地址分配
中 断 源 中断入口地址
外部中断0 0003H
定时器T0中断 000BH
外部中断1 0013H
定时器T1中断 001BH
串行口中断 0023H
2.在外部中断中,有几种中断触发方式?如何选择中断源的触发方式?
答: 外部中断源请求有两种触发方式:电平方式和脉冲方式,可通过特殊功能寄存器 TCON中的控制位 IT0 和 IT1 定义。电平方式低电平有效,而脉冲方式则是脉冲的下降沿有效。一旦输入信号有效,特殊功能寄存器 TCON 中的中断标识位 IE0 或 IE1 被置 1,外部中断信号便向CPU发出了中断请求申请。
3. 80C51提供哪几种中断?在中断管理上有何特点?什么是同级内的优先权管理?中断
被封锁的条件有哪些?
答: 80C5l共有3类5个中断源,分别是2个外部中断源、2个定时中断源、1个串行口接收/发送中断源。
中断管理是通过设置中断允许控制寄存器IE和中断优先级寄存器IP完成的。
中断

源申请后,中断能否被响应,取决于CPU对中断源的开放或屏蔽状态,由内部的中
断允许寄存器IE进行控制,IE的地址是A8H,位地址为AFH~A8H,其内容如表6.4所示。
中断允许控制寄存器
位 地 址 AFH AEH ADH ACH ABH AAH A9H A8H
位 符 号 EA - - ES ET1 EX1 ET0 EX0
IE中与中断有关的共有6位,各位含义如下。
EA:CPU 中断允许总控制位。EA = l,CPU 开放中断,此时,每个中断源的中断
允许或禁止,取决于各自的中断允许控制位;EA = 0,CPU 屏蔽所有中断,即中断总
禁止。 EX0、EX1:外部中断允许控制位。EX0(EX1) = l,允许外部中断;EX0(EX1) = 0,禁止外部中断。
ET0、ET1:定时器/计数器溢出中断允许控制位。ET0(ET1) = 1,允许中断;ET0(ET1) = 0,
禁止定时器/计数器中断。
ES:串行口中断允许控制位。ES = 1,允许串行口中断;ES = 0,禁止串行口中断。
以上中断控制为两级控制,即以EA实现中断总控,以各中断源的中断允许位实现分控。
当总控制位为禁止时,不管分控位状态如何,整个中断系统被禁止。只有当总控制位为允许
状态时,中断的允许与禁止才能由各分控制位决定,参见图6.3。
80C51 有两个中断优先级,每个中断源均可通过软件设置为高优先级或低优先级中断,
实现2级中断嵌套。高优先级中断请求可以中断一个正在执行的低优先级中断服务,除非正
在执行的低优先级中断服务程序设置了禁止某些高优先级的中断。正在执行的中断服务程序
不能被另一个同级或低优先级的中断所中断;正在执行高优先级的中断服务程序,不能被任
何中断源中断。一直执行到返回指令RETI,返回主程序,而后再执行一条指令后,才能响应新的中断申请。 为实现以上功能, 80C51中断系统设有两个不可寻址的优先级状态触发器,一个指示CPU是否正在执行高优先级中断服务程序,而另一个指示CPU是否正在执行低优先级中断服务程序。前一个触发器的1状态屏蔽所有的中断申请,而后一个触发器的1状态屏蔽相同优先级的其他中断申请。
特殊功能寄存器 IP 为中断优先级控制寄存器,其地址为 B8H,位地址为 BFH~B8H,
各位内容如表6.5所示。
表6.5 中断优先级控制寄存器
位 地 址 BFH BEH BDH BCH BBH BAH B9H B8H
位 符 号 - - - PS PT1 PX1 PT0 PX0
PX0:外部中断0中断优先级控制位。PX0 = l,外部中断0定义为高优先级中断;PX0 =
0,为低优先级中断。
PT0:定时器0中断优先级控制位。PT0 = 1,定时器T0中断定义为高优先级中断;PT0 =
0,为低优先级中断。
PX1:外部中断1中断优先级控制位。PX1 = l,外部中断1定义为高优先级中断;PX1 = 0,


为低优先级中断。
PT1:定时器1中断优先级控制位。PT1 = 1,定时器T1中断定义为高优先级中断;PT1 =
0,为低优先级中断。
PS:串行口中断优先级控制位。PS=1 时,串行口中断定义为高优先级中断;PS=0 时,
为低优先级中断。
当系统复位后,IP的所有位被清0,所有的中断源均被定义为低优级中断。IP的各位都
可以用程序置位和复位,也可以用位操作指令或字节操作指令更新IP的内容,以改变各中断源的中断优先级。
当同一优先级的几个中断源同时向 CPU 提出中断请求时,CPU 通过内部硬件查询逻辑
电路,按查询顺序判定优先响应哪一个中断请求,其查询顺序为:外部中断0、定时中断0、
外部中断1、定时中断1、串行中断。
4.在中断请求有效并开中断状况下,能否保证立即响应中断?有什么条件?
答: 条件是不出现下列情况:
● 一:CPU正在处理同级的或更高优先级的中断。
● 二:当前的机器周期不是所执行指令的最后一个机器周期,即在当前指令完成之前,
CPU不会响应任何中断请求。
● 三:正在执行的指令是RETI或访问IE或IP的指令。CPU完成这类指令后,至少还要再执行一条指令才会响应新的中断请求,以便保证程序能够正确地返回。
5.中断响应中,CPU应完成哪些自主操作?这些操作状态对程序运行有什么影响?
答: CPU 响应中断时,先置位相应的高/低优先级状态触发器,指出 CPU 开始处理的中断优先级别,然后由硬件生成一条长调用指令LCALL,其格式为:LCALL addr16。其中,addr16是在程序存储区中与各中断请求对应的中断入口地址,也称为中断向量地址。
6.80C51 单片机内部设有几个定时器/计数器?它们各由哪些特殊功能寄存器所组成?
有哪几种工作方式?
答: 80C51 的单片机内有 2 个 16 位可编程的定时器/计数器,它们具有 4 种工作方式,其控制字和状态均在相应的特殊功能寄存器中,通过对控制寄存器的编程就可以方便地选择适当的工作方式。
特殊功能寄存器包括加1计数器和控制寄存器:
16位加1计数器TH0、TL0和TH1、TL1;
定时控制寄存器(TCON)和工作方式控制寄存器(TMOD);
有4种工作方式,分别是:
方式0:13位定时器/计数器
方式1:16位定时器/计数器
方式2:初值自动重新装入的8位定时器/计数器
方式3:仅适用于T0,将其分为两个8位计数器。对T1停止计数
7.80C51 定时器/计数器方式 0 的 13 位计数器初值如何计算?已有方式 1 的 16 位计数为何还需要13位的计数方式?
答: 当TMOD中M1M0 = 00 时,定时器/计数器选定方式 0 进行工作。不妨以定时器/计数器
T0 为例解释。图 6.7 所

示为T0 工作在方式 0 下的逻辑结构图(定时器/计数器 1 与其完全一致)。在该工作方式下,TH0的全部8位和TL0的低5位构成13位的加1计数器,计数器的最大值为213
= 8192,而TL0的高3位处于闲置状态,这是出于与MCS-48单片机兼容性的考
虑,因为MCS-48单片机的加1计数器是13位的。
图6.7 定时器/计数器0的工作方式0电路逻辑结构
计数器初值为:
N = 8192 - x
计数初值x是TH0、 TL0设定的初值。 x = 8191时为最小计数值l, x = 0时为最大计数值8192,
即计数范围为1~8192(213
)。
8.定时器/计数器作定时用时,定时时间与哪些因素有关?作为计数用时,对外界计数
频率有何限制?
答: 当 80C5l 内部的定时器/计数器被选定为定时器工作模式时,计数输入信号是内部时钟脉冲,此当需要高分辨率的定时,应尽量选用频率较高的晶振(80C5l最高为40 MHz)。
当定时器/计数器用作计数器时,计数脉冲来自外部输入引脚T0 或T1。当输入信号产生
由 1 至 0 的跳变(即负跳变)时,计数器的值增l。每个机器周期的S5P2 期间,对外部输入进行采样。如在第一个周期中采得的值为1,而在下一个周期中采得的值为0,则在紧跟着的再下一个周期S3P1 的期间,计数器加 1。由于确认一次下跳变需要花 2 个机器周期,即 24个振荡周期,因此外部输入的计数脉冲的最高频率为振荡器频率的1/24.例如,选用6MHZ频率的晶体,允许输入的脉冲频率为250kHz, 如果选用12MHz频率的晶体,则可输入500kHz
的外部脉冲。对于外部输入信号的占空比并没有什么限制,但为了确保某一给定的电平在变
化之前能被采样一次,则这个电平至少要保持一个机器周期。
9.定时器 T0 为方式 3 时,由于 TR1 位已经被 T0 占用,如何控制定时器 T1 的开启和关闭?
答: 在工作方式3下,定时器/计数器T0被拆成两个独立的8位计数器TL0和TH0。其中,
TL0既可以计数使用,又可以定时使用,定时器/计数器T0的控制位和引脚信号全归它使用。
其功能和操作与方式0或方式1完全相同,而且逻辑电路结构也极其类似,如图6.10所示。
图6.10 工作方式3下定时器/计数器T0被分成两个8位计数器的逻辑结构
与 TL0 的情况相反,对于 T0 的另一半 TH0,则只能作为简单的定时器使用。而且由于
T0 的控制位已被 TL0 独占,因此只好借用定时器/计数器 T1 的控制位 TR1 和 TF1,以计数
溢出去置位TF1,而定时的启动和停止则受TR1的状态控制。
由于 TL0 既能做定时器使用,也能做计数器使用,而 TH0 只能做定时器使用却不能做
计数器使用,因此在工作方式 3 下,定时器/计数器 0 可以构成 2 个定时器或 1 个定时器、1个计数器。

如果定时器/计数器T0已工作在工作方式3下,则定时器/计数器T1只能工作在方式0、方式1或方式2下,它的运行控制位TR1及计数溢出标识位TF1已被定时器/计数器0借用,
图6.11 定时器/计数器方式3的T1结构
在这种情况下定时器/计数器1通常是作为串行口的波特率发生器使用,以确定串行通信
的速率。因为已没有计数溢出标识位TF1可供使用,因此只能把计数溢出直接送给串行口。
当作为波特率发生器使用时,只需设置好工作方式,便可自动运行。如果要停止工作,只需
送入一个把它设置为方式3的方式控制字就可以了, 因为定时器/计数器1不能在方式3下使用,如果硬把它设置为方式3,则停止工作。
10.用80C51的定时器测量某正单脉冲的宽度,采用何种方式可以得到最大量程?若单
片机晶振频率为12MHz,求允许测量的最大脉冲宽度是多少?
答: 当80C5l内部的定时器/计数器被选定为定时器工作模式时,计数输入信号是内部时钟脉冲,每个机器周期产生一个脉冲位,计数器增 l。将定时器 0 或 1 设置为工作方式 1,即 16位定时器方式,并且计数初值设置为0x0000,计满65536定时脉冲后溢出,此时可以得到最大量程。
当采用12MHz频率的晶体时,每个机器周期为1μs, 测量的最大脉冲宽度也是65536μs。
11.80C51 单片机系统中,已知单片机晶振频率为 6MHz,选用定时器 0 以方式 3 产生
周期为400μs的等宽正方波连续脉冲,请编写由P1.1口输出此方波的程序。
解: 示例程序如下:
#include "REG51.H"
sbit rect_wave=P1^1;
void time_over(void);
void main(void){
TMOD=0x03;
TL0=160;
IE=0x00;
TR0=1;
for(;;){
if(TF0)time_over();
}
}
void time_over(void)
{
TF0=0;
TL0=160;
rect_wave=!rect_wave;
}
12.串行通信操作模式有哪几种?各有什么特点?
答: 串行通信操作模式有2种,异步串行通信和同步串行通信。
异步串行通信(以下简称为异步通信)所传输的数据格式(也称为串行帧)由1个起始
位、7 个或 8 个数据位、1~2 个停止位(含 1.5 个停止位)和 1 个校验位组成。起始位约定为0,空闲位约定为1。在异步通信方式中,接收器和发送器有各自的时钟,它们的工作是非同步的。图6.17所示为异步通信方式和异步通信数据格式示意图,数据格式是1个起始位、8个数据位、1个停止位,所传输的数据是35H(00110101)。
图6.17 异步通信方式和异步通信数据格式示意图
异步通信的实质是指通信双方采用独立的时钟,每个数据均以起始位开始、停止位结束,
起始位触发甲乙双方同步时钟。每个异步串行帧中的1位彼此严格同步,位周期相同。所谓
异步是指发送、接收双方的数据帧

与帧之间不要求同步,也不必同步。
同步串行通信(以下简称为同步通信)中,发送器和接收器由同一个时钟源控制。而在
异步通信中,每传输一帧字符都必须加上起始位和停止位,占用了传输时间,在要求传送数
据量较大的场合,速度就会慢得多。同步传输方式去掉了这些起始位和停止位,只在传输数
据块时先送出一个同步头(字符)标识即可。图6.18所示为同步通信方式和同步通信数据格式示意图。由图6.18可知,同步通信所传输的数据格式(也称同步串帧)是由多个数据构成的,每帧有2个同步字符作为起始位以触发同步时钟开始发送或接收数据。空闲位需发送同步字符。因此,同步是指发送、接收双方的数据帧与帧之间严格同步,而不只是位与位之间严格同步。
图6.18 同步通信方式和同步通信数据格式示意图
同步传输方式比异步传输方式速度快,这是它的优势。但同步传输方式也有其缺点,即
它必须要用一个时钟来协调收发器的工作,所以它的设备也较复杂。
由上所述可以得到推论:异步通信比较灵活,适用于数据的随机发送/接收,而同步通信
则是成批数据传送的。异步传输一批数据,因为每个字节均有起始位和停止位控制而使发送/接收速度有所降低,一般适用于每秒50~19200位, 而同步传输速度较快,可达每秒80万位。
13.异步串行通信时,通信双方应遵守哪些协定?一帧信息包含哪些内容?
答: 异步串行通信(以下简称为异步通信)所传输的数据格式(也称为串行帧)由1个起始位、7 个或 8 个数据位、1~2 个停止位(含 1.5 个停止位)和 1 个校验位组成。起始位约定为0,空闲位约定为1。在异步通信方式中,接收器和发送器有各自的时钟,它们的工作非同步的。
图6.17所示为异步通信方式和异步通信数据格式示意图,数据格式是1个起始位、8个
数据位、1个停止位,所传输的数据是35H(00110101)。
图6.17 异步通信方式和异步通信数据格式示意图
14.串行通信时会出现哪些错误?用什么方法检查这些错误?
答: 异步通信时可能会出现帧格式错、超时错等传输错误。在具有串行口的单片机的开发中,应考虑在通信过程中对数据差错进行校验,因为差错校验是保证准确无误通信的关键。
常用差错校验方法有奇偶校验(80C51系列单片机编程采用此法)、和校验及循环冗余码
校验。
15.80C51 串行通信有哪几种工作方式?当并行口不够用时,如何实现串行口作并行口
使用?
答: 80C51串行通信有4工作方式,方式0~方式3
方式0下,串行口作为同步移位寄存器使用。这时用RXD(P3.0)引脚作为数据移位


入口和出口,而由TXD(P3.1)引脚提供移位脉冲。移位数据的发送和接收以8位为一帧,
不设起始位和停止位,低位在前高位在后,利用这一特点,当并行口不够用时,可以通过串
行口扩展并行口。具体方法见主教材P214~P215。
16.什么是波特率?如何计算和设置80C51串行通信的波特率。
答: 波特率是串行通信中一个重要概念。波特率BR是单位时间传输的数据位数,即单位bps(bit per second),1bps = 1bit/s。波特率的倒数即为每位传输所需的时间。由上面介绍的异步串行通信原理可知,互相通信甲乙双方必须具有相同的波特率,否则无法成功的完成数
据通信。发送和接收数据是由同步时钟触发发送器和接收器而实现的。发送/接收时钟频率与波特率有关,即: fT/R = n×BRT/R
式中,fT/R为发/收时钟频率,单位为Hz;BRT/R为发/收波特率,单位为bps;n为波特率因子。 同步通信n = 1。异步通信n可取1、16或64。也就是说,同步通信中数据传输的波特率即为同步时钟频率,而异步通信中,时钟频率可为波特率的整数倍。
① 方式0时波特率是固定的,为单片机晶振频率的1/12,即BR = fosc/12。如果晶振频率
用fosc表示,按此波特率也就是一个机器周期进行一次移位。当fosc = 6MHz时,波特率为500kbps,即2μs移位一次;当fosc = 12MHz时,波特率为1Mbps,即1μs移位一次。
② 方式 2 的波特率也是固定的,且有两种:一种是晶振频率的 1/32,另一种是晶振频
率的1/64,即fosc/32和fosc/64。例如,用公式表示为:
BR = 2SMOD×fosc/64 式中,SMOD为PCON寄存器最高位的值,SMOD = 1表示波特率加倍。
③ 方式 1 和方式 3 的波特率是可变的,其波特率由定时器 1 的计数溢出(对 80C52 来
说,也可以使用定时器2的计数溢出)决定,公式为:
BR = (2SMOD×Td) /32 式中,SMOD 为 PCON 寄存器最高位的值,SMOD = 1 表示波特率加倍。而定时器 1 溢出率计算公式为: T = fosc/[12×(256-TH1)]
使用定时器1的计数溢出,方式1和方式3的常用波特率如表6.16所示。
表6.16 方式1和方式3的常用波特率
fosc=6MHz fosc=12MHz fosc=11.0592MHz
串行口工 作方式
波 特 率
SMOD TMOD TH1 SMOD TMOD TH1 SMOD TMOD TH1
57600 1 20 FFH 方式1或方式3
28800 1 20 FEH
19200 1 20 FDH
9600 0 20 FDH
4800 1 20 F3H 0 20 FAH
2400 1 20 F3H 0 20 F3H 0 20 F4H
1200 1 20 E6H 0 20 E6H 0 20 E8H
600 1 20 CCH 0 20 CCH 0 20 D0H
300 0 20 CCH 0 20 98H 0 20 A0H
从表6.16中可以看出,当选择晶振fosc=11.0592MHz时, 波特率最为

齐全, 如无特别要求,通常在80C51单片机系统中选择晶振频率为11.0592MHz。
设置定时器 2 为波特率发生器工作方式,定时器 2 的溢出脉冲经 16 分频后作为串行口
发送脉冲、接收脉冲。发送脉冲、接收脉冲的频率称为波特率。其计算公式如下:
osc
BR
32 [65536 (RCAP2H,RCAP2L)]
f
=
×?
17.串行口控制寄存器SCON中TB8、RB8起什么作用?在什么方式下使用?
答: TB8——发送数据位8
在方式2和方式3时,TB8是发送的第9位数据。在多机通信中,以TB8位的状态表示
主机发送的是地址还是数据。TB8 = 0为数据,TB8 = 1为地址。该位由软件置位或复位。
RB8——接收数据位8 在方式2或方式3时,RB8存放接收到的第9位数据,代表着接收的某种特征,故应根据其状态对接收数据进行操作。
18.什么是串行接口的异步数据传输和同步数据传输?80C51 UART中哪些方式是异步
传输?哪些方式是同步传输?
答: 异步数据传输的实质是指通信双方采用独立的时钟,每个数据均以起始位开始、停止位结束,起始位触发甲乙双方同步时钟。每个异步串行帧中的1位彼此严格同步,位周期相同。所谓异步是指发送、接收双方的数据帧与帧之间不要求同步,也不必同步。
同步数据传输,发送器和接收器由同一个时钟源控制。
80C51除了方式0是同步传输外,其余均为异步传输。
19.80C51单片机内部串行口工作方式工作于方式1、3时波特率与T1的溢出率有关,
什么是T1的溢出率?,如何计算定时器T1工作于方式1时的T1溢出率?
答: 计数器计满时(最后一个计数状态,对 16 位计数器一般为 65535) ,再来一个脉冲,会产生一个溢出信号,计数器复位至第一个状态(第一个计数状态,对16位计数器一般为0),从 0~65535 这是满量程计数的情况。如果想不想满量程,则需要设置初值,如设置初值为65536-1000=64536,则计数器输入1000个脉冲就会产生溢出信号。对T1而言,单位时间的溢出次数即T1的溢出率。
方式1和方式3的波特率是可变的,其波特率由定时器1的计数溢出(对80C52来说,
也可以使用定时器2的计数溢出)决定,公式为:
BR = (2SMOD×Td) /32
式中,SMOD 为 PCON 寄存器最高位的值,SMOD = 1 表示波特率加倍。而定时器 1 溢
出率计算公式为:
T = fosc/[12×(256-TH1)]
20.设置串行口工作于方式 3,波特率为 9600bps,系统主频为 11.0592MHz,允许接收
数据,串行口开中断,初始化编程,实现上述要求。若将串口改为方式 1,应如何修改初始
化程序?
答: 用公式
SMOD
osc 2
Count 256
384 BR
f ×
=?
×
计算TH1的初值。
设置串行口工作于方式3:
/********** 初始化串口波特率 ************/

void initUart(void)/*初始化串口波特率,使用定时器1*/
{
/* Setup the serial port for 9600 baud at 11.0592MHz */
SCON = 0xd0; //串口工作在方式3,此处SM0SM1=03
TMOD = 0x20;
PCON = 0x0;
TH1 = 0xfd;
TCON = 0x40;
}
设置串行口工作于方式1:
/********** 初始化串口波特率 ************/
void initUart(void)/*初始化串口波特率,使用定时器1*/
{
/* Setup the serial port for 9600 baud at 11.0592MHz */
SCON = 0x50; //串口工作在方式1,此处SM0SM1=01
TMOD = 0x20;
PCON = 0x0;
TH1 = 0xfd;
TCON = 0x40;
}
21. 使用串行口方式3进行双机通信,系统主频为11.0592MHz, 设置波特率为19200bps,
定时器T1工作于方式2。 A机将地址为3000H~30FFH外部RAM中数据传送到B机地址为4000H~40FFH 外部 RAM 中。请编写程序:① 采用查询方式,进行偶校验,② 采用中断方式,不要校验。(答案不惟一,仅供参考! )
解:① 采用查询方式,进行偶校验,
A-甲机,B-乙机使用一个程序,P1.0悬空,为发送方,P1.0接地,为接收方。
程序一:
#include /* special function register declarations */
#include /* prototype declarations for I/O functions */
#include
#include
#include
#include
#define byte unsigned char
#define uchar unsigned char
#define word unsigned int
#define uint unsigned int
#define ulong unsigned long
#define BYTE unsigned char
#define WORD unsigned int
#define TRUE 1
#define FALSE 0
void initUart(void);/*初始化串口*/
void time(unsigned int ucMs);//延时单位:ms
/* SEND_RECI_LINE=1,设置发送; SEND_RECI_LINE=0,设置接收*/
sbit SEND_RECI_CTRL = P1^0;
sbit CTRL_BUTTON = P1^7; /* CTRL_BUTTON=0,设置错误校验和 */
void initUart(void);/*初始化串口波特率,使用定时器2*/
void send(uchar *d); /*发送函数*/
void receive(uchar *d); /*接收函数*/
xdata uchar sbuf[0x100] _at_ 0x3000;
xdata uchar rbuf[0x100] _at_ 0x4000;
/******** main 函数 *********/
void main (void) {
time(1);/* 延时等待外围器件完成复位 */
initUart();/* 初始化串口 */
if(SEND_RECI_CTRL){ /*发送*/
send(sbuf);
}
else{ /*接收*/
receive(rbuf);
}
while(TRUE){}
}
/********** 初始化串口波特率 ************/
void initUart(void)/*初始化串口波特率,使用定时器1*/
{
/* Setup the serial port for 19200 baud at 11.0592MHz */
SCON = 0xd0; //串口工作在方式3,此处SM0SM1=03
TMOD = 0x20;
PCON = 0x80; //波特率19200-0x80 波特率9600-0x00
TH1 = 0xfd;
TCON = 0x40;
}
void send(uchar *d) /*发送函数*/
{
uchar pf;
uint i;
do{
ACC=0xaa;TB8=P;
SBUF=0xaa; /*发送联络信号*/
while(TI==0){}TI=0;
while(RI==0){}RI=0;
}while((SBUF^0xbb)!=

0); /*乙机未准备好,继续联络*/
time(500);
do{ pf=0; /*清校验和*/
for(i=0;i<255;i++){
time(500);
ACC=d[i];TB8=P;
SBUF=d[i]; /*发送一个数据*/
pf+=d[i]; /*求校验和*/
while(TI==0){}TI=0;
}
if(!CTRL_BUTTON) pf++; /* CTRL_BUTTON=0,设置错误校验和 */
time(500); /*显示校验和*/
ACC=pf;TB8=P;
SBUF=pf; /*发送校验和*/
while(TI==0){}TI=0;
while(RI==0){}RI=0;
time(500);
}while(SBUF!=0); /*回答出错, 则重发*/
}
void receive(uchar *d)/*接收函数*/
{
uchar pf;
uint i;
do{
while(RI==0){}RI=0;
time(500);
}while((SBUF^0xaa)!=0); /*判甲机请求否*/
time(500);
ACC=0xbb;TB8=P;
SBUF=0xbb; /*发应答信号*/
while(TI==0){}TI=0;
while(1){
pf=0; /*清校验和*/
for(i=0; i<255; i++){
while(RI==0){}RI=0;
d[i]=SBUF; /*接收一个数据*/
ACC=d[i];if(P!=RB8) pf=0;//偶校验错误,置校验和=0
pf+=d[i]; /*求校验和*/
}
while(RI==0){}RI=0;
if((SBUF^pf)==0){/*比较校验和*/
time(500);
ACC=0x00;TB8=P;
SBUF=0x00;/*校验和相同发"0x00"*/
while(TI==0){}TI=0;
}
else{
time(500);
ACC=0xff;TB8=P;
SBUF=0xff;while(TI==0){}TI=0; /*校验和不同发"0xff", 重新接收*/
}
}
}
/*********************************************************
* 函数说明:延时5us,晶振改变时只用改变这一个函数!
1、对于11.0592M晶振而言,需要2个_nop_();
2、对于22.1184M晶振而言,需要4个_nop_();
* 入口参数:无
* 返回: 无
*********************************************************/
void delay_5us(void)//延时5us,晶振改变时只用改变这一个函数!
{
_nop_();
_nop_();
//_nop_();
//_nop_();
}
/************ delay_50us ***************/
void delay_50us(void)//延时50us
{
unsigned char i;
for(i=0;i<4;i++)
{
delay_5us();
}
}
/******** 延时100us ******************/
void delay_100us(void)//延时100us
{
delay_50us();
delay_50us();
}
/*********** 延时单位:ms *******************/
void time(unsigned int ucMs)//延时单位:ms
{
unsigned char j;
while(ucMs>0){
for(j=0;j<10;j++) delay_100us();
ucMs--;
}
}
② 采用中断方式,不要校验。
#include /* special function register declarations */
#include /* prototype declarations for I/O functions */
#include
#include
#include
#include
#define byte unsigned char
#define uchar unsigned char
#define word unsigned int
#define uint unsigned int
#define ulong unsigned long
#define BYTE unsigned char
#define WORD unsigned int
#define TRUE 1
#define FALSE 0
void initUart(void);/*初始化串口*/
void time(unsigned int ucMs);//延时单位:ms
/*

SEND_RECI_LINE=1,设置发送; SEND_RECI_LINE=0,设置接收*/
sbit SEND_RECI_CTRL = P1^0;
sbit CTRL_BUTTON = P1^7; /* CTRL_BUTTON=0,设置错误校验和 */
void initUart(void);/*初始化串口波特率,使用定时器2*/
void send(uchar *d); /*发送函数*/
void receive(uchar *d); /*接收函数*/
xdata uchar sbuf[0x100] _at_ 0x3000;
xdata uchar rbuf[0x100] _at_ 0x4000;
xdata uchar* p_rbuf=&rbuf[0]; //指向接收缓冲去第一个字节地址
/******** main 函数 *********/
void main (void) {
time(1);/* 延时等待外围器件完成复位 */
initUart();/* 初始化串口 */
if(SEND_RECI_CTRL){ /*发送*/
send(sbuf);
}
while(TRUE){}/*中断接收*/
}
/********** 初始化串口波特率 ************/
void initUart(void)/*初始化串口波特率,使用定时器1*/
{ /* Setup the serial port for 19200 baud at 11.0592MHz */
SCON = 0xd0; //串口工作在方式3,此处SM0SM1=03
TMOD = 0x20;
PCON = 0x80; //波特率19200-0x80 波特率9600-0x00
TH1 = 0xfd;
TCON = 0x40;
if(!SEND_RECI_CTRL)
IE=0x90; //如果是接收方,则打开串口中断
}
void send(uchar *d) /*发送函数*/
{
uint i;
for(i=0;i<255;i++){
time(10);
SBUF=d[i]; /*发送一个数据*/
while(TI==0){}TI=0;
}
}
/*********** 串行口中断服务程序***************/
void serial0_int(void) interrupt 4
{ *p_rbuf=SBUF;RI=0;
p_rbuf++; }
/*********************************************************
* 函数说明:延时5us,晶振改变时只用改变这一个函数!
1、对于11.0592M晶振而言,需要2个_nop_();
2、对于22.1184M晶振而言,需要4个_nop_();
* 入口参数:无
* 返回: 无
*********************************************************/
void delay_5us(void)//延时5us,晶振改变时只用改变这一个函数!
{
_nop_();
_nop_();
//_nop_();
//_nop_();
}
/************ delay_50us ***************/
void delay_50us(void)//延时50us
{
unsigned char i;
for(i=0;i<4;i++)
{
delay_5us();
}
}
/******** 延时100us ******************/
void delay_100us(void)//延时100us
{
delay_50us();
delay_50us();
}

/*********** 延时单位:ms *******************/
void time(unsigned int ucMs)//延时单位:ms
{
unsigned char j;
while(ucMs>0){
for(j=0;j<10;j++) delay_100us();
ucMs--;
}
}
22.80C52 串行口按工作方式 1 进行串行数据通信。假定波特率为 1200bps,系统主频
为11.0592MHz,以中断方式传送数据,将本机中地址为30H~4FH内部RAM中内容传送到对方地址为50H~6FH内部RAM中去。请编写全双工通信程序。(答案不惟一,仅供参考! )
解: 程序示例如下:
#include /* special function register declarations */
#include /* prototype declarations for I/O functions */
#include

相关文档