前面我们介绍了TD-Ⅰ~Ⅲ型机,许多读者来信说程序看不太懂,这是正常的。从本讲开始我们将陆续分七讲介绍单片机的指令和单片机内部功能单元的原理和应用方法。
8031单片机可以接受总共111条机器语言指令,这些指令按功能的不同分为5类:29条数据传送类指令、24条算术运算类指令、24条逻辑运算类指令、17条控制转移类指令、17条位操作类指令。
8031单片机在工作时,能够接受机器语言指令,这些指令实际上是8位二进制数。因为它们既不容易为人理解,又不便记忆,所以人们想到用一些帮助记忆的符号(称作助记符)来表示机器语言,于是就出现了“汇编语言”。
8031单片机片内有256字节RAM,地址从00H~FFH。部分片内RAM存储单元直接参与指令的执行,所以我们先来看看8031的片内RAM。
8031片内RAM简介
8031片内RAM的地址、功能请见表1所示。本讲中只介绍片内RAM中的程序状态字寄存器PSW。

PSW寄存器实际上是片内RAM的0D0H存储单元,用于保存指令执行结果的状态标志,供程序查询和判别用。其各位定义如下:

CY(7PSW)为进位标位,若操作结果在最高位有进位输出(加法)或有借位输入(减法)时,CY位被置为1,否则清零在位操作运算时,CY被用作累加器。AC(6PSW)为辅助进位标志位,若操作结果的低4位有进位(加法)或向高4位借位(减法)时,AC位置1,否则清零。AC位主要用于10进制调整指令DA A。F0(5PSW)为用户标志位,可由用户程序来置位、清除及测试,以控制程序流向。RS1(4PSW)。RS0(3PSW)为寄存器选择位,专门用来选择当前的工作寄存器区。RS1、RS0为00、01、10、11时,R0~R7工作寄存器分别工作在片内RAM的0、1、2、3区,这种结构为中断保护提供了方便。OV(2PSW)为溢出标志位,当操作结果溢出,如结果有进位进入高位,而最高位没有向CY产生进位时,或者最高位产生进位而次高位没有向最高位进位时,OV置1,否则清零。1PSW未用,对它操作无效。P(0PSW)为奇偶标志位,若累加器A中数据各位为1的位数为奇数时,P置1,否则清零。在串行通信传输数据时,此标志位有着重要意义。
指令的寻址方式
8031单片机汇编语言格式一般为
[标号]:操作码 [目的操作数] [源操作数]
“[ ]”中为可选项。每条指令中操作码必不可少。执行指令时,单片机首先要寻找源操作数。寻找源操作数的方式称为寻址方式。8031单片机指令根据源操作数取向的不同,分5种寻址方式。①寄存器寻址,源操作数取自某些专用寄存器或工作寄存器。②直接寻址,源操作数取自片内RAM。③寄存器间接寻址,源操作数是以寄存器中数据为地址的片内RAM中的数据。④立即数寻址,源操数就是指令中的立即数。⑤基址寄存器加变址寄存器间接寻址,基址寄存器(PC或DPTR)中数据加上变址寄存器(累加器A)中数据形成新的16位地址,这个新地址中的数据就是源操作数。
传送类指令和算术运算类指令
这两类指令的汇编语言助记符和功能描述见表2。

表2中,MOV A,Rn指令的寻址方式为寄存器寻址。MOV A,dir指令中的dir是片内RAM区中的存储单元地址,该指令的寻址方式为直接导址。MOV A,#nnH指令中,#nnH有的书中也表示成#data或#da,该指令的寻址方式为立即数寻址。MOV(X)A,指令中示间接关系,表示以R1寄存器中的数据作为片内(外部)RAM的地址,MOV(X)A,功能就是把以Ri寄存器中数据作为地址的片内(外部)RAM存储单元中的数据送到累加器A中。由于源操作数间接取自Ri寄存器,故该指令的寻址方式为寄存器间接寻址。MOVC A,獶PTK指令的寻址方式为基址寄存器(PC或DPTR)加变址寄存器(即累加器A)间接寻址。
指令练习实验
为加深对指令功能的理解和掌握指令的用法,我们利用TD-Ⅰ、TD-Ⅱ及TD-Ⅲ型机的学习程序来进行8031单片机的指令实验,学习程序详见《无线电》1990年第9、10、11期“单片机原理和开发应用”。TD-Ⅰ、Ⅱ、Ⅲ型机学习程序中的实验子程序的起始地址分别为0100 H00H及A100H。下面我们以TD-Ⅰ型机为例进行实验,拥有TD-Ⅱ、Ⅲ型机的读者可以参照练习。
[实验1] 体会MOV Rn,dir指令的功能和用法。这里取n=0,dir=40 H。实验子程序如下:
PRO:MOV 40 H,#0 FH;0 FH送片内40H单元
MOV R0,40 H ;40 H内容送R0
MOV A,R0 ;R0内容送累加器A
RET ;返回主程序
程序机器码为0100H:75 40 0F A8 40 E8 22。执行后V1~V8显示0FH。
[实验2]体会指令 MOV,#nnH的功能和用法,选择nnH=0FH,i=0。实验子程序如下:
PRO:MOV ,#0FH;((R0))←0FH
MOV A,{48}R0 ;(A)←((R0))
RET ; 返回
机器码为 0100 H: 76 0F E6 22。
程序中,第一条指令表示把立即数0FH送到以R0中数据为地址的片内RAM存储单元中。执行结果显示0FH。
为进一步验证该指令功能,我们可以指定作为片内RAM单元地址的R0内容,如指定R0之中数据为40H,40H就是片内RAM中的存储单元地址。实验子程序如下:
PRO:MOV R0,#40H ;(R0)←40H
MOV ,#0FH;((R0))←0FH
MOV A,40H ;(A)←(40H)
RET ;返回
机器码为0100 H:78 40 76 0F E5 40 22。执行结果显示0FH,说明40H中的内容被MOV,#0FH指令置为0FH。
[实验 3]体会外部传送指令MOVX TR,A。
该指令的功能表示为((DPTR))←(A),即把累加器A中的数据传送到以寄存器DPTR中数据为地址的外部RAM存储单元中。由于TD-Ⅰ型机的RAM 6116既作外部ROM又作外部RAM,所以应把ROM区和RAM区分开。下面是实验子程序:
PRO:MOV DPTR,#0203H;(DPTR)←0203H
MOV A,#0FH ;(A)←0FH
MOVX TR,A;((DPTR))←(A)
RET ;返回
机器码为 0100 H:90 02 03 74 0F F0 22。执行后显示0FH,检查0203H单元内容也应为0FH。
8031指令系统中还有1条外部传送指令MOVX ,A。请读者运行下面的实验子程序机器码,0100 H:78 03 74 0F F2 22。检查0FH被写在0003H还是0303 H外部RAM单元,为什么?再在学习程序中的实验子程序中安排下面一段机器码 0100 H:75 A0 00 78 03 74 0F F2。执行后检查0FH 被写入到哪个单元,为什么?(安排MOV P2,#00H)。
[实验4 ]用加法指令ADD A,R0实现两数相加,如52 H+FCH。
读者可以直接按十六进制规律将这两数相加,有2+C=E,5+F=14,故52H+FCH=14EH。也可转换成二进制数,列竖式计算52H+FCH:

运行下面实验子程序:
PRO:MOV A,#52H ;(A)←52H
MOV R0, #FCH;(R0)←FCH
ADD A, R0 ;(A)←(A)+(R0)
NOP/NOP/RET ; 2个空操作/返回
机器码为 0100H:74 52 78 FC 28 22。执行后显示两数相加的低8位结果4EH。
下面再来看看程序状态字寄存器PSW中的CY(进位标志)位。学习程序中的实验子程序机器码如下:0100H:74 52 78 FC 28 E5 D0 22。其中E5 D0是MOV A,0D0H的机器码,0D0H地址是程序状态字寄存器的地址。执行学习程序后,显示PSW寄存器中数据为81H,即(CY)=1,(P)=1。
[实验 5]用带进位加法指令ADD A,R0实现52H与0CH之和。
该指令功能为(A)←(A)+(R0)+(CY)。用该指令实现52H与0CH的带进位加法,结果应为5EH+(CY),如果(CY)=0,则结果为5EH;若(CY)=1,则结果为5FH。实验子程序如下:
PRO:MOV A,# 52 H ;(A)←52H
MOV R0, #0CH ;(R0)←0CH
MOV 0D0H,#80 H;CY置1
ADDC A, R0;(A)←(A)+(R0)+(CY)
RET ;返回
机器码为0100H:74 52 78 0C 75 D0 80 38 22。执行后显示5FH。将0106H内容80H改为00H,执行后显示5EH。
[实验6]体会十进制调整指令DA A的功能和用法。
由于计算机只能接受二进制信息。当用这些二进制数表示0~9的十进制数时,可采用0000、0001…1001来表示,这样计算机中1个字节的8个位可都示从0~99的十进制数,形式为00000000~1001 1001。 0000~1001这些数被称为二进制编码的十进制数,即BCD码。当用BCD码进行运算时(如65+58=BD\(_{BCD}\)),往往产生很不直观的结果。利用DAA指令调整BD这个BCD码,结果为(A)=23,(CY)=1,合在一起是123,即65与58之和的十进制结果。这个结果就直观多了。实验子程序如下:
PRO:MOV A,#65 ;(A)←65
ADD A,#58 ;(A)←(A)+58
DA A ;十进制调整,结果送A
NOP/NOP/RET;2个空操作/返回
机器码为0100H:74 65 24 58 D4 00 00 22。结果显示23。删掉两个空操作NOP并补进MOV A,0D0H指令用来显示进位标志CY位,机器码为E5 D0。执行后显示85H,即(CY)=1。
[实验7]用乘法指令MUL AB进行FFH×03H。
乘法(或除法)指令用来实现两个十六进制数相乘(或除)时,被乘(或被除)数放A,乘(或除)数放B;乘法(或除法)运算结果的低8位(或商)放A,高8位(或余数)放B。若积大于255(或用0作除数)时,结果溢出,OV位置1。
FFH×03H的实验子程序如下:
PRO:MOV A,#FFH;(A)←FFH
MOV B,#03H;(B)←03 H
MUL AB ;(B)、(A)←(A)×(B)
NOP/NOP/RET;2个空操作/返回
机器码为0100H:74 FF 75 F0 03 A4 00 00 22。执行后显示累加器A内容为FDH。将2个空操作换成MOV A,B(机器码为E5 F0),执行结果显示B中内容为02 H。最后FFH×03H=02FDH。这个结果对不对?FFH=255,03H=3,255×3=765,而02FDH=2×16\(^{2}\)+15×16+13=765,说明结果是正确的。(周振安)