程序状态字组(PSW,Program Status Word)
CY | AC | F0 | RS1 | RS0 | OV | - | P |
PSW里存着一些反应目前CPU执行过程的状态.PSW如图所示,它是在SFR里一个位元组,它包含有进位旗号(CY) 、辅助进位旗号(AC)、(在BCD运算时使用)、两个暂存器库选择位元(RS1和RS0)、溢位旗号(0V)、同位元(P,parity)和两个由使用者定义的旗号(F0和PSW.1).
进位旗号除了作算数运算的进位位元外,也当作布林代数运算的'累加器'(Boolean Accumulator).同位元(P)的作用是反应累加器内的八个位元为"1"的个数,如果P=1,则累加器内有其数个"1",若P=0则累加器内有偶数个"1".也就是偶同位(累加器为"1"的个数+P=偶数)之义.PSW的另两个位元,CPU未使用,因此可当作一般旗号使用.
所有MCS-51族的微处理机都执行相同的指令集.MCS-51的指令集是设计给控制应用.它提供了一些快速且多种定址模式以存取内部RAM之资料,使得在这一小小的结构里更容易做位元组操作.另外指令集更支援了单一位元变数的资料型态,以帮助需要作布林代数运算的控制和逻辑系统里直接作位元运算.
定址法
定址法就是资料所在处的表示方法,MCS-51指令集之定址法有下列六种:
直接定址法--直接定址模式时,运算元是由一个八位元的位址所指定.其中只有内部记忆体(低128位元)和SFR才可以使用直接定址法.
间接定址法--间接定址法是指令指定一个暂存器,而此暂存器的内容即为运算元的位址.无论内部或外部的RAM都可以使用间接定址法.被选择到的暂存器库中的R0 、 R1和堆叠指标(SP)可当作此8位元位址之暂存器.16位元的位址站存器只能使用16位元的"资料指标"暂存器,DPTR.
暂存器指令--暂存器库内的R0至R7暂存器,可以被某些指令直接定址,其定址法是由指令的运算码(OP Code)里的3个位元所指定,使用这种指定法去存取暂存器会使得指令码减少,而显得相当有效率,因为这种方法减少了一个位元组的位址位元组.当执行这种指令时,被选择到的暂存器库中的一个暂存器的资料会被存取.但四组暂存器库可以在程序执行时由PSW里的两个位元加以选择.
暂存器指定指令--有些指令只针对所指定的暂存器运作,例如:有些指令,只操作累加器或资料指标(DPTR)等,因此就不须位址位元组去定址它,只要运算码本身就可以指到它了
立即常数--在程序记忆体里一个常数的值可以紧跟在操作码之后,例如:将一个十进制100这个值载入累加器中,也可以使用十六进制64H.
索引定址法--只有程序记忆体可以使用索引定址法,且只能读入.这种定址法的最主要用途是作为程序记忆体查表.此法是以16位元的基底暂存器( DPTR或程序计数器PC)指到表的基底,而累加器则指出表的进入点.也就是进入程序记忆体的表的位址是将累加器的值加上基底指标的值所组成.
另一个索引定址的型式是使用在"条件跳跃指令",在此情况下跳跃指令的目的位址是由基底指标加上累加器的值所计算出的值.
ADD A,7FH 直接寻址 7FH代表数据所在之内部RAM地址 |
ADD A,@R0 间接寻址 R0内所存的是数据所在之内部RAM地址,间接寻址须加"@"符号 |
ADD A,R7 缓存器寻址 可使用R0至R7,数据在缓存器中 |
ADD A,#127 立即寻址 127为要运算的数据,闲接寻址须加"#"符号 |
缩写符号说明 | ||
缩写符号 | 说明 | 备注 |
Rn | 缓存器R0-R7 | |
direct | <> /> /> />>8bit内部数据存储器,包括 1.内部数据存储器(00-7F)的地址 2.特殊功能缓存器(80-FF)的地址,如P0,PSW,TMOD..等 | |
@Ri | 由缓存器R0或R1所寻址的内部RAM数据 | |
#data | 8bit常数 | |
#data 16 | 16bit常数 | |
addr 16 | 16bit的目的地址,可使跳跃指令跳跃64k | |
addr 11 | 11bit的目的地址,可使跳跃指令跳跃2k | |
rel | 具正负号的8位地址偏移量,用于相对地址的跳跃 | |
bit | 1个bit:只所有可以位寻址的位。 | |
A | 累加器(累积器) | |
C或CY | 进位旗号 | |
AC | 辅助进位旗号 | |
PC | 程序计数器 | |
P0 | I/O port 0 | |
P1 | I/O port 1 | |
P2 | I/O port 2 | |
P3 | I/O port 3 | |
PSW | 程序状态字组(类似于旗号缓存器) | |
SP | 堆栈指针缓存器 | |
B | 缓存器B | |
DPTR | 数据指针缓存器 | |
@ | 间接地址符号 | |
$ | 程序计数迄目前的值 | |
reg | 缓存器 |
算数运算指令 | ||
指令 | 说明 | 周期 |
ADD A,Rn | A←A+Rn | 12 |
ADD A,direct | A←A+direct | 12 |
ADD A,@Ri | A←A+Ri | 12 |
ADD A,#data | A←A+data | 12 |
ADDC A,Rn | A←A+Rn+C | 12 |
ADDC A,direct | A←A+direct+C | 12 |
ADDC A,@Ri | A←A+Ri+C | 12 |
ADDC A,#data | A←A+data+C | 12 |
SUBB A,Rn | A←A-Rn-C | 12 |
SUBB A,direct | A←A-direct-C | 12 |
SUBB A,@Ri | A←A-Ri-C | 12 |
SUBB A,#data | A←A-data-C | 12 |
INC A | A←A+1 | 12 |
INC Rn | Rn←Rn+1 | 12 |
INC direct | direct←direct+1 | <> /> /> />>12 |
INC @Ri | @Ri←@Ri+1 | 12 |
INC DPTR | DPTR←DPTR+1 | 12 |
DEC A | A←A-1 | 12 |
DEC Rn | Rn←Rn-1 | 12 |
DEC direct | direct←direct-1 | 12 |
DEC @Ri | @Ri←@Ri-1 | 12 |
MUL AB | 两个无符号的8位数据相乘,其中高阶8位放入B缓存器,低阶8位则放入累积器ACC | 24 |
DIV AB | 两个无符号的8位数据相除,把ACC值除以B缓存器值,商数放回ACC,余数放在B | 48 |
INC指令可以直接操作16位元的资料指标.而资料指标是用来产生16位元的外部资料记忆体位址,因此可以直接对16位元的暂存器加1是很有用的功能.
MUL AB指令是将累加器的内容乘上B暂存器的内容,且将16位元的乘积的低8位元放到A,高8位元放到B中.
DIV AB指令是将累加器的内容除以B暂存器的内容,而8位元的商放在累加器,但8位元余数则放在B暂存器.说也奇怪,DIV AB指令却很少使用在数学的"除法"程序中,而它却常使用在数字的基底(radix)转换和程序化的位移操作中.在稍后会举例如何使用DIV AB指俴作基底的转换.在位移操作里,被2n除后,会将n个位元向右移,使用DIV AB指令,作位移动作时,可在4μS的时间里将n个位元右移至B暂存器里.
DA A指令是用在BCD算术运算;在作BCD运算时,ADD和ADDC指令之后必须紧跟着DA A指令,以保证运算后的结果也是BCD,请特别注意DA A指令并不能直将一个二进制数字转换成BCD码.DA A指令只有在执行两个BCD码的加算后再执行才有意义.
逻辑运算指令 | ||
指令 | 说明 | 周期 |
ANL A,Rn | A←A and Rn | 12 |
ANL A,direct | A←A and direct | 12 |
ANL A,@Ri | A←A and Ri | 12 |
ANL A,#data | <> /> /> />>A←A and data | 12 |
ANL direct,A | direct←direct and A | 12 |
ANL direct,#data | direct←direct and data | 24 |
ORL A,Rn | A←A or Rn | 12 |
ORL A,direct | A←A or direct | 12 |
ORL A,Rn | A←A or Rn | 12 |
ORL A,@Ri | A←A or Ri | 12 |
ORL A,#data | A←A or data | 12 |
ORL direct,A | direct←direct or A | 12 |
ORL direct,#data | direct←direct or data | 24 |
XRL A,Rn | A←A xor Rn | 12 |
XRL A,direct | A←A xor direct | 12 |
XRL A,@Ri | A←A xor Ri | 12 |
XRL A,#data | A←A xor data | 12 |
XRL direct,A | direct←direct xor A | 12 |
XRL direct,#data | direct←direct xor data | 12 |
CLR A | 清除累加器 | 12 |
CPL A | 累加器反相 | <> /> /> />>12 |
RL A | 累加器向左旋转 | 12 |
RLC A | 累加器和C左旋 | 12 |
RR A | 累加器向右旋转 | 12 |
RRC A | 累加器和C右旋 | 12 |
这些指令是以位元组里的位元对位元执行逻辑运算,例如:累加器的内容为01010101B而<byte>的内容为10101010B,则ANL A,<byte>会使得累加器的内容变成00000000B 。
请注意:在内部资料记忆空间里的任一位元组都可直接执行逻辑运算,而不需透过累加器。如XRL <byte>,#data这个指令可以提供很快速得将P1上的位元资料做转换,例如: XRL P1,#0FFH
旋转指令( RL A、RLC A等)将累加器位移1位元至左边或右边,对一个左旋转指令是将MSB转至LSB之位置,而右旋转指令将LSB转至MSB位置。
SWAP A指令是将累加器的高4位元和低4位元的资料交换,这对于BCD的操作相当有用.
若累加器的内容为一个二进制数字,且已知其值小于十进制之100,则它可以很快地用如下列程序转换成BCD码: |
数据转移指令 | ||
指令 | 说明 | 周期 |
MOV A,Rn | A←Rn | 12 |
MOV A,direct | A←direct | 12 |
MOV A,@Ri | A←Ri | 12 |
MOV A,#data | A←data | 12 |
MOV Rn,A | Rn←A | 12 |
MOV Rn,direct | Rn←direct | 24 |
MOV Rn,#data | Rn←data | 12 | <> /> /> />>
MOV direct,A | direct←A | 12 |
MOV direct,Rn | direct←Rn | 24 |
MOV direct,direct | direct←direct | 24 |
MOV direct,@Ri | direct←Ri | 24 |
MOV direct,#data | direct←data | 24 |
MOV @Ri,A | Ri←A | 12 |
MOV @Ri,direct | Ri←direct | 24 |
MOV @Ri,#data | Ri←data | 12 |
MOV DPTR,#data 16 | Ri←16bit data | 24 |
MOVC A,@A+DPTR | A←程序内存的数据 | 24 |
MOVC A,@A+PC | A←程序内存的数据 | 24 |
MOVX A,@Ri | A←外部RAM的数据(8bit地址) | 24 |
MOVX A,@DPTR | A←外部RAM的数据(16bit地址) | 24 |
MOVX @Ri,A | 外部的RAM(8bit)←A | 24 |
MOVX @DPTR,A | 外部的RAM(16bit)←A | 24 |
PUSH direc | 推迭区←direct | 24 |
POP direc | <> /> /> />>direct←堆栈区 | 24 |
XCH A,Rn | A和Rn互换 | 12 |
XCH A,direct | A和direct互换 | 12 |
资料转移
SFR内的暂存器则只能使用直接定址法。注意到所有MCS-51的堆叠区都是芯片内部的RAM里,PUSH指令首先将堆叠指标(SP)加1,然后将一个位元组拷贝进去堆叠区。 PUSH和POP都只能使用直接定址法来指出被存入或取出的位元组,但是堆叠本身只能使用SP暂存器的间接定址法加以存取。这意思是说,堆叠区可以使用较高的128位元组,如果他们有的话,但却不是在SFR空间里。在8051、80C51BH;或内部没有ROM的8031或EPROM版本的8751都没有较高的128位元组的RAM,使用这些版本时,如果SP指向较高128位元组时,若PUSH一个位元组,此资料将遗失,而POP一个位元组时将会得到一个不确定的资料。
资料转移指令里包含了一个16位元的MOV,它可以用来设定资料指标(DPTR)的初值,以当作在程序记忆体查表支用,或作为16位元的外部资料记忆存取。
XCH A,<byte>指令可以将累加器的内容与被定址到位元组的内容互换。 XCHD A,@Ri指令也类似,只不过是交换其中的低4位元(Low Nibble)。
外部RAM
外部资料记忆体资料转移指令,只能使用间接定址法。但有两种方式可供选择,那就是使用单位元组定址或是两位元组定址,单位元组位址的产生是使用暂存器库中的R0或R1。双位元组位址则由DPTR所产生。使用16位元位址较不方便的地方是,假如只有几K位元组的外部RAM时,16位元不只是使用了接口2里的所有八位元当作位址汇流排。然而,使用八位元的位址也可以定址到几K位元组的外部RAM,而不须使用接口2的所有位元。请注意:所有的外部资料存取时,累加器都是当作指令资料的目的地(destination)或来源地(source)。对外部RAM的读(RD)和写(WR)的激发信号只有在执行MOVX指令时会动作,在一般情形下这些信号不会动作。事实上如果RD和WR不再使用时,这些脚还可以当作额外的I/O现使用。
读取在程序记忆体的查表指令
这些指令只读取程序记忆体的资料,因此表中的资料只能被读而不能更改。其中MOVC是"MOVE constant"的意思。如果要读的表是再外部的程序记忆体时,则读取的激发信号是PSEN。第一个MOVC指令中容纳256位元的表,即OOH至FFH。首先将想要进入的位址在载入累加器中,再将资料指标设定指到表的开始点,然后执行:
MOVC A,@A+DPTR就会将想要的值载入累加器。
另一个MOVC指令的动作情形也相同,只不过是使用程序计数器(PC)当作表的基底,因此这个表就要透过副程序加以读取。首先将想要进入的位址载入累加器,然后作一个副程序呼叫。
MOV A,ETRY_NUMBER
CALL TABLE
而副程序"TABLE"的写法就像这样:
TABLE:MOVC A,@A+PC
RET
DB 23H
DB 45H
这个表本身紧跟着一个RET指令,因此这种型式的表只能有255位元组,即从1到255,其中0不可以使用,因为执行MOVC指令时,PC的内容是RET这个指令的位址,所以读到的值会是RET的机械码。
布尔运算指令 | ||
指令 | 说明 | 周期 |
CLR C | 清除进位旗标 | 12 |
CLR bit | 清除直接位 | 12 |
SETB C | 设定进位旗标 | 12 |
SETB bit | 设定直接位 | < />12 |
CPL C | 进位旗标反相 | 12 |
CPL bit | 直接位反相 | 12 |
ANL C,bit | C←C and bit | 24 |
ANL C,/bit | C←C and bit(反相) | 24 |
ORL C,bit | C←C or bit | 24 |
ORL C,/bit | C←C or bit(反相) | 24 |
MOV C,bit | C←bit | 12 |
MOV bit,C | bit←C | 24 |
JC rel | 若C=1跳至rel | 24 |
JNC rel | 若C=0跳至rel | 24 |
JB bit,rel | 若bit=1跳至rel | 24 |
JNB bit,rel | 若bit=0跳至rel | 24 |
JBC bit,rel | 若bit=1跳至rel,且清除此位 | 24 |
布林指令
MCS-51内部包含有一完整的布林(单一位元)指令。在内部RAM有128个可定址位元,而SFR也提供了另128个可定址位元。因此所有I/O接口的位元都是可定址位元,且都可被当成分开的单位元接口。这些指令存取这些位元不仅只条件式跳跃指令,还有完整的转移(move)、设定(set)、清除(clear)、取补数(complement)、OR和AND指令。所以这些指令在八位元的微处理器里是很难能可贵的布林处理器的指令集如表所示。表中所有位元资料的存取都是使用直接定址法。位元位址00H至7FH是在内部RAM的较低128位元里,而位元位址80H至FFH是在SFR里。
请看:将一个内部的旗号转移至I/O接口的接脚上是多容易:
MOV C,FLAG
MOV P1.0,C
在这个例子里,FLAG是在较低128位元或SFR里的可定址位元,而I/O线上的信好是设定或清除就决定旗号位元"1"或"0"。在PSW里的进位旗号(C)位元就当作布林处理器的单位元累加器。而进位位元是个直接位址,因为它是在PSW里面的一个位元,且是个可定址位元。