第5章 8051单片机工作原理

通过前面4位计算机的结构、指令和程序,我们对计算机这一事物有了比较深入的理解,但这个4位机结构简单、指令集不丰富、运算速度慢、不支持高级语言编程,基本没有多少实际应用价值,仅能用来理解计算机工作原理。

这一章我们将对Intel公司出品的8051架构单片微型计算机进行讲解,并在后续章节中陆续设计出基于8051单片机的个人计算机,并且为其开发一款简单的操作系统,最终此8051计算机可以运行SD上的应用程序,可以在8051计算机上完成BASIC程序的编辑和运行。这台个人计算机将具备硬件、操作系统和应用软件的层次架构。

下面我们从结构、指令和程序三个方面来理解8051单片机。

5.1 8051单片机体系结构

8051单片机仍然符合冯诺依曼计算机设计方案。

l 二进制表示指令和数据;

l 存储程序,自动运行;

l 运算器、控制器、存储器、输入设备和输出设备。

5.1.1 8051片上资源

面向控制的8位CPU;

l 布尔量处理能力;

l 64KB程序地址空间;

l 64KB数据地址空间;

l 4KB片上程序存储器;

l 128字节片上数据存储器;

l 32路I/O通道;

l 2路16位定时器/计数器;

l 1个全双工串行通信口;

l 5个中断源。

5.1.2 8051结构方框图

8051单片机的功能方框图如图5-1所示,8051单片机也包括CPU(运算器和控制器)、数据存储器、程序存储器和输入/输输出5大部分。

 

5-1 8051单片机功能框图

前面我们自己设计的4位计算机,每一部分都能精确到用三极管怎样实现,8051单片机具体的硬件细节无从得知,除非Intel公司完全披露,好在我们不是设计或实现8051单片机,只是大体弄明白它的硬件结构和工作原理。


5-2 8051单片机引脚图

8051单片机常见的产品外观就是DIP40双列直插封装形式,示意图如图5-2所所示。把整个单片微型计算机封装在一个芯片内,所以简称单片机。P00~P07、P10~P17、P20~P27、P30~P37为四个8位并行的输入/输出口,其中P0、P2、P3为双功能口。P0、P2口也可用于扩展外部程序和数据存储器使用,当用于外部扩展存储器使用时,ALE、PSEN、EA、WR、RD为系统扩展的控制线。XTAL2和XTAL1为时钟输入线。RESET为复位线。Vcc为电源、Vss为地。

5.1.3 中央处理器(CPU)

中央处理器包括运算器和控制器。运算器主要功能:

l 加、减、乘、除算数运算;

l 与、或、非等逻辑运算;

l 数据传送操作;

l 位操作;

l 十进制数调整;

自加1、自减1运算。

控制器主要作用是协调单片机各功能部件的动作,包括取指令、指令译码、发出微操作信号、控制存储器地址/数据传送等功能。

5.1.4 程序存储器

8051单片机的程序计数器是16位的,所以可访问的程序存储器最大为64KB,地址范围为0000H到FFFFH。实际的8051芯片片内不一定有64KB ROM,可能只有4KB、8KB等,如果需要更大的程序存储器,可以扩展片外程序存储器。如图5-3所示,8051内部有4KB ROM,外扩了60KB外部ROM。当引脚EA=1时,8051先访问片内的4KB ROM,超出4KB地址范围则访问外部ROM芯片;当EA=0时,直接忽略内部ROM,完全访问外部ROM。

 

5-3 8051存储器结构图

外部程序存储器的扩展方法如图5-4所示,当访问外部程序存储器时,P0自动输出低8位的地址信息到锁存器,ALE引脚输出锁存信号,低8位地址被锁存,P2口再输出高8位地址,和锁存器的低8位地址共同构成外部ROM的地址,PSEN引脚输出读信号,ROM数据通过P0口输入8051单片机,完成外部程序存储器的读。

 

5-4 8051扩展外部程序存储器

5.1.5 数据存储器

指令要对数据进行操作,指令给出参与运算数据的方式称为寻址方式,8051单片机支持的寻址方式有:寄存器寻址、直接寻址、寄存器间接寻址、立即寻址和基址寄存器加变址寄存器间接寻址。

l MOV A,#20H  把20H数据直接送入累加器A,立即寻址;

l MOV A,20H  把20H地址单元里存的数据送入累加器A,直接寻址;

l MOV A,@R0  把R0寄存器里存的地址指向内存单元里的数据送入累加器A,寄存器间接寻址;

l MOV A,R0  把R0里存的数据送入累加器A,寄存器寻址;

l MOVC A,@A+DPTR  把DPTR寄存器里的值加上累加器A里的值作为新的地址,此地址指向的存储单元里的数据送入累加器,基址寄存器加变址寄存器间接寻址。

8051数据存储器空间可分成4部分:外部64KB地址空间、内部低128字节数据存储区、内部高128字节特殊功能寄存器区、内部高128字节数据存储区,数据存储区结构如图5-5所示。

 

 

5-5 8051单片机数据存储区结构

其中内部低128字节数据存储区可以直接地址访问,内存高128字节数据存储区只能寄存器间接访问,内部高128字节特殊功能寄存器区可以直接地址访问,外部64KB存储区使用寄存器间接访问。

8051内部有一个低128字节的直接地址访问的数据存储区和一个高128字节直接地址访问的特殊功能寄存器区,更详细的划分如图5-6所示。

 

5-6 8051内部直接地址访问存储区结构

 

1. 工作寄存器区

内部数据存储区的00H~0FH区域为四组工作寄存器区,每组有8个寄存器,用R0~R7表示,R0~R7具体位于哪一组工作寄存器区,通过PSW程序状态寄存器的第4位(RS1)和第3位(RS0)的组合指定,如果RS1RS0=“01”,则R0~R7位于第一组工作寄存器区,即R0的地址是08H,R7的地址是0FH。一旦设定好R0~R7位于的工作寄存器区的哪一组,那么剩下的其它地址单元就可以当普通RAM使用。

2. 位寻址区

内部数据存储区的20H~2FH共16字节的存储区,除了有字节地址外,还有位地址,位地址的范围是00H~7FH。8051单片机可以用字节地址访问这段内存,也可以使用位地址访问这段内存。

比如说学生宿舍楼,每个房间都有一个房间编号,假设一个房间有8个床位,我们给床位再编一个床位号,100房间床位号是00H~07H,101房间床位号就是07H~0FH,其它房间以此类推。这样编完号后,每个床位可以用两种方式表示,一种是房间号加上第几个床位,另一种是直接的床位号,房间号好比字节地址,床位号好比位地址,表示方式不同,但访问的是同一个地方。

3. 堆栈

8051单片机在中断、子程序调用、传递参数等实际应用中,通常会用到一种称之为“栈”的数据存储结构。“栈”其实就是数据存储器中的一段内存,这段内存通过一个称为“栈指针”的特殊寄存器SP记录地址,当往“栈”里写入数据时,先把SP加1,然后把数据写入SP指向的内存单元,当从“栈”里读出数据时,把SP指向的内存单元数据读出,然后SP减1。8051单片机复位时,SP指向07H地址单元,用户可根据实际情况设置SP的指向。

片内数据存储区的低128字节除了工作寄存器区和堆栈区外,其它区域都可以作为普通的内存使用。

4. 外部RAM和IO口

8051可以扩展64KB外部数据存储器或者I/O口,其中00H~FFH范围可以用R0、R1寄存器间接寻址,0000H~FFFFH范围可以使用16 位DPTR寄存器访问。8051单片机只管访问片外地址空间,至于访问是数据存储器还是外扩的I/O设备,由用户自己设计的硬件电路决定。

5. 特殊功能寄存器

8051内部的CPU寄存器、I/O端口锁存器、串口寄存器、定时器寄存器、中断控制寄存器等特殊功能寄存器字节地址编号范围是80H~FFH,地址分配如表5-1所示。

5-1 8051特殊功能寄存器表

 

累加器ACC用于存放算数逻辑运算操作中的输入数和保存运算结果。

寄存器B在乘法和除法运算中作为辅助的寄存器使用,因为两个8位数相乘结果可能是16位数,只有累加器A存不下,所以使用B寄存器配合。

PSW程序状态寄存器,主要用于存储加法/减法的进位/借位信息,指定R0~R7位于哪一组工作寄存器区,存储溢出标志位和奇偶校验位等。

    IP和IE都是和中断相关的寄存器,中断机制在后面讲解。

SBUF和SCON是串口通信相关寄存器,串口也在后面讲解。

TH1、TH0、TL1、TL0、TMOD和TCON是计数器寄存器,计数器后面讲解。

DPH和DPL组合到一起就是16位的DPTR寄存器,访问片外程序存储器和片外数据存储器时,DPTR用于存储地址信息。

SP是堆栈指针,用于指示栈顶的地址。

P0、P1、P2、P3是通用I/O的寄存器,可以输出数据和读入数据。

带星花的特殊功能寄存器除了可以字节寻址外,还可以位寻址,也就是说它们还有一个位地址,位地址编号为80H~FFH,与前面可位寻址的RAM共同构成00H~FFH的256个位寻址空间。

6. 外部数据存储器的扩展

当需要外部扩展数据存储器时,接口可参考图5-7所示。P0输出低8位地址,ALE输出锁存信号,锁存器锁存低8位地址,然后P2口输出的高地址和锁存器里的低8位地址组成外部RAM的地址,如果是写入RAM数据,那么P0口输出待写入数据,WR引脚输出写信号,数据写入RAM相应地址单元,如果是读出数据,那么RD引脚输出读信号,RAM读出的数据通过P0口输入8051单片机。

 

5-7 外部数据存储器的扩展结构

 

5.1.6 中断

CPU正在按顺序一条条执行指令的时候,有紧急事件发生了,CPU被迫中断当前正在执行的程序,转而去处理紧急事件,处理完紧急事件后再返回中断处继续执行,这种机制就叫中断,能够请求CPU中断的来源称为中断源,8051单片机中断源及入口地址如表5-2所示。

5-2 8051单片机中断源和中断入口

中断源

中断入口

外中断0

0003H

定时器0

000BH

外中断1

0013H

定时器1

001BH

串口中断

0023H

以定时器0溢出产生中断为例,当定时器0记数达到最大值溢出后,会产生一个中断标志,CPU硬件会在每一个机器周期(标准8051的机器周期是12个时钟周期)末尾检查是否有中断需要处理,如果有中断到来,就把当前执行到的程序地址压入堆栈保存,然后把定时器0对应的中断入口000BH输入到程序计数器PC,也就是CPU跳转到000BH处执行,000BH处往往安排一条跳转指令,直接跳转到定时器0的中断处理子程序并执行,在子程序末尾会安排一条中断返回指令,中断返回指令会把压入栈的地址弹出到程序计数器PC中,也就是返回到中断前程序处继续执行。

5.1.7 外围设备

8051单片机一般都有并行输入/输出口、定时器和串行通信口等几种常见的外围设备,一般外围设备都是由寄存器和功能部件构成,寄存器都有地址,往寄存器里写入/读出数据,寄存器再和功能部件产生电路上联系,最终通过控制寄存器就行控制这种外围设备。

1. P口

8051单片机有P0、P1、P2和P3共32个通用输入/输出口,输入输出口的功能,可以理解为:往P1特殊功能寄存器里写入数据,数据会通过芯片P1口的8个引脚输出,读取P1特殊功能寄存器里的数据(MOV A,P1),就相当于把P1口的8个引脚上的高低电平读入计算机。P1、P2和P3都具有第二功能,比如外扩程序和数据存储器时用到的地址和数据功能,只有P1口是纯粹的输入输出口,P1口的结构如图5-8所示。

 

5-8 P1口结构图

由图5-8可见,当把数据写入特殊功能寄存器时,实际上就是写入到了图中的D触发器中,如果写入1,Q—输出0,再经过一个反相器后,引脚上正好输出一个1。如果用MOV A,P1指令,则只是读取数据,会读引脚数据;如用OR P1,#0FFH等指令,则是读出-运算-写回,会读取寄存器里数据。

另外需要注意,P0口是开漏输出,做I/O口输出1时,实际输出的是高阻态,必须接上拉电阻后才能有效输出1的功能;P1、P2、P3内部都有一个比较大的上拉电阻,也就意味着当输出1时,实际是串联了一个大电阻再输出的,所以驱动电流比较小。如果要驱动较大功率的器件,可以使用“灌电流”的方式,也就是引脚输出0,外部器件接高电平,让电流流进引脚,形成灌电流;也可以在引脚外再用一个小电阻与片内的上拉电阻并联,并联后再接外部器件,因为并联后总电阻小于外接的小电阻,所以电流驱动能力也比较大。

2. 定时器

    定时器配合定时器中断,可以实现类似闹钟提醒的功能。定时器包括一个记数时钟和一个计数器,可以给计数器设置一个初始值,记数时钟频率也可选择,这样在记数时钟驱动下,计数器从初始值开始累加,当记数到最大值后发生溢出,并会产生一个定时器中断,定时器中断的间隔可以通过记数时钟频率和计数器初始值计算得出,有了定时器就可以实现定时处理事情了,比如定时扫描键盘、输出设定占空比的脉冲信号等功能。

3. 串口

不同计算机之间往往需要传递信息或传输数据,那么就需要通信,串口可以实现串行通信,并口(前面提到的P口)可以实现并行通信。一般串行通信速率较慢,但连线少,并行通信则相反。

8051单片机最简单的串口通信只需一根地线,一根数据接收线,一根数据发送线。通信双方设置好发送和接收数据的波特率,发送方把待发送的字节数据写入发送寄存器SBUF,串口设备把SBUF里数据转换成8个脉冲信号,并且添加上起始位和停止位发送出去,接收方再把收到的脉冲信号还原成字节,并存入接收方的SBUF接收寄存器,接收单片机通过读取SBUF寄存器接收数据。异步串行通信的一种帧格式如图5-8所示。

 

5-8 异步串行通信帧格式

从异步串行通信的帧格式可以看出,一个数据帧通常包括1位起始位、8位二进制数据位、1位停止位。一秒钟能传输的二进制位的个数称为波特率,波特率确定了两个二进制位之间的时间间隔,接收双方只有相同的波特率才能通信成功。两个数据帧之间的时间间隔没有要求,一个数据帧除了数据位还包括起始位等无效数据,所以最终的有效数据传输速率肯定小于波特率。

常用的波特率有9600、19200、38400、57600、115200等,波特率可以通过设置8051单片机的相关寄存器进行设定。

5.2 8051指令集

二进制的指令编码方便记忆,所以设计了助记符与二进制编码对应,助记符也就是汇编语言,8051单片机总共有111条汇编指令。按指令编码字节数分类,有49条单字节指令、45条双字节指令和17条3字节指令;按指令执行周期分类,有64条单周期指令、45条双周期指令和2条4周期指令;按照指令完成的功能分类,有数据传送类、算术运算类、逻辑运算类、位操作类和控制转移类指令。

1. 8051指令集介绍

8051指令的16进制编码、助记符和功能解释如表5-3所示,其中:

l Rn 表示寄存器 R0-R7;

l Ri 表示 R0、R1;

l addr 表示直接8位地址;

l addr 11 表示 11 位地址,addr 16 表示 16 位地;

l #data 表示8位立即数,#data16表示16位立即数;

l bit 表示位地址;

l rel 表示相对地址,范围是-128到127;

l @表示间接寻址;

l ->表示数据传送;

l <->表示数据交换

R0)表示R0里的数据;

addr)表示addr地址指向的内存单元里的数据;

l ((R0))表示R0里存储的地址指向的内存单元里的数据;

l data7~0表示data的第0位到第7位。

5-3 8051指令集表

助记符

指令编码

说明

第1字节

第2字节

第3字节

MOV A,Rn

E8~EF

(Rn)->A

MOV A,addr

E5

(addr)->A

MOV A,@Ri

E6、E7

((Ri))->A

MOV A,#data

74

data->A

MOV Rn,A

F8~FF

(A)->Rn

MOV Rn,addr

A8~AF

(addr)->Rn

MOV Rn,#data

78~7F

data->Rn

MOV addr,A

F5

addr

(A)->addr

MOV addr,Rn

88~8F

addr

(Rn)->addr

MOV addr2,addr1

85

addr1

addr2

(addr1)->addr2

MOV addr,#data

75

addr

data

data->addr

MOV addr,@Ri

86,87

addr

((Ri))->addr

MOV @Ri,A

F6,F7

(A)->(Ri)

MOV @Ri,addr

A6,A7

addr

(addr)->(Ri)

MOV @Ri,#data

76,77

data

data->(Ri)

MOV DPTR,#data16

90

data1615~8

data167~0

data1615~8->DPH

data167~0->DPL

PUSH addr

C0

addr

(SP)+1->SP

(addr)->(SP)

POP addr

D0

addr

((SP))->addr

(SP)-1->SP

XCH A,Rn

C8~CF

(A)<->(Rn)

XCH A,addr

C5

addr

(A)<->(addr)

XCH A,@Ri

C6,C7

(A)<->((Ri))

XCHD A,@Ri

D6,D7

(A)3~0<->((Ri))3~0

MOVX A,@DPTR

E0

((DPTR))->A

MOVX A,@Ri

E2,E3

((Ri))->A

MOVX @DPTR,A

F0

(A)->(DPTR)

MOVX @Ri,A

F2,F3

(A)->(Ri)

MOVC A,@A+PC

83

((A)+(PC))->A,

访问的是程序存储器

MOVC A,@A+DPTR

93

((A)+(DPTR))->A,

访问的是程序存储器

ADD A,Rn

28~2F

(Rn)+(A)->A

进位->CY

ADD A,addr

25

addr

(addr)+(A)->A

进位->CY

ADD A,@Ri

26,27

((Ri))+(A)->A

进位->CY

ADD A,#data

24

data

data+(A)->A

进位->CY

ADDC A,Rn

38~3F

(CY)+(Rn)+(A)->A

进位->CY

ADDC A,addr

35

addr

(CY)+(addr)+(A)->A

进位->CY

ADDC A,@Ri

36,37

(CY)+((Ri))+(A)->A

进位->CY

ADDC A,#data

34

data

(CY)+data+(A)->A

进位->CY

INC A

04

(A)+1->A

INC Rn

08~0F

(Rn)+1->Rn

INC addr

05

addr

(addr)+1->addr

INC @Ri

06,07

((Ri))+1->(Ri)

INC DPTR

A3

(DPTR)+1->DPTR

DA A

D4

(A)BCD调整->A

SUBB A,Rn

98~9F

(A)-(Rn)-(CY)->A

借位->CY

SUBB A,addr

95

addr

(A)-(addr)-(CY)->A

借位->CY

SUBB A,@Ri

96,97

 无

(A)-((Ri))-(CY)->A

借位->CY

SUBB A,#data

94

data

(A)-data-(CY)->A

借位->CY

DEC A

14

(A)-1->A

DEC Rn

18~1F

(Rn)-1->A

DEC addr

15

addr

(addr)-1->addr

DEC @Ri

16,17

((Ri))-1->(Ri)

MUL AB

A4

(A)乘以(B),积的高字节送入A,低字节送入B

DIV AB

84

(A) 除以(B),商送入A,

余数送入B

CLR A

E4

0->A

CPL A

F4

(A)按位取反->A

RL A

23

左环移1位,第7位移入第0位

RLC A

33

左环移1位,第7位移入CY,(CY)移入第0位

RR A

03

右环移1位,第0位移入第7位

RRC A

13

右环移1位,第0位移入CY,(CY)移入第7位

SWAP A

C4

(A)3~0<->(A)7~4

ANL A,Rn

58~5F

(A)与(Rn)->A

ANL A,addr

55

addr

(A)与(addr)->A

ANL A,@Ri

56,57

(A)与((Ri))->A

ANL A,#data

54

data

(A)与data->A

ANL addr,A

52

addr

(addr)与(A)->addr

ANL addr,#data

53

addr

data

(addr)与data->addr

ORL A,Rn

48~4F

(A)或(Rn)->A

ORL A,addr

45

addr

(A)或(addr)->A

ORL A,@Ri

46,47

(A)或((Ri))->A

ORL A,#data

44

data

(A)或data->A

ORL addr,A

42

addr

(addr)或(A)->addr

ORL addr,#data

43

addr

data

(addr)或data->addr

XRL A,Rn

68~6F

(A)异或(Rn)->A

XRL A,addr

65

addr

(A)异或(addr)->A

XRL A,@Ri

66,67

(A)异或((Ri))->A

XRL A,#data

64

data

(A)异或data->A

XRL addr,A

62

addr

(addr)异或(A)->addr

XRL addr,#data

63

addr

data

(addr)异或data->addr

MOV C,bit

A2

Bit

(bit)->CY

MOV bit,C

92

Bit

(CY)->bit

CLR C

C3

0->CY

CLR bit

C2

Bit

0->bit

CPL C

B3

(CY)取反->CY

CPL bit

B2

Bit

(bit)取反->bit

SETB C

D3

1->CY

SETB bit

D2

Bit

1->bit

ANL C,bit

82

Bit

(CY)与(bit)->CY

ANL C,/bit

B0

Bit

(bit)先取反,然后与(CY)->CY

ORL C,bit

72

bit

(CY)或(bit)->CY

ORL C,/bit

A0

bit

(bit)先反,然后或(CY)->CY

AJMP addr11

a10a9a80 0001

a7a6a5a4

a3a2a1a0

(PC)+2->PC

addr1110~0->PC10~0

SJMP rel

80

rel

(PC)+2->PC,(PC)+rel->PC

LJMP addr16

02

addr1615~8

addr167~0

addr16->PC

JMP @A+DPTR

73

(A)+(DPTR)->PC

JZ rel

60

rel

(PC)+2->PC

如果(A)=0,则(PC)+rel->PC;

否则执行下一条指令

JNZ rel

70

rel

(PC)+2->PC

如果(A)不为0,则(PC)+rel->PC;

否则执行下一条指令

JC rel

40

rel

(PC)+2->PC

如果(CY)=0,则(PC)+rel->PC;

否则执行下一条指令

JNC rel

50

rel

(PC)+2->PC

如果(CY)不为0,则(PC)+rel->PC;

否则执行下一条指令

JB bit,rel

20

bit

rel

(PC)+3->PC

如果(bit)=1,则(PC)+rel->PC;

否则执行下一条指令

JNB bit,rel

30

bit

rel

(PC)+3->PC

如果(bit)=0,则(PC)+rel->PC;

否则执行下一条指令

JBC bit,rel

10

bit

rel

(PC)+3->PC

如果(bit)=1,则(PC)+rel->PC,

0->bit;否则执行下一条指令

CJNE A,addr,rel

B5

addr

rel

(PC)+3->(PC)

如果(A)不等于(addr),

则(PC)+rel->(PC);

否则执行下一条指令

CJNE A,#data,rel

B4

data

rel

(PC)+3->(PC)

如果(A)不等于data,

则(PC)+rel->(PC);

否则执行下一条指令

CJNE Rn,#data,rel

B8~BF

data

rel

(PC)+3->(PC)

如果(Rn)不等于data,

则(PC)+rel->(PC);

否则执行下一条指令

CJNE @Ri,#data,rel

B6,B7

data

rel

(PC)+3->(PC)

如果((Ri))不等于data,

则(PC)+rel->(PC);

否则执行下一条指令

DJNZ Rn,rel

D8~DF

rel

(PC)+2->PC,(Rn)-1->Rn

如果(Rn)不等于0,

则(PC)+rel->(PC);

否则执行下一条指令

DJNZ addr,rel

D5

addr

rel

(PC)+2->PC,(addr)-1->addr

如果(addr)不等于0,

则(PC)+rel->(PC);

否则执行下一条指令

ACALL addr11

a10a9a81

0001

a7a6a5a4

a3a2a1a0

(PC)+2->PC

(PC)->SP

addr1110~0->PC10~0

LCALL addr16

12

addr1615~8

addr167~0

(PC)+3->PC

(PC)->SP

addr16->PC

RET

22

(SP)->PC,调用返回

RETI

32

(SP)->PC,中断返回

NOP

00

空操作

2. 调用与转移

调用指令(LCALL)和转移(LJMP)指令都会带来程序的跳转,但调用指令会把当前地址压入堆栈保存,所以调用指令通过RET指令可以返回,但转移指令则不行。

3. 调用与中断

调用和中断都把当前地址压入堆栈保存,都可以返回。调用是软件行为,而中断是硬件行为,并且中断还要清除中断标志、设置中断优先级状态寄存器等操作。调用用RET返回,中断用RETI返回,RETI指令除了把保存的地址弹出到PC外,还要清除中断响应时所置位的中断优先级状态寄存器。

4. 时钟周期、机器周期、指令周期

时钟周期就是最基本的晶振周期;8051单片机的1个机器周期包括12个时钟周期,完成指令的取指、译码、读操作数、执行、写结果等流程;指令周期就是一条指令的执行需要几个机器周期,比如乘除法需要4个机器周期,其它指令都是1到2个机器周期完成。

5. 汇编伪指令

在讲解简单的4位计算机时,汇编代码是通过手工翻译成机器码的,耗时费力且容易出错,8051这里将用汇编器完成汇编语言的翻译工作。8051汇编器除了能翻译汇编指令为机器码外,还定义了很多伪指令,伪指令是用户想要传给汇编器的信息,通常不对应专门的机器码,伪指令主要有:

l ORG addr:指出后面的代码从程序存储器的addr地址处开始放置;

l DB d0,d1,d2,……,dn:把d0~dn字节数存入程序存储器,地址不确定;

l LABEL:一段汇编程序的标号,汇编器会计算出来LABEL后第一条指令的地址,代码中就可以使用LABEL,如LJMP LABEL;

l P0 EQU 80H:P0符号等价于80H,汇编器会把P0自动替换成80H;

l LED bit 87H:LED标号等价于位地址87H,汇编器把LED替换成87H;

l END:汇编代码结束,后面即使还有程序也不会再处理;

注释:一行汇编指令后面用“;”注释,汇编器不处理分号后内容。

5.3 汇编小程序

5.3.1 终端命令控制LED灯

通过串口终端发送命令控制两个LED的亮灭,Proteus仿真原理图如图5-9所示。

 

5-9 命令控制LED灯仿真原理图

1. 程序原理

无论是写汇编程序,还是高级语言程序,基本思路都是化繁为简。在主函数中把复杂问题化为较简单的若干模块,在子函数中实现每个模块,如果模块仍然复杂,那么就进一步简化,总之就是简化、简化,一直简化到能实现为止。

    比如我们这个汇编小程序,可以在主函数中分成串口初始化和接收命令,在子函数中实现命令处理,直接处理命令不好解决,那么再写一个字符串比较子函数,一步步细化到好实现为止。

主程序流程图,命令处理子程序流程图、字符串比较子程序流程图如图所示。。。。。。

2. 源代码及注释

LED1 BIT 90H

LED2 BIT 91H

;*******主程序开始*************************

ORG 0

MAIN:

;串口初始化

MOV TMOD,#20H ;选择定时器1,处于定时器工作方式2

MOV TL1,#0FDH ;根据计算公式,初始值为FDFDH时,波特率是9600

MOV TH1,#0FDH

MOV SCON,#50H ;串口工作方式1,即1-8-1,允许接收数据

MOV PCON,#00H ;波特率不加倍

SETB TR1     ;允许定时器1开始计数

;先关闭LED灯

CLR 90H

CLR 91H

;接收命令并回显,保存命令至RAM 70~7F

RCMD: MOV R0,#70H

WAIT1: JNB RI,WAIT1 ;等待接收命令

CLR RI

MOV A,SBUF

MOV @R0,A ;保存接收到的一个字符

INC R0 ;指向下一个地址

MOV SBUF,A ;发送回显

WAIT2: JNB TI,WAIT2 ;如果发送没有完成,则等待发送完

CLR TI

CJNE A,#0DH,WAIT1 ;如果没有接收到回车符,那么继续接收下一个字符

LCALL PCMD ;如果接收到回车符,认为收到了一条完整的命令,处理命令

LJMP RCMD ;重新接收新命令

;**********主程序结束**************************************************

;********命令处理子程序开始****************

PCMD: MOV R0,#60H

MOV R1,#0H

RON1: MOV A,R1 ;把on 1字符串读取到到RAM 60H处

MOV DPTR,#ON1

MOVC A,@A+DPTR

MOV @R0,A

INC R0

INC R1

CJNE A,#0DH,RON1 ;字符串以回车结尾,没回车则继续读取

LCALL CMPCMD ;命令比较,返回值存入R3,字符串相等,则R3=0

MOV A,R3

JNZ CMPON2 ;如果不是on 1,则继续比较是不是其它命令

SETB LED1 ;是on 1,则开LED1

RET ;返回,继续接收新命令

CMPON2: MOV R0,#60H

MOV R1,#0H

RON2: MOV A,R1 ;判断是不是on 2命令

MOV DPTR,#ON2

MOVC A,@A+DPTR

MOV @R0,A

INC R0

INC R1

CJNE A,#0DH,RON2

LCALL CMPCMD

MOV A,R3

JNZ CMPOF1

SETB LED2

RET

 

CMPOF1: MOV R0,#60H

MOV R1,#0H

ROFF1: MOV A,R1 ;判断是不是off 1命令

MOV DPTR,#OFF1

MOVC A,@A+DPTR

MOV @R0,A

INC R0

INC R1

CJNE A,#0DH,ROFF1

LCALL CMPCMD

MOV A,R3

JNZ CMPOF2

CLR LED1

RET

CMPOF2: MOV R0,#60H

MOV R1,#0H

ROFF2: MOV A,R1 ;判断是不是off 2命令

MOV DPTR,#OFF2

MOVC A,@A+DPTR

MOV @R0,A

INC R0

INC R1

CJNE A,#0DH,ROFF2

LCALL CMPCMD

MOV A,R3

JNZ CMDERR

CLR LED2

RET

 

CMDERR: MOV R0,#0 ;如果哪个命令都不是,那就是命令错误

SENT: MOV A,R0

MOV DPTR,#ERROR

MOVC A,@A+DPTR

JNZ PRINT

RET ;返回重新接收新命令

PRINT: MOV SBUF,A

WAIT: JNB TI,WAIT ;如果发送没有完成,则等待发送完

CLR TI

INC R0

LJMP SENT

;**************命令处理程序结束**********************

 

;*******字符串比较函数****************************

;70H和60H开始挨个做差,差存入R3,遇到回车返回,

;差不为0也返回,R3=0为相等,否则不等

CMPCMD: MOV R3,#0H

MOV R0,#70H

MOV R1,#60H

LOOP: MOV A,@R0

SUBB A,@R1

MOV R3,A

CJNE @R0,#0DH,CON ;回车表示比较完成

RET

CON: INC R0

INC R1

JZ LOOP ;字符相等,则比较下一个字符

RET ;只要遇到不相等,则比较完成

 

;***********预存入ROM中的数据************

ON1: DB 'on 1'

DB 0DH

ON2: DB 'on 2'

DB 0DH

OFF1: DB 'off 1'

DB 0DH

OFF2: DB 'off 2'

DB 0DH

ERROR: DB 'cmd error'

DB 0DH

END

3. 仿真步骤

新建proteus工程,并绘制如图所示原理图;

在新建工程目录下创建code目录,code目录里创建led.asm文件文件,把汇编源代码录入led.asm;

l Proteus->source->add/remove source files里添加源文件led.asm,并选择ASEM51,然后build all;

仿真原理图中双击80c51单片机,并选择程序led.hex,执行仿真;

通过终端输入led开关的命令,查看程序执行的情况;

l 可以任意时刻暂停仿真,单片机上右键,选择查看特殊功能寄存器、内存单元里的内容,也可以调试汇编代码。

  • 12
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值