单片机各类指令详解

2024-02-28  

  数据传递类指令

  以累加器为目的操作数的指令

  MOV A,Rn

  MOV A,direct

  MOV A,@Ri

  MOV A,#data

  第一条指令中,Rn代表的是R0-R7。第二条指令中,direct就是指的直接地址,而第三条指令中,就是我们刚才讲过的。第四条指令是将立即数data送到A中。

  下面我们通过一些例子加以说明:

  MOV A,R1 ;将工作寄存器R1中的值送入A,R1中的值保持不变。

  MOV A,30H ;将内存30H单元中的值送入A,30H单元中的值保持不变。

  MOV A,@R1 ;先看R1中是什么值,把这个值作为地址,并将这个地址单元中的值送入A中。如执行命令前R1中的值为20H,则是将20H单元中的值送入A中。

  MOV A,#34H ;将立即数34H送入A中,执行完本条指令后,A中的值是34H。

  以寄存器Rn为目的操作的指令

  MOV Rn,A

  MOV Rn,direct

  MOV Rn,#data

  这组指令功能是把源地址单元中的内容送入工作寄存器,源操作数不变。

  以直接地址为目的操作数的指令

  MOV direct,A 例: MOV 20H,A

  MOV direct,Rn MOV 20H,R1

  MOV direct1,direct2 MOV 20H,30H

  MOV direct,@Ri MOV 20H,@R1

  MOV direct,#data MOV 20H,#34H

  以间接地址为目的操作数的指令

  MOV @Ri,A 例:MOV @R0,A

  MOV @Ri,direct MOV @R1,20H

  MOV @Ri,#data MOV @R0,#34H

  十六位数的传递指令

  MOV DPTR,#data16

  8051是一种8位机,这是唯一的一条16位立即数传递指令,其功能是将一个16位的立即数送入DPTR中去。其中高8位送入DPH(083H),低8位送入DPL(082H)。例:MOV DPTR,#1234H,则执行完了之后DPH中的值为12H,DPL中的值为34H。反之,如果我们分别向DPH,DPL送数,则结果也一样。如有下面两条指令:MOV DPH,#35H,MOV DPL,#12H。则就相当于执行了MOV DPTR,#3512H。

  累加器A与片外RAM之间的数据传递类指令

  MOVX A,@Ri

  MOVX @Ri,A

  MOVX #9; A,@DPTR

  MOVX @DPTR,A

  说明:

  1)在51中,与外部存储器RAM打交道的只可以是A累加器。所有需要送入外部RAM的数据必需要通过A送去,而所有要读入的外部RAM中的数据也必需通过A读入。在此我们可以看出内外部RAM的区别了,内部RAM间可以直接进行数据的传递,而外部则不行,比如,要将外部RAM中某一单元(设为0100H单元的数据)送入另一个单元(设为0200H单元),也必须先将0100H单元中的内容读入A,然后再送到0200H单元中去。

  2)要读或写外部的RAM,当然也必须要知道RAM的地址,在后两条指令中,地址是被直接放在DPTR中的。而前两条指令,由于Ri(即R0或R1)只是一个8位的寄存器,所以只提供低8位地址。因为有时扩展的外部RAM的数量比较少,少于或等于256个,就只需要提供8位地址就够了。

  3)使用时应当首先将要读或写的地址送入DPTR或Ri中,然后再用读写命令。

  例:将外部RAM中100H单元中的内容送入外部RAM中200H单元中。

  MOV DPTR,#0100H

  MOVX A,@DPTR

  MOV DPTR,#0200H

  MOVX @DPTR,A

  程序存储器向累加器A传送指令

  MOVC A,@A+DPTR

  本指令是将ROM中的数送入A中。本指令也被称为查表指令,常用此指令来查一个已做好在ROM中的表格(类似C语言中的指针)

  说明:

  此条指令引出一个新的寻址方法:变址寻址。本指令是要在ROM的一个地址单元中找出数据,显然必须知道这个单元的地址,这个单元的地址是这样确定的:在执行本指令立脚点DPTR中有一个数,A中有一个数,执行指令时,将A和DPTR中的数加起为,就成为要查找的单元的地址。

  1)查找到的结果被放在A中,因此,本条指令执行前后,A中的值不一定相同。

  例:有一个数在R0中,要求用查表的方法确定它的平方值(此数的取值范围是0-5)

  MOV DPTR,#TABLE

  MOV A,R0

  MOVC A,@A+DPTR

  TABLE: DB 0,1,4,9,16,25

  设R0中的值为2,送入A中,而DPTR中的值则为TABLE,则最终确定的ROM单元的地址就是TABLE+2,也就是到这个单元中去取数,取到的是4,显然它正是2的平方。其它数据也可以类推。

  标号的真实含义:从这个地方也可以看到另一个问题,我们使用了标号来替代具体的单元地址。事实上,标号的真实含义就是地址数值。在这里它代表了,0,1,4,9,16,25这几个数据在ROM中存放的起点位置。而在以前我们学过的如LCALL DELAY指令中,DELAY 则代表了以DELAY为标号的那段程序在ROM中存放的起始地址。事实上,CPU正是通过这个地址才找到这段程序的。

  可以通过以下的例子再来看一看标号的含义:

  MOV DPTR,#100H

  MOV A,R0

  MOVC A,@A+DPTR

  ORG 0100H.

  DB 0,1,4,9,16,25

  如果R0中的值为2,则最终地址为100H+2为102H,到102H单元中找到的是4。这个可以看懂了吧?

  那为什么不这样写程序,要用标号呢?不是增加疑惑吗?

  答:如果这样写程序的话,在写程序时,我们就必须确定这张表格在ROM中的具体的位置,如果写完程序后,又想在这段程序前插入一段程序,那么这张表格的位置就又要变了,要改ORG 100H这句话了,我们是经常需要修改程序的,那多麻烦,所以就用标号来替代,只要一编译程序,位置就自动发生变化,我们把这个麻烦事交给计算机��指PC机去做了。


  堆栈操作

  PUSH direct

  POP #9; direct

  第一条指令称之为推入,就是将direct中的内容送入堆栈中,第二条指令称之为弹出,就是将堆栈中的内容送回到direct中。推入指令的执行过程是,首先将SP中的值加1,然后把SP中的值当作地址,将direct中的值送进以SP中的值为地址的RAM单元中。例:

  MOV SP,#5FH

  MOV A,#100

  MOV B,#20

  PUSH ACC

  PUSH B

  则执行第一条PUSH ACC指令是这样的:将SP中的值加1,即变为60H,然后将A中的值送到60H单元中,因此执行完本条指令后, 内存60H单元的值就是100,同样,执行PUSH B时,是将SP+1,即变为61H,然后将B中的值送入到61H单元中,即执行完本条指令后,61H单元中的值变为20。

  POP指令的执行是这样的,首先将SP中的值作为地址,并将此地址中的数送到POP指令后面的那个direct中,然后SP减1。

  接上例:

  POP B

  POP ACC

  则执行过程是:将SP中的值(现在是61H)作为地址,取61H单元中的数值(现在是20),送到B中,所以执行完本条指令后B中的值是20,然后将SP减1,因此本条指令执行完后,SP的值变为60H,然后执行POP ACC,将SP中的值(60H)作为地址,从该地址中取数(现在是100),并送到ACC中,所以执行完本条指令后,ACC中的值是100。

  这有什么意义呢?ACC中的值本来就是100,B中的值本来就是20,是的,在本例中,的确没有意义,但在实际工作中,则在PUSH B后往往要执行其他指令,而且这些指令会把A中的值,B中的值改掉,所以在程序的结束,如果我们要把A和B中的值恢复原值,那么这些指令就有意义了。

  还有一个问题,如果我不用堆栈,比如说在PUSH ACC指令处用MOV 60H,A,在PUSH B处用指令MOV 61H,B,然后用MOV A,60H,MOV B,61H来替代两条POP指令,不是也一样吗?是的,从结果上看是一样的,但是从过程看是不一样的,PUSH和POP指令都是单字节,单周期指令,而MOV指令则是双字节,双周期指令。更何况,堆栈的作用不止于此,所以一般的计算机上都设有堆栈,而我们在编写子程序,需要保存数据时,通常也不采用后面的方法,而是用堆栈的方法来实现。

  例:写出以下程序的运行结果

  MOV 30H,#12

  MOV 31H,#23

  PUSH 30H

  PUSH 31H

  POP 30H

  POP 31H

  结果是30H中的值变为23,而31H中的值则变为12。也就两者进行了数据交换。从这个例子可以看出:使用堆栈时,入栈的书写顺序和出栈的书写顺序必须相反,才能保证数据被送回原位,否则就要出错了。

  算术运算类指令

  1) 加法

  a) 不带进位加法

  影响程序状态字标志位PSW中的CY(CY是进位标志位,即和的D7为有进位时(CY)=1,否则,(CY)= 0)、AC(AC为辅助进位标志位,当D3为有进位时为1,否则为0)、OV(和的D7和D6为只有一个进位时为1,否则为0)和P(当累加器ACC中的1为奇数时为1,否则为0)

  例如:(A)= 84H,(30H)= 8DH,执行指令 ADD A,30H 结果A=11H

  b) 带进位加法

  影响的程序状态字标志位与不带进位的加法相同。表达形式为ADDC  A,Rn

  c) 增一

  例如:INC A  A的数值自加一

  d) 十进制调整

  当累加器A中的低4位数出现了非BCD码或第四位产生进位时,应在第四位加六调整,以产生第四位正确的BCD码结果。

  当累加器A中的高4位数出现了非BCD码或第四位产生进位时,应在第四位加六调整,以产生第四位正确的BCD码结果。

  例如:(A)= 0101 0110B (R2)= 0110 0111B

  ADD A,R2     DA A 结果为123

  2) 减法

  a) 带错位减法

  要是想实现不带错位减法只需要在每次执行带错位减法之前给CY清零即可。

  例如:(A)= C9H,(R2)= 54H,CY = 1。执行 SUBB A,R2之后结果为A-CY-R2。

  b) 减一

  例如:DEC A A自减一。

  3) 乘法

  乘法运算之后第八位放在累加器A中,高八位放在寄存器中。

  例如:(A)= 50H,(B)= A0H。执行指令 MUL AB后(A)= 00H,(B)= 32H

  4) 除法

  该指令的功能是将累加器A中的无符号8位二进制数除以B中的无符号8位二进制数,商的整数部分放在累加器A中,余数部分放在寄存器B中。

  例如:(A)= FBH,(B)= 12H,执行指令 DIV AB后,(A) = 0DH,B = 11H。

  3、 逻辑运算和循环类指令

  1、 逻辑与ANL:例如:(A)= C3H,(R0)= AAH,执行指令 ANL A,R0后,(A)= 82H。

  2、 逻辑或ORL例如:(A)= C3H,(R0)= 55H,执行指令 ORG A ,R0后,(A)= D7H。

  3、 逻辑异或XRL:例如:(A)= C3H,(R0)= AAH,执行指令 XRL A,R0后(A)= 69H。

  4、 累加器清0:例如:执行指令CLR A,那么无论累加器A之前是什么值,执行这条指令后都为0。

  5、 累加器取反:例如:CPL A 那么累加器A = A非。

  6、 循环移位:RR循环右移;RL循环左移;有时候循环移位可以很方便的把原来的数据乘以2。


  4、控制转移类指令

  a) 无条件转移指令

  1. 短跳转指令:AJPM addr11;程序跳转到addr11指示的地址处。

  2. 长跳转指令:LJPM addr16;程序跳转到addr16指示的地址处。

  3. 相对跳转指令:SJMP rel; 程序跳转到rel相对地址处。

  4. 散转移跳转指令:JMP @A+DPTR;程序跳转到变址指出的地址处。

  b) 条件转移指令

  1. 判0跳转指令:JZ  rel; A为0,程序跳转到rel的相对地址出;

  JNZ rel; A不为0,程序跳转到rel的相对地址出;

  2. 比较不等跳转指令:例如:CJNE A,#data; A的内容与data的内容不等则跳转。

  3. 减一不为0跳转指令:例如:DJNZ Rn;Rn内容减一不为零则跳转。

  4. 子程序跳转:ACALL addr11;调用addr11 处理子程序;

  LCALL addr16;调用addr16处理子程序;

  5. 返回:RET:子程序返回; RETI:中断返回

  6. NOP:空操作,耗时一个机器周期。

  5、位操作指令

  MCS-51单片机的硬件结构中,有一个位处理器(又称布尔处理器),它有一套位变量处理的指令集。在进行位处理时,CY(就是我们前面讲的进位位)称“位累加器”。有自已的位RAM,也就是我们刚讲的内部RAM的20H-2FH这16个字节单元即128个位单元,还有自已的位I/O空间(即P0.0…。.P0.7,P1.0…….P1.7,P2.0……。.P2.7,P3.0……。.P3.7)。当然在物理实体上它们与原来的以字节寻址用的RAM,及端口是完全相同的,或者说这些RAM及端口都可以有两种用法。

  首先,我们想要处理位操作,那么,我们必须知道两个关键字;1、bit代表一个位。2、C相当于A不过只能代表一个bit。

  a) 位传送:其实和MOV的普通用法没有什么区别,只是每次只传送一个bit。例如:C=1、(P3)= 1100 0101B、(P1)= 0011 0101B。执行一下指令:

  MOV P1.3,C

  MOV C,P3.3

  MOV P1.2,C

  结果为:C=0,P3内容不变,P1的内容变为0011001B。

  b) 位状态子设置:

  1、位清零:CLR C或bit可以实现给累加器C和地址内容清零。

  2、位置位:SETB C或bit可以实现给累加器C和地址内容设置为1。

  c) 位逻辑运算:

  1、位逻辑“与”:ANL C,bit 执行这条指令之后bit的值不发生改变,把与的结果送给累加器C。

  2、为逻辑“或”:ORL C,bit 执行这条指令之后bit的值不发生改变,把或的结果送给累加器C。

  3、位取反:CPL C;

  d) 位跳转指令(条件转移)

  1、判断C:JC C为0跳转

  JNC C为0不跳转

  第一条指令的功能是如果CY等于1就转移,如果不等于1就顺序执行。那么转移到什么地方去呢?我们可以这样理解:JC 标号,如果等于1就转到标号处执行。这条指令我们在上节课中已讲到,不再重复。

  第二条指令则和第一条指令相反,即如果CY=0就转移,不等于0就顺序执行,当然,我们也同样理解: JNC 标号

  2、判断bit: JB bit 位为1跳转

  JBC bit 位为1跳转,同时把bit清零

  JNB bit 位不为1跳转

  第一条指令是如果指定的bit位中的值是1,则转移,否则顺序执行。同样,我们可以这样理解这条指令:JB bit,标号

  第二条指令请大家先自行分析

  下面我们举个例子说明:

  ORG 0000H

  LJMP START

  ORG 30H

  START:MOV SP,#5FH

  MOV P1,#0FFH

  MOV P3,#0FFH

  L1: JNB P3.2,L2 ;P3.2上接有一只按键,它按下时,P3.2=0

  JNB P3.3,L3 ;P3.3上接有一只按键,它按下时,P3.3=0

  LJM P L1

  L2: MOV P1,#00H

  LJMP L1

  L3: MOV P1,#0FFH

  LJMP L1

  END

  把上面的例子写入片子,看看有什么现象………

  按下接在P3.2上的按键,P1口的灯全亮了,松开或再按,灯并不熄灭,然后按下接在P3.3上的按键,灯就全灭了。这像什么?这不就是工业现场经常用到的“启动”、“停止”的功能吗?

  怎么做到的呢?一开始,将0FFH送入P3口,这样,P3的所有引线都处于高电平,然后执行L1,如果P3.2是高电平(键没有按下),则顺序执行JNB P3.3,L3语句,同样,如果P3.3是高电平(键没有按下),则顺序执行LJMP L1语句。这样就不停地检测P3.2、P3.3,如果有一次P3.2上的按键按下去了,则转移到L2,执行MOV P1,#00H,使灯全亮,然后又转去L1,再次循环,直到检测到P3.3为0,则转L3,执行MOV P1,#0FFH,例灯全灭,再转去L1,如此循环不已。

  改程序还可以用JB来写.


  位寻址区

  在8031中,有一部份RAM和一部份SFR是具有位寻址功能的,也就是说这些RAM的每一个位都有自已的地址,可以直接用这个地址来对此进行操作。

  

  内部RAM的20H-2FH这16个字节,就是8031的位寻址区。看图1。可见这里面的每一个RAM中的每个位我们都可能直接用位地址来找到它们,而不必用字节地址,然后再用逻辑指令的方式。

  可以位寻址的特殊功能寄存器

  8031中有一些SFR是可以进行位寻址的,这些SFR的特点是其字节地址均可被8整除,如A累加器,B寄存器、PSW、IP(中断优先级控制寄存器)、IE(中断允许控制寄存器)、SCON(串行口控制寄存器)、TCON(定时器/计数器控制寄存器)、P0-P3(I/O端口锁存器)。以上的一些SFR我们还不熟,等我们讲解相关内容时再作详细解释。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。