PSW里存着一些反应目前CPU执行过程的状态.PSW如图所示,它是在SFR里一个位元组,它包含有进位旗号(CY) 、辅助进位旗号(AC)、(在BCD运算时使用)、两个暂存器库选择位元(RS1和RS0)、溢位旗号(0V)、同位元(P,parity)和两个由使用者定义的旗号(F0和PSW.1) 程序状态字组(PSW,Program Status Word)
进位旗号除了作算数运算的进位位元外,也当作布林代数运算的'累加器'(Boolean Accumulator).同位元(P)的作用是反应累加器内的八个位元为"1"的个数,如果P=1,则累加器内有其数个"1",若P=0则累加器内有偶数个"1".也就是偶同位(累加器为"1"的个数+P=偶数)之义.PSW的另两个位元,CPU未使用,因此可当作一般旗号使用. 所有MCS-51族的微处理机都执行相同的指令集.MCS-51的指令集是设计给控制应用.它提供了一些快速且多种定址模式以存取内部RAM之资料,使得在这一小小的结构里更容易做位元组操作.另外指令集更支援了单一位元变数的资料型态,以帮助需要作布林代数运算的控制和逻辑系统里直接作位元运算. 定址法 定址法就是资料所在处的表示方法,MCS-51指令集之定址法有下列六种: 直接定址法--直接定址模式时,运算元是由一个八位元的位址所指定.其中只有内部记忆体(低128位元)和SFR才可以使用直接定址法.
下表是其后指令表格所使用之缩写符号
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码的加算后再执行才有意义.
这些指令是以位元组里的位元对位元执行逻辑运算,例如:累加器的内容为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的操作相当有用.
资料转移 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指令的动作情形也相同,只不过是使用程序计数器(PC)当作表的基底,因此这个表就要透过副程序加以读取。首先将想要进入的位址载入累加器,然后作一个副程序呼叫。 布林指令 MCS-51内部包含有一完整的布林(单一位元)指令。在内部RAM有128个可定址位元,而SFR也提供了另128个可定址位元。因此所有I/O接口的位元都是可定址位元,且都可被当成分开的单位元接口。这些指令存取这些位元不仅只条件式跳跃指令,还有完整的转移(move)、设定(set)、清除(clear)、取补数(complement)、OR和AND指令。所以这些指令在八位元的微处理器里是很难能可贵的布林处理器的指令集如表所示。表中所有位元资料的存取都是使用直接定址法。位元位址00H至7FH是在内部RAM的较低128位元里,而位元位址80H至FFH是在SFR里。 请看:将一个内部的旗号转移至I/O接口的接脚上是多容易: 布林指令集包含ANL和ORL运算但没有XRL(Exclusive OR)运算,但是XRL运算很容易地由软体模拟,例如:想要作两位元的互斥或C=bit1 XRL bit2可以用如下的软体加以达成: JNB指令是一系列的位元测试指令中一个。它们在被测试的位元为"1"时JC、JB及JBC执行跳跃,或是被测试的位元"0"时JNC、JNB执行跳跃。在上面的例子里,是测试bit2,如果bit=0时,则CPL C这个指令就被跳过。 程序跳跃指令 指令说明周期ACALL addr11绝对式子程序呼叫24LCALL addr16远程子程序呼叫24RET从子程序返回24RETI从中断子程序返回24AJMP addr11绝对式跳跃24LJMP addr16远程跳跃24SJMP rel短程跳跃24JMP @A+DPTR间接跳跃24JZ rel若A=0跳至rel24JNZ rel若A不等于0跳至rel24CJNE A,direct,rel若A不等于direct跳至rel24CJNE A,#data,rel若A不等于data跳至rel24CJNE Rn,#data,rel若Rn不等于data跳至rel24CJNE @Ri,#data,rel若Ri不等于data跳至rel24DJNZ Rn,relRn减1不等于0跳至rel24DJNZ direct,reldirect减1不等于0跳至rel24NOP没动作12 对于以上的条条件式跳跃指令的目的位址,可以使用标记(label)或用程序记忆体的实际位址以指定给组译器使用。然而组译出来的目的位址是一个相对偏移值的位元组,且是一个带符号(2补数)的偏移值,如果跳跃被执行的话,则这个位元组的值会以2补数的加法加入PC里。因此条件式跳跃的范围就从跳跃指令的下一个位址算起在- 128至+ 127之间。 跳跃指令: 在表中的" JMP addr"指令,实际上总共有三种------既SJMP、LJMP和AJMP------它们在目的位址的格式上有所不同,如果程序不管跳跃指令的解码方式的话,JMP这个指令可作一般指令使用。 SJMP这个指令将目的的位址编码成如上面所讨论的相对偏移位址,这个指令要使用2位元组长,既包括有操码(opcode)和偏移值(offset),此时跳跃的距离就限制在SJMP指令下一个指令位址的-128至+127之间。 LJMP指令是将目的的位址编码成16位元的常数。这个指令共占了3位元组,包括操作和两位元组的位址。如此LJMP就可跳至64K程序记忆体的任何一个位址。 AJMP指令将目的的位址编码成11位元的常数,这个指令共占2位元组,包括一个操作码,此操作码中的3个位元是11位址位元中的一部分,接下去的一个位元组就是位址的低阶八位元。当执行这个指令时,这11位元就取代了PC的低阶11位元,而PC的高阶5位元不变,因此目的位址必须在AJMP指令的下一个指令位址算起的2K区域内。 在任何情况下,写程序的人都是以标记(Label)或16位元常数去指定目的位址,组译器(Assembler)会转成正确的值给指令。如果跳跃的距离超过了指令所能达到的范围时,组译器会输出"Destinationout of rang"的讯息。 JMP @A+DPTR指令是一个间接跳跃指令。其跳跃的目的位址会在程序执行中计算16位元的DPTR和累加器的和,通常DPTR是指到一个跳跃表的位址,而累加器是表里的索引,例如:要作5条通路的跳跃时,可将整数0至4载入累加器,其程序如下面所列:
上面程序的RL A指令是将索引值(0~4)转换成0至8的偶数值范围,因为在跳跃表里的每个进入点是2位元长. 表里所列的"CALL addr"指令也包括有两种指令----LCALL和ACALL,它们只是位址格式不同。 CALL是使用在不在乎什么位址编码方式时。 LCALL指令使用16位址格式,此时副程序可以在64K程序记忆体李的任一位址。而ACALL指令是使用11位元的格式,因此副程序必须在ACALL的下一位址算起的2K区域范围。在任何一种情况下,写程序的人可以以相同的方法指定副程序的位址给组译器:既使用标记或16位元的常数。组译器会放入正确的格式给组译令。 副程序必须以RET指令作结束,它会反回CALL的下一个指令去执行。 RETI是在中断服务程序反回使用,RET和RETI之间仅有的不同点是RETI会告诉中断控制系统,中断事件以作完,如果在没中断的情况下执行了RETI指令时,则RETI与RET在功能上是相同的。 MCS-51的条件跳跃指令所有跳跃指令所跳到的目的位址都是以相对偏移的方法指定,因此跳跃的距离是从这个指令的下一位址算起的-128至+127之间。重要一点是,写程序时只要告诉组译器直接位址或标记(label)就可以了,与其他的跳跃指令一样,组译器会算出正确的偏移值。 在PSW里并没有零旗号位址,因此MCS-51使用JZ和JNZ指令去测试累加器的内容是否为零。 DJNZ指令(递减且不为零时跳跃)是用来作回路控制用,要执行N次的回圈时,可将N载入计数器,然后用DJNZ结束这个回圈,如下所示,若N =10: <>
CJNE指令(比较且不相等时跳跃)也可以使用在回圈控制上,在指令的运算元(operand)栏里共指定了两的位元组,只有在这两个位元组不相等时会产生跳跃。这个指令的另一功能是"大于、小于"的比较,在运算元里的两个位元组被看成无号数(Unsign)的整数,如果第一个位元组小于第二个,则进位旗号C=1,而如果第一个大于或等于第二个位元组则C=0。 布林指令集包含ANL和ORL运算但没有XRL(Exclusive OR)运算,但是XRL运算很容易地由软体模拟,例如:想要作两位元的互斥或C=bit1 XRL bit2可以用如下的软体加以达成: JNB指令是一系列的位元测试指令中一个。它们在被测试的位元为"1"时JC、JB及JBC执行跳跃,或是被测试的位元"0"时JNC、JNB执行跳跃。在上面的例子里,是测试bit2,如果bit=0时,则CPL C这个指令就被跳过。 程序跳跃指令 指令说明周期ACALL addr11绝对式子程序呼叫24LCALL addr16远程子程序呼叫24RET从子程序返回24RETI从中断子程序返回24AJMP addr11绝对式跳跃24LJMP addr16远程跳跃24SJMP rel短程跳跃24JMP @A+DPTR间接跳跃24JZ rel若A=0跳至rel24JNZ rel若A不等于0跳至rel24CJNE A,direct,rel若A不等于direct跳至rel24CJNE A,#data,rel若A不等于data跳至rel24CJNE Rn,#data,rel<>若Rn不等于data跳至rel24CJNE @Ri,#data,rel若Ri不等于data跳至rel24DJNZ Rn,relRn减1不等于0跳至rel24DJNZ direct,reldirect减1不等于0跳至rel24NOP没动作12 对于以上的条条件式跳跃指令的目的位址,可以使用标记(label)或用程序记忆体的实际位址以指定给组译器使用。然而组译出来的目的位址是一个相对偏移值的位元组,且是一个带符号(2补数)的偏移值,如果跳跃被执行的话,则这个位元组的值会以2补数的加法加入PC里。因此条件式跳跃的范围就从跳跃指令的下一个位址算起在- 128至+ 127之间。 跳跃指令: 在表中的" JMP addr"指令,实际上总共有三种------既SJMP、LJMP和AJMP------它们在目的位址的格式上有所不同,如果程序不管跳跃指令的解码方式的话,JMP这个指令可作一般指令使用。 SJMP这个指令将目的的位址编码成如上面所讨论的相对偏移位址,这个指令要使用2位元组长,既包括有操码(opcode)和偏移值(offset),此时跳跃的距离就限制在SJMP指令下一个指令位址的-128至+127之间。 LJMP指令是将目的的位址编码成16位元的常数。这个指令共占了3位元组,包括操作和两位元组的位址。如此LJMP就可跳至64K程序记忆体的任何一个位址。 AJMP指令将目的的位址编码成11位元的常数,这个指令共占2位元组,包括一个操作码,此操作码中的3个位元是11位址位元中的一部分,接下去的一个位元组就是位址的低阶八位元。当执行这个指令时,这11位元就取代了PC的低阶11位元,而PC的高阶5位元不变,因此目的位址必须在AJMP指令的下一个指令位址算起的2K区域内。 在任何情况下,写程序的人都是以标记(Label)或16位元常数去指定目的位址,组译器(Assembler)会转成正确的值给指令。如果跳跃的距离超过了指令所能达到的范围时,组译器会输出"Destinationout of rang"的讯息。 JMP @A+DPTR指令是一个间接跳跃指令。其跳跃的目的位址会在程序执行中计算16位元的DPTR和累加器的和,通常DPTR是指到一个跳跃表的位址,而累加器是表里的索引,例如:要作5条通路的跳跃时,可将整数0至4载入累加器,其程序如下面所列:
上面程序的RL A指令是将索引值(0~4)转换成0至8的偶数值范围,因为在跳跃表里的每个进入点是2位元长. 表里所列的"CALL addr"指令也包括有两种指令----LCALL和ACALL,它们只是位址格式不同。 CALL是使用在不在乎什么位址编码方式时。 LCALL指令使用16位址格式,此时副程序可以在64K程序记忆体李的任一位址。而ACALL指令是使用11位元的格式,因此副程序必须在ACALL的下一位址算起的2K区域范围。在任何一种情况下,写程序的人可以以相同的方法指定副程序的位址给组译器:既使用标记或16位元的常数。组译器会放入正确的格式给组译令。 副程序必须以RET指令作结束,它会反回CALL的下一个指令去执行。 RETI是在中断服务程序反回使用,RET和RETI之间仅有的不同点是RETI会告诉中断控制系统,中断事件以作完,如果在没中断的情况下执行了RETI指令时,则RETI与RET在功能上是相同的。 MCS-51的条件跳跃指令所有跳跃指令所跳到的目的位址都是以相对偏移的方法指定,因此跳跃的距离是从这个指令的下一位址算起的-128至+127之间。重要一点是,写程序时只要告诉组译器直接位址或标记(label)就可以了,与其他的跳跃指令一样,组译器会算出正确的偏移值。 在PSW里并没有零旗号位址,因此MCS-51使用JZ和JNZ指令去测试累加器的内容是否为零。 DJNZ指令(递减且不为零时跳跃)是用来作回路控制用,要执行N次的回圈时,可将N载入计数器,然后用DJNZ结束这个回圈,如下所示,若N =10: <>
CJNE指令(比较且不相等时跳跃)也可以使用在回圈控制上,在指令的运算元(operand)栏里共指定了两的位元组,只有在这两个位元组不相等时会产生跳跃。这个指令的另一功能是"大于、小于"的比较,在运算元里的两个位元组被看成无号数(Unsign)的整数,如果第一个位元组小于第二个,则进位旗号C=1,而如果第一个大于或等于第二个位元组则C=0。 布林指令集包含ANL和ORL运算但没有XRL(Exclusive OR)运算,但是XRL运算很容易地由软体模拟,例如:想要作两位元的互斥或C=bit1 XRL bit2可以用如下的软体加以达成: MOV C,bit1 JNB指令是一系列的位元测试指令中一个。它们在被测试的位元为"1"时JC、JB及JBC执行跳跃,或是被测试的位元"0"时JNC、JNB执行跳跃。在上面的例子里,是测试bit2,如果bit=0时,则CPL C这个指令就被跳过。 程序跳跃指令 指令说明周期ACALL addr11绝对式子程序呼叫24LCALL addr16远程子程序呼叫24RET从子程序返回24RETI从中断子程序返回24AJMP addr11绝对式跳跃24LJMP addr16远程跳跃24SJMP rel短程跳跃24JMP @A+DPTR间接跳跃24JZ rel若A=0跳至rel24JNZ rel若A不等于0跳至rel24CJNE A,direct,rel若A不等于direct跳至rel24CJNE A,#data,rel若A不等于data跳至rel24CJNE Rn,#data,rel<>若Rn不等于data跳至rel24CJNE @Ri,#data,rel若Ri不等于data跳至rel24DJNZ Rn,relRn减1不等于0跳至rel24DJNZ direct,reldirect减1不等于0跳至rel24NOP没动作12 对于以上的条条件式跳跃指令的目的位址,可以使用标记(label)或用程序记忆体的实际位址以指定给组译器使用。然而组译出来的目的位址是一个相对偏移值的位元组,且是一个带符号(2补数)的偏移值,如果跳跃被执行的话,则这个位元组的值会以2补数的加法加入PC里。因此条件式跳跃的范围就从跳跃指令的下一个位址算起在- 128至+ 127之间。 跳跃指令: 在表中的" JMP addr"指令,实际上总共有三种------既SJMP、LJMP和AJMP------它们在目的位址的格式上有所不同,如果程序不管跳跃指令的解码方式的话,JMP这个指令可作一般指令使用。 SJMP这个指令将目的的位址编码成如上面所讨论的相对偏移位址,这个指令要使用2位元组长,既包括有操码(opcode)和偏移值(offset),此时跳跃的距离就限制在SJMP指令下一个指令位址的-128至+127之间。 LJMP指令是将目的的位址编码成16位元的常数。这个指令共占了3位元组,包括操作和两位元组的位址。如此LJMP就可跳至64K程序记忆体的任何一个位址。 AJMP指令将目的的位址编码成11位元的常数,这个指令共占2位元组,包括一个操作码,此操作码中的3个位元是11位址位元中的一部分,接下去的一个位元组就是位址的低阶八位元。当执行这个指令时,这11位元就取代了PC的低阶11位元,而PC的高阶5位元不变,因此目的位址必须在AJMP指令的下一个指令位址算起的2K区域内。 在任何情况下,写程序的人都是以标记(Label)或16位元常数去指定目的位址,组译器(Assembler)会转成正确的值给指令。如果跳跃的距离超过了指令所能达到的范围时,组译器会输出"Destinationout of rang"的讯息。 JMP @A+DPTR指令是一个间接跳跃指令。其跳跃的目的位址会在程序执行中计算16位元的DPTR和累加器的和,通常DPTR是指到一个跳跃表的位址,而累加器是表里的索引,例如:要作5条通路的跳跃时,可将整数0至4载入累加器,其程序如下面所列:
上面程序的RL A指令是将索引值(0~4)转换成0至8的偶数值范围,因为在跳跃表里的每个进入点是2位元长. 表里所列的"CALL addr"指令也包括有两种指令----LCALL和ACALL,它们只是位址格式不同。 CALL是使用在不在乎什么位址编码方式时。 LCALL指令使用16位址格式,此时副程序可以在64K程序记忆体李的任一位址。而ACALL指令是使用11位元的格式,因此副程序必须在ACALL的下一位址算起的2K区域范围。在任何一种情况下,写程序的人可以以相同的方法指定副程序的位址给组译器:既使用标记或16位元的常数。组译器会放入正确的格式给组译令。 副程序必须以RET指令作结束,它会反回CALL的下一个指令去执行。 RETI是在中断服务程序反回使用,RET和RETI之间仅有的不同点是RETI会告诉中断控制系统,中断事件以作完,如果在没中断的情况下执行了RETI指令时,则RETI与RET在功能上是相同的。 MCS-51的条件跳跃指令所有跳跃指令所跳到的目的位址都是以相对偏移的方法指定,因此跳跃的距离是从这个指令的下一位址算起的-128至+127之间。重要一点是,写程序时只要告诉组译器直接位址或标记(label)就可以了,与其他的跳跃指令一样,组译器会算出正确的偏移值。 在PSW里并没有零旗号位址,因此MCS-51使用JZ和JNZ指令去测试累加器的内容是否为零。 DJNZ指令(递减且不为零时跳跃)是用来作回路控制用,要执行N次的回圈时,可将N载入计数器,然后用DJNZ结束这个回圈,如下所示,若N =10: <>
CJNE指令(比较且不相等时跳跃)也可以使用在回圈控制上,在指令的运算元(operand)栏里共指定了两的位元组,只有在这两个位元组不相等时会产生跳跃。这个指令的另一功能是"大于、小于"的比较,在运算元里的两个位元组被看成无号数(Unsign)的整数,如果第一个位元组小于第二个,则进位旗号C=1,而如果第一个大于或等于第二个位元组则C=0。 |