汇编语言
一、指令系统
1.1、指令系统概述
MCS-51的基本指令共111条,按指令所占的字节来分:
- 单字节指令49条;
- 双字节指令45条;
- 三字节指令17条。
按指令的执行时间来分:
- 1个机器周期(12个时钟振荡周期)指令64条
- 2个机器周期(24个时钟振荡周期)指令45条
- 只有乘、除两条指令的执行时间为4个机器周期(48个时钟振荡周期)
12MHz晶振:机器周期为1μs。
指令的长度是单字节并不一定执行起来就是一个机器周期
例如:
单字节双周期 | RET |
---|---|
单字节四周期 乘 | (MUL) |
除 | (DIV) |
双字节单周期 | ANL A,#00H |
51指令不区分大小写(C语言区别)
1.2、指令格式
两部分组成:
操作码 | 操作数 |
---|---|
用来规定指令进行什么操作 | 指令操作的对象 |
有单字节指令、双字节指令、三字节不同长度的指令,格式不同:
- 单字节指令:指令只有一个字节,操作码和操作数同在一个字节中
- 双字节指令:一个字节为操作码,另一个字节是操作数
- 三字节指令:操作码占一个字节,操作数占二 个字节。其中操作数既可能是数据,也可能是地址
1.3、 指令系统的寻址方式
重点理解:
直接寻址方式
间接寻址方式
寻址方式理解:
就是在指令中说明操作数所在地址的方法。(太官方,不好懂)
简单理解:cpu怎么找到这个数据,找到这个数据有哪几种方法可以得到这个数据
(一般寻址方式越多,越丰富的话,那么单片机的指令也越丰富,单片机功能也越强大)
对于51单片机来说有以下几种寻址方式:
1.寄存器寻址方式
操作数在寄存器中
MOV A,Rn ;(Rn)→A,n=0~7
表示把寄存器Rn的内容传送给累加器A
Rn:工作寄存器组,对于一组工作寄存器来说它包括R0 ~ R7
寻址范围包括:
- (1)4组通用工作寄存区共32(4*8=32)个工作寄存器。
- (2)部分特殊功能寄存器,例如(累加器)A、B 以及数据指针寄存器DPTR(16位数据指针,包括低八位DPL,高八位DPH)等。
4组通用工作寄存区补充理解:
工作寄存器的选择由程序状态字PSW中的D4、D3位(RS0、RS1)组成的值决定,当RS1、RS0为00时选中0区,为01时选中1区,为10时选中2区,为11时选中3区。
每个工作寄存器区为8字节(其中每字节分别记作R0-R7)共占用32字节的空间:0区的地址为00H-07H;1区的地址为08H-0FH;2区的地址为10H-17H;3区的地址为18H-1FH;
2.直接寻址方式
操作数直接以单元地址的形式给出
MOV A,40H (40H指片内RAM中,它的字节地址为40H的那个单元)
执行结果为把片内RAM中字节地址为40H那个单元的内容,放入到累加器A中
【51系列单片机片内有128字节RAM(00 ~ 7F)(疑问:为什么不是00 ~ FF),52系列有256字节RAM(有低128字节RAM、高128字节RAM)(低128字节RAM可用直接寻址,高128字节RAM采用间接寻址方式)】
寻址范围:
(1) 内部RAM的(低)128个单元
(2) 特殊功能寄存器。除了以单元地址的形式外, 还可用寄存器符号的形式给出。
例如:
MOV A,80H 与 MOV A,P0是等价的(直接写名字P0,由编译系统给它编译成80H)
(在52系列单片机当中,它的高128字节RAM是从80 ~ FF,SFR的内容也是从80 ~ FF,都是从80 ~ FF)
3. 寄存器间接寻址方式
寄存器中存放的是操作数的地址
在寄存器的名称前面加前缀标志 “ @ ”
访问内部RAM或外部数据存储器的低256个字节时
注意:
只能采用R0 或R1作为间址寄存器
例如:
MOV R1,#40H
MOV A,@R1 ;
把内部RAM中地址为40H单元内容送入A中。
对比寄存器寻址:
MOV R1,#40H
MOV A,R1 ;
将40H送入A中
寻址范围:
- (1)访问内部RAM区,51系列128个字节,52系列256个字节, 其通用形式为@Ri (只能采用R0 或R1作为间址寄存器)
- (2)对片外数据存储器的64K字节的间接寻址,例如: MOVX A,@DPTR 【因为DPTR为16位指针,其可指向范围为0000 ~ FFFF,是64K(65536字节)的空间】
- (3)片外数据存储器的低256字节,不建议使用
例如:MOVX A,@Ri
(R0、R1只有八位,它所能找到的地址范围就是00 ~ FF,256个字节)
这条指令的执行结果就是把片外的低256字节给它拿回来,放入到累加器A当中
注:
当前面操作码是MOVX时,那么这条指令执行结果都是从片外的单元当中取数据回来,必须采用间接寻址方式。或者是用DPTR间接寻址,或者是用Ri间接寻址。其所寻址范围不一样,使用DPTR间接寻址的话,可访问的范围是64K(65536字节),如果使用Ri间接寻址的话,可访问范围只有256字节。
如果操作码不是MOVX而是MOV的时候,那么MOV是对片内的RAM进行操作。在使用MOV指令进行操作的时候,只能使用R0或者R1作为间接寻址的寄存器,那么它可寻找的范围就是包括了这个的内部RAM空间,对于51系列就包括128字节RAM,对于52系列就包括整个256字节RAM,都支持这种间接寻址。
- (4)堆栈区
堆栈操作指令PUSH(压栈)和POP(出栈)使用堆栈指针 (SP)作间址寄存器
注:
SP只能作为堆栈和出栈的时候使用,而不能对于其它的一些RAM单元进行操作(不能像R0、R1那样,可以指向任意一个单元。他只能够作为堆栈区的一个栈指针)
4.立即寻址方式
操作数在指令中直接给出,需在操作数前面加前缀 “ # ”
若立即数的首位为A~F,前面还要加零(0只起到指示作用)
例如:
MOV A,#40H
MOV A,#0FFH
5.基址寄存器加变址寄存器间接寻址方式
本寻址方式是以DPTR(16位指针)或PC(程序计数器,存放将要执行的下一条指令的地址,也是一个16位的数据)作基址寄存器,以累加器A作为变址寄存器。
例如:
指令 MOVC A,@A+DPTR
其中A的原有内容为 05H,DPTR的内容为0400H,该指令执行的结果是把程序存储器0405H单元的内容传送给A。(要取程序存储器里的内容必须使用基址寄存器加变址寄存器间接寻址的方式,基址寄存器要么是DPTR要么是PC,变址寄存器必须使用A)
注:
若要从外部程序寄存器取数据,就必须用MOVC
若要是从片外数据存储器取数据,就必须用MOVX,使用DPTR作为指针,采用间接寻址的方式来读数据回来
【只有MOVC 、MOVX是跟数据存储器或程序存储器(片外数据存储器)打交道的两条指令】
说明:
- (1)本寻址方式是专门针对程序存储器的寻址方式, 寻址范围可达到64KB。
- (2)本寻址方式的指令只有3条(都是转向程序存储器当中)
MOVC A,@A+DPTR
MOVC A,@A+PC
JMP @A+DPTR
6.位寻址方式
MCS-51有位处理功能,可以对数据位进行操作,
例如:
MOV C,40H 是把位40H的值(内容)送到位累加器C(又是进借位标志位,就是CY,他俩是一个单元,一个单元身兼两职,一个职作为进借位标志,另一个职就是作为位累加器来使用)(那么只要不是进行这种加减运算的时候它就是作为位累加器使用,只有在加减运算的时候它内部内容才反应出有没有进借位的标志)。
寻址范围包括:
- (1)内部RAM中的位寻址区(20 ~ 2F这个单元,一共16个字节128个位,其中每一位都有一个固定地址,在这个空间位地址是连续排列的,都是从00 ~ 7F)。位有两种表示方法
直接书写位地址:
例 如,40H;
另一种是单元地址(字节地址)加上位:
例如, (28H).0,指的是28H单元中的最低位。它们是等价的。
- (2)特殊功能寄存器(SFR)中的可寻址位(83个)
可寻址位在指令中有如下4种的表示方法:
a. 直接使用位地址。
例如PSW.5的位地址为0D5H。
b.位名称的表示方法。
例如:PSW.5是F0标志位,可使用F0表示该位。
c.单元地址加位数的表示方法。例如 :(0D0H).5。
d. 特 殊 功 能 寄 存 器 符 号 加 位 数 的表示方法。
例 如:PSW.5。
7.相对寻址方式
在相对寻址的转移指令中,给出了地址偏移量,
以 “rel”表示,即把PC的当前值加上偏移量就构成了程序转移的目的地址:
目的地址=转移指令所在的地址 + 转移指令的字节数 + rel
(原因:程序在执行这一条转移指令的时候,PC值并不是指向这条转移指令的地址,PC值指向转移指令的下一条指令的地址。故当前PC值恰好等于转移指令所在的地址 + 转移指令的字节数)
偏移量rel是一带符号的8位二进制数补码数 (可向上、可向下跳转)。
范围是:–128(向上跳) ~ +127(向下跳)
向地址增加方向最大可转移(127+转移指令字节)个单元地址,
向地址减少方向最大可转移(128-转移指令字节)个单元地址。
总结:
直接寻址和间接寻址这两种方式非常重要,关键是这两种方式对应51内部的RAM它的不同区域的访问,我如何去访问它要采用不同寻址方式。尤其是当前在51系列单片机设计的时候大量采用52系列单片机,对于52系列单片机其内部含有高128字节RAM,一定要使用这种间接寻址的方式去寻找,对于SFR的操作,一定要用直接寻址方式去操作它,这样才能够通过不同寻址方式去找到它的位置,来消除它的重叠性带来的影响。
1.4 MCS-51指令系统分类介绍
111条指令,按功能分类,可分为下面5大类:
- (1)数据传送类(28条)
- (2)算术操作类(24条)
- (3)逻辑运算类(25条)
- (4)控制转移类(17条)
- (5)位操作类(17条)
指令中符号的意义:
- Rn :当前寄存器区的8个工作寄存器R0~R7(n=0~ 7)。
- Ri :当前选中的寄存器区中可作间接寻址寄存器的2 个寄存器R0、R1(i=0,1)。
- Direct: 直接地址,即8位的内部数据存储器单元或 特殊功能寄存器的地址。
- #data: 包含在指令中的8位立即数(00 ~ FF)(0 ~ 255)。
- #data16 :包含在指令中的16位立即数(只有在给DPTR赋值时才会用到)。
- rel: 相对转移指令中的偏移量,为8位的带符号补 码数 DPTR 数据指针,可用作16位的数据地址寄存器。
- DPTR :数据指针,可用作16位的数据地址寄存器。
- bit: 内部RAM或特殊功能寄存器中的直接寻址位。
- C(或Cy): 进位标志位或位处理机中的累加器。
(所谓位累加器就是进行单位的、一位的数据的传送的时候,都需要C作为一个中间介质来传送,并不支持把某一位的信息,比如说00H,直接送到01H当中去,这是不支持的,不能写成MOV 01H, 00H,表示说把位地址为00H的那一位的内容拿出来,放入到01H中去,它必须经过中介C传递一下。必须写成MOV C, 00H然后再加一条指令,MOV 01H, C,表示把C的内容放入到01H中去。在这,C也起到累加器A的作用,故也管它叫位累加器)
- addr11 :11位目的地址 。
- addr16 :16位目的地址 。
- @ :间接寻址寄存器前缀,如@Ri,@A+DPTR。
- (X): X中的内容。(比如说,括号里是A的话,(A)就表示A当中的内容)
- ((X)): 由X寻址的单元中的内容。
- → :箭头右边的内容被箭头左边的内容所取代。
1.4.1 数据传送类指令
使用最频繁的一类指令,通用格式:
MOV <目的操作数>,<源操作数>
属“复制”性质,而不是“搬家”
数据传送类指令不影响标志位, Cy、Ac和OV,但不包 括奇偶标志位P(P反映的是累加器A当中“1”的个数,是奇数个它就为“1”,是偶数个它就为“0”)
1.以累加器为目的操作数的指令
MOV A,Rn ; (Rn)→A,n=0~7
MOV A,@Ri ; ((Ri))→A,i=0,1
MOV A,direct ;(direct)→A
MOV A,#data ; #data→A
例如:
MOV A,R6 ;(R6)→A,寄存器寻址
MOV A,70H ;(70H)→A,直接寻址
MOV A,@R0 ;((R0))→A,间接寻址
MOV A,#78H ;78H→A,立即寻址
2.以Rn为目的操作数的指令
MOV Rn,A ; (A)→Rn,n=0~7
MOV Rn,direct ;(direct)→Rn,n=0~7
MOV Rn,#data ; #data→Rn,n=0~7
功能:
是把源操作数的内容送入当前一组工作寄存器区的R0~R7中的某一 个寄存器。
3.以直接地址direct为目的操作数的指令
MOV direct,A ; (A)→direct
MOV direct,Rn; (Rn)→direct, n=0~7
MOV direct1,direct2;
MOV direct,@Ri ; ((Ri))→direct
MOV direct,#data; #data→direct
功能:
把源操作数送入直接地址指出的存储单元。direct指的是内部RAM或 SFR的地址。
注意:
在R寄存器进行传送的时候,对R寄存器为目的操作数的这些指令当中,或者以R寄存器为源操作数的这些指令当中,比如说,MOV R0 ,R1 这样的指令它就不存在,不能直接把R1寄存器的内容放入到R0当中去,这样是不支持的,指令系统没有这样的指令。如果真的想把R1的内容传到R0去,或者通过累加器A进行一下传递,或者通过其它RAM地址进行一下传递就可以了
4.以寄存器间接地址为目的操作数的指令
MOV @Ri,A ;(A)→((Ri)),i=0,1
MOV @Ri,direct ; (direct)→((Ri))
MOV @Ri,#data ; #data→((Ri))
5.16位数传送指令
MOV DPTR,#data16 ;
#data16→DPTR
唯一的16位数据的传送指令 ,立即数的高8位送入 DPH,立即数的低8位送入DPL。
注:
DPTR虽然是一个16位的指针,咱们可以对它进行整体的赋值、加一。但实际上内部并没有一个没有指针就是DPTR,实际上它是由两部分构成的,一部分是DPH、一部分是DPL,并没有一个寄存器的名字叫DPTR。DPH和DPL在一起组合成一个16位的指针。大家在使用的时候可以直接在指令系统当中出现DPTR,但它内部物理结构上是两个,一个是DPL、一个是DPH
6.堆栈操作指令
MCS-51内部RAM中可以设定一个后进先出(LIFO-Last In First Out)的区域称作堆栈. (向上生成,SP指向栈顶)
堆栈指针SP指出堆栈的栈顶位置。
- (1)进栈指令
PUSH direct
先将栈指针SP加1,然后把direct中的内容送到栈指针SP指示 的内部RAM单元中。
堆栈区:
是用户用来开发,暂存数据的一个空间。不论是程序自身运行,还是在编写子程序的时候,都可能会需要用到这个堆栈区,所以大家一定要设置好这个堆栈区,在程序初始化的时候一定把栈顶给它设好。因为51单片机它的堆栈区可以通过SP来重新划分的,上电复位之后SP指向07H,系统默认的堆栈区占用了第一组工作寄存器。这是不合适的,那么就要求在编程时重新给栈指针赋一个新的值,一般加一条赋值语句,例如:MOV SP, 60H
例如:
当(SP)=60H,(A)=30H,(B)=70H时,
执行:
PUSH ACC ; (SP)+1=61H→SP,(A)→61H
PUSH B ; (SP)+1=62H→SP,(B)→62H
结果:(61H)=30H,(62H)=70H,(SP)=62H
- (2)出栈指令
POP direct
SP指示的栈顶(内部 RAM单元)内容送入 direct字节单元中,栈指针SP减1.
例如: 当 (SP)=62H,(62H)=70H,(61H)=30H,
执行:
POP DPH ;((SP))→DPH,(SP)-1→SP
POP DPL ;((SP))→DPL,(SP)-1→SP
结果:(DPTR)=7030H,(SP)=60H
不遵循先进后出原则的问题
mov SP ,#60H
MOV A ,#0AAH
MOV B ,#00H
PUSH A (61H)为 #0AAH
PUSH B (62H)为 #00H
POP A A 为#00H
POP B B 为#0AAH