用这些指令,我们将在以后的课程中结合具体的实验加以介绍。为了加深印象,大家可以用DUBG8051 软件对上述指令进行反复练习,用
实验结果来加深课堂知识。 单片机经典教程13 单片机指令(三)
算术、逻辑运算类指令也是单片机中极为重要的指令系统,在很多教科书中都把它们归为一类,实际上它们还是有区别的,为了让大家便于记忆,这里把它们分了开来。在单片机中,算术运算类指令有24 条;逻辑运算类指令有25 条。这一课我们先来讲解算术运算类指令,下面我们分别加以讲解: 一.算术运算类指令 1。不带进位的加法指令
(1)ADD A,Rn ;例:ADD A,R7 (2)ADD A,@Ri ;例:ADD A,@R1 (3)ADD A,direct;例:ADD A,30H
(4)ADD A,#data ;例:ADD A,#30H指令说明:这些指令的意思就是把后面的值与A 中的值相加,结果送到A 中去。举例:MOV A,30H ;
ADD A,10H ;执行结果A=40H 2。带进位的加法指令
(1)ADDC A,Rn ;例:ADDC A,R7 (2)ADDC A,@Ri ;例:ADDC A,@R1 (3)ADDC A,direct;例:ADDC A,30H (4)ADDC A,#data ;例:ADDC A,#30H
指令说明:这些指令的作用都是将A 中的值和其后面的值相加,并且加上进位位CY 中的值。为什么要这样做呢?我们知道51 单片机是一种8 位单片机,所以只能做8 位的数学运算,也就是说最大运算的范围只能是0-255 ,这在实际工作中是不够的,因此就要进行扩展,怎么扩展,就是将2 个8 位的数学运算合起来,成为一个16 位的运算,这样可以表达的数的范围就能达到0-65535 。如何合并呢?其实很简单,让我们看一个十进制数的加法例子:66+78 ,这两个数相加,我们根本不会在意它的过程,但事实上我们是这样做的:先做6+8 (低位),然后再做6+7 ,这是高位。做了两次加法,只是我们做的时候并没有刻意分成两次加法来做罢了,或者说我们并没有意识到我们做了两次加法,之所以要分成两次来做,是因为这两个数超过了一位数所能表达的范置(0-9)。在做低位时产生了进位,我们通常的办法是在适当的位置点一下,然后在做高位加法时将这一点加进去;其实计算机中做16 位加法时同样如此,先做低8 位的,如果两数相加产生了进位,也要“点一下”做个标记,这个标记就是进位位CY,在PSW 中,我们前面已经讲过,在进行高位加法时将这个CY 加进去。例如做2 个16 进制数相加:1067H+10A0H ,先做67H+A0H=107H ,而107H 显然超过了0FFH ,因此最终保存在A 中的是7,而1 则进到了PSW 中的CY 位去了,换言之,CY 位就相当于是100H ,然后再做10H+10H+CY ,结果是21H ,所以最终的结果是2107H。 3。带借位的减法指令
(1)SUBB A,Rn ;(2)SUBB A,@Rn ;(3)SUBB A,direct;(4)SUBB A,#data ;
指令说明:没有不带借位的减法指令,如果需要做不带借位的减法指令(在做第一次相减时),只要将CY 清零即可。 4.乘法指令 (1)MUL AB ;
指令说明:此指令的功能是将A 和B 中的两个8 位无符号数相乘,两数相乘结果一般比较大,因此最终结果用1 个16 位数来表达,其中高8 位放在B 中,低8 位放在A 中。在乘积大于FFFFFH(65535)时,PSW 的0V 位置“1”(溢出),否则OV 为“0”,而CY 位总是为“0”。
例:(A)=4EH,(B)=5DH;MUL AB ;乘积是1C56H,所以在B 中放的是1CH,而A 中放的则是56H。 5.除法指令 (1)DIV AB(A/B)
指令说明:此指令的功能是将A 中的8 位无符号数除以B 中的8 位无符号数(什么是无符号数?简单的说就是没有负数的数,也就是整数,比如1,2,3,1.2,4.5 等等这样的数)。除法一般会出现小数,但计算机中可没法直接表达小数,它用的是我们小学生用的商和余数的概念,如13/5 ,其商是2,余数是3。除了以后,商放在A 中,余数放在B 中。CY 位和OV 位都是“0”,如果在做除法前B 中的值是00H,也就是除数为0,那么0V=1。 6.加1 指令
(1)INC A ;例如:A=20H INC A; A=21H (2)INC Rn ;例如:R7=20H INC A; R7=21H (3)INC direct;例如:30H=20H INC 30H; 30H=21H (4)INC @Ri ;例如:
(5)INC DPTR ;例如:DPTR=20H INC DPTR; DPTR=21H
指令说明:从结果上看INC A 和ADD A,#1 差不多,但INC A 是单字节单周期指令,而ADD A,#1 则是双字节双周期指令,而且INC A 不会影响PSW 位,如(A)=0FFH,INC A 后(A)=00H ,而CY 依然保持不变;如果是ADD A ,#1,则(A)=00H ,而CY 一定是“1”。因此加1 指令并不适合做加法,事实上它主要是用来做计数、地址增加等用途。另外,加法类指令都是以A 为核心的,其中一个数必须放在A 中,而运算结果也必须放在A 中,而加1 类指令的对象则广泛得多,可以是寄存器、内存地址、间址寻址的地址等等。 7.减1 指令
(1)DEC A ;例如:A=20H DEC A; A=19H (2)DEC Rn ;例如:R7=20H DEC A; R7=19H (3)DEC direct;例如:30H=20H DEC 30H; 30H=19H (4)DEC @Ri ;例如:
指令说明:既然加1 指令可以用于计数、定时、地址等加1,那么有加也必然有减,所以减1 指令的功能与加1 指令类似,这里就不多说了。
8.十进制加法调整指令
DA A ;这是一条对十进制加法进行调整的指令,等下册用到时再介绍。
另外需要了解的是:在算术运算类指令中,除了加1 和减1 指令外,其他的算术运算类指令都要把结果放到累加器A 中,这与数据传递类指令有所不同。二.逻辑运算类指令
什么是逻辑运算?相信大家不会陌生,在数字电路中我们学过“与门”、“或门”、“非门”等,在单片机中也有类似的运算。那么它们是如何分类的呢?接下来我们就来一一讲解,先来看对累加器A 的逻辑运算指令: 1。对累加器A 的逻辑运算指令 (1)CLR A
指令说明:累加器A 清零。效果同MOV A,#00H 是一样的,只不过它是单周期指令,而MOV A,#00H 是双周期指令。 (2)CPL A
指令说明:将累加器A 逐位取反。相当于数字电路的“非”逻辑,例如:A=12H CPL A ;12H 化为二进制是00010010,逻辑取反后为11101101,即A=EDH。 (3) RL A
指令说明:将累加器A 的值逻辑左移。例如:A=12H RL A;化为二进制为00010010 ,逐位左移后为0010100 ,即24H 。这里把第7 位移到了第0,第0 位移到了第1 位,第1 位移到了第2 位,其余的依次类推。(4)RLC A
指令说明:加上进位位CY 并逻辑左移。例如:CY=1 A=12H RLC A;加上进位位CY 后1 00010010 逻辑左移变为0 00100101(即CY=0,A=25H)。(5)RR A
指令说明:将累加器A 中的值逻辑右移。同RL A 类似。 (6)RRC A
指令说明:加上进位位CY 并逻辑右移。同RLC A 类似。 (7)SWAP A
指令说明:将A 中的值的高、低4 位进行交换。例如:(A)=39H,SWAP A 之后,A 中的值就是93H 。怎么正好是这么前后交换呢?因为这是一个十六进制数,每1 个十六进位数代表4 个二进制数。注意?,如果是这样的:(A)=39D ,后面没加H,执行SWAP A 之后,可不是(A)=93 。要将它化成二进制数再算:39D 化为二进制是10111 ,也就是0001,0111 高4 位是0001 ,低4 位是0111 ,交换后是01110001,也就是71H,即113D。 2。两个寄存器之间的逻辑运算指令
上面的指令都是针对累加器A 的逻辑运算指令,也就是说对一个寄存器的逻辑运算,那么如果两个寄存器之间的逻辑运算又是怎么样的呢?接着往下看:
指令说明:什么是逻辑“与”?数字电路中我们已经学过:就是F=A*B ,简记为“全1 出1,有0 出0”。如果忘了,没关系,找本书再看一下,这里就不详细的阐述了。
例如:71H 和56H 相“与”,将两数写成二进制形式:(71H) 01110001 和(56H) 00100110 。逐位相“与”结果就是00100000 即20H,从上面的例子可以看出,两个参与运算的值只要其中有一个位上是“0”,则这位的结果就是“0”,两个同是“1”,结果才是“1”,是不是符合逻辑“与”的结果?
知道了逻辑“与”指令的功能后,逻辑“或”和逻辑“异或”的功能就很简单了。逻辑“或”是逐位相“或”,即有1 出1,全0 出0。例:71H 和56H 相“或”结果就是77H ;而“异或”则是逐位“异或”,即相同出0,相异出1。仍旧71H 和56H 相“异或”,结果是57H。两个寄存器之间的逻辑“或”以及逻辑“异或”的指令如下:(2)ORL A,Rn ;A 与Rn 中的值按位‘或’,结果送入A 中 ORL A,direct ;A 与direct 中的值按位‘或’,结果送入A 中 ORL A,@Ri ;A 与间址寻址单元@Ri 中的值按位‘或’,结果送入A 中 ORL A,#data ;A 与立即数data 按位‘或’,结果送入A 中
ORL direct,A ;direct 中值与A 中的值按位‘或’,结果送入direct 中
ORL direct,#data ;direct 中的值与立即数data 按位‘或’,结果送入direct 中。(3)XRL A,Rn ;A 与Rn 中的值按位‘异或’,结果送入A 中XRL A,direct ;A 与direct 中的值按位‘异或’,结果送入A 中
XRL A,@Ri ;A 与间址寻址单元@Ri 中的值按位‘异或’,结果送入A 中XRL A,#data ;A 与立即数data 按位‘异或’,结果送入A 中XRL direct,A ;direct 中值与A 中的值按位‘异或’,结果送入direct 中 XRL direct,#data;direct 中的值与立即数data 按位‘异或’,结果送direct 中。
连续好几节课将讲了许多的基本知识,大家是不是又觉得有些枯燥和无聊了,别急,接下来让我们轻松一下,做一个实验来证明一下几节课所学的内容:
START:MOV SP,#5FH ; MOV A,#80H ; LOOP:MOV P1,A ; RL A ; LCALL DELAY ; LJMP LOOP ; DELAY:MOV R7,#255 ; D1:MOV R6,#255 ; D2:NOP NOP NOP NOP
DJNZ R6,D2 ; DJNZ R7,D1 ; RET ; END。
好久没做实验了,大家还记得实验的步骤吗?调试→编译→下载,看到了什么,有一个暗点在
流动;想象一下,如果我们把P1.0-1.7 的LED 换成8 只可控硅来控制霓虹灯,是不是就有点实用价值了。 2.程序分析:
前面的ORG 0000H 、LJMP START 、ORG 30H 我们以后分析。从START 开始,MOV SP,#5FH,这是初始化堆栈,在本程序中有无此句无关紧要,不过我们慢慢开始接触正规的编程,我也就慢慢地给大家培养习惯吧。MOV A,#80H ,将80H 这个数送到A 中去。干什么呢?不知道,往下看:MOV P1,A 将A 中的值送到P1 端口去,此时A 中的值是80H,所以送出去的也就是80H,因此P1 口的值是80H,也就是二进制10000000 ,对应P1.7-P1.0 这8 位。我们应当知道,此时P1.7 接的LED8 是不亮的,而其它的LED 都是亮的,所以就形成了一个“暗点”,继续往下看,RL A;将A 中的值进行左移,算一下,移之后的结果是什么?对了,是01H ,也就是二进制00000001 ,这样,应当是接在P1.0 上的LED1 不亮了,而其它的都亮了,从现象上看就是“暗点”移到了后面;然后是调用延时程序,这里有一条指令NOP,它是空操作指令,也就是什么都不做,用于短暂的延时,其他的指令我们很熟悉了,就是让这个“暗点”暗一会儿,然后又跳转到LOOP 处(LJMP LOOP),请大家计算一下,下面该哪个灯不亮了??对了,应当是接在P1.1 上灯不亮了,这样依次不断的循环,就形成了“暗点流动”的现象。
单片机经典教程14 单片机指令(四) 控制转移类指令
控制转移类指令共有17 条,分为无条件转移指令、条件转移指令和返回及调用指令三大类,下面我们分别加以学习: 1.无条件转移类指令
(1)无条件绝对转移指令:AJMP addr11 (2)无条件长转移指令:LJMP addr16 (3)无条件相对转移指令:SJMP rel
在讲解上面这三条指令之前先来认识一下三个符号:add11 、add16 、rel。其中add11 和add16 表示外部ROM 的16 位和11 位地址,前面我们已经讲过,单片机的外部ROM 可以扩展到64K,add16 就表示64K 程序存储器的任何地址,换句话说LJMP 指令可以跳转到程序的任何地方,而add11 则表示下一条指令的2K 页面,也就是说,SJMP 指令只能跳转到程序的2K 范围之内;rel 表示8 位的偏移量,其范围是下一条指令第一字节的前128 到后127 个字节(即-128-+127B) 。介绍完了三个符号,再看上面的三条转移类指令,如果要仔细分析的话,它们之间其实区别较大,但在初学时,我们可以不理会这么多,统统把它们理解成:(*JMP 标号),比如SJMP LOOP ,就是跳转到有LOOP 标号处。原则上,所有用SJMP 或AJMP 的地方都可以用LJMP 来替代。因此在初学时,需要跳转时可以全用LJMP 代替,除了一个场合,什么场合呢?先看一下AJMP,AJMP 是一条双字节指令,也就说这条指令本身占用存储器(ROM )的两个单元,而LJMP 则是一条三字节指令,即这条指令占用存储器(ROM )的三个单元,这就是区别。下面再来看第4 条跳转指令: (4)无条件间接转移指令:JMP @A+DPTR
这条指令的用途也是跳转,跳转到什么地方去呢?这可不能由标号简单地决定了,让我们从一个实际的例子入手吧: MOV DPTR,#TAB ;将TAB 所代表的地址送入DPTR MOV A,R0 ;从R0 中取数(详见下面说明) MOV B,#2 ; MUL A,B ;
A 中的值乘2 ;(详见下面的说明) JMP A,@A+DPTR ;跳转 TAB: AJMP S1 ;跳转表格 AJMP S2 ; AJMP S3 ;
应用背景介绍:在单片机开发中,经常要用到键盘,见下面的9 个按键的键盘图。我们的要求是:当按下功能键A??G 时去完成不同的功能,这用程序设计语言来表达的话,就是:按下不同的键去执行不同的程序段,以完成不同的功能,怎么样来实现这个功能呢? 看图,前面的程序读入的是按键的值,如按下‘A’键后获得的键值是“0”,按下‘B’键后获得的值是“1”等等,然后根据不同的值进行跳转,如键值为“0”就转到S1 处执行,如键值为“1”就转到S2 处执行,??到底如何来实现这一功能呢?
先从程序的下面看起,是若干条AJMP 语句,这若干条AJMP 语句最后在存储器中是这样存放的(见图),也就是每个AJMP 语句都占用了两个存储器的空间,并且是连续存放的。而AJMP S1 存放的地址是TAB,到底TAB 等于多少,我们不需要知道,把它留给汇编程序来算好了。
下面我们来看这段程序的执行过程:第1 条MOV DPTR,#TAB 执行完了之后,DPTR 中的值就是TAB ,第2 条是MOV A,R0,我们假设R0 是由按键处理程序获得的键值,比如按下‘A’键,R0 中的值是“0”,按下‘B’键,R0 中的值是“1”??以此类推;现在我们假设按下的是‘B’键,则执行完第2 条指令后,A 中的值就是“1”。并且按照我们的分析,按下‘B’后应当执行S2 这段程序,让我们来看一看是否是这样呢?第3 条、第4 条指令是将A 中的值乘“2”,即执行完第4 条指令后A 中的值是“2”,下面就执行JMP @A+DPTR 了,现在
DPTR 中的值是“TAB”,而A+DPTR 后就是“TAB+2”,因此,执行完这条程序后,将会跳到TAB+2 这个地址处继续执行;看一看在TAB+2 这个地址里面放的是什么?就是AJMP S2 这条指令,因此,马上又执行AJMP S2 这条指令,程序将跳到S2 处往下执行,这与我们的要求相符合。请大家自行分析按下键‘A’、‘C’、‘D’??之后的情况。
这样我们用JMP @A+DPTR 这条指令就实现了按下一个键跳转到相应程序段去执行的这样一个要求。再提一个问题,为什么取得键值后要乘“2”呢?如果例程下面的所有指令换成LJMP ,即:LJMP S1,LJMP S2??这段程序还能正确地执行吗?如果不能,应该怎么改? 2.条件转移类指令
条件转移类指令就是在满足一定的条件后进行相对转移。 1 转移指令:JZ rel 2 转移指令:JNZ rel
第1条指令的功能是:如果(A)=0 ,则转移,否则顺序执行(执行本指令的下一条指令),转移到什么地方去呢?如果按照传统的方法,就要算偏移量,很麻烦,好在现在我们可以借助于机器汇编了。因此这条指令我们可以这样理解:JZ 标号,即转移到标号处。下面举一个例子来加以说明:
L1: MOV R1,#0FFH;L2: SJMP L2 ;END
在执行上面这段程序前如果R0 中的值是“0”的话,就转移到L1 标号处执行,因此最终的执行结果是R1 中的值为0FFH ;而如果R0 中的值不等于“0”,则顺序执行,也就是执行 MOV R1,#00H 指令,最终的执行结果是R1 中的值等于“0”。把这个例子中的JZ 改成JNZ 试试吧,看看程序执行的结果是什么?
(3)比较转移指令A.CJNE A,#data,rel B.CJNE A,direct,rel C.CJNE Rn,#data,rel D.CJNE @Ri,#data,rel
指令说明:第1 条指令的功能是将A 中的值和立即数data 比较,如果两者相等,就顺序执行;如果不相等,就转移。同样地,我们可以将rel 理解成标号,即:CJNE A,#data, 标号。这样利用这条指令,我们就可以判断两数是否相等,这在很多场合是非常有用的,但有时还想知道两数比较之后哪个大,哪个小,本条指令也具有这样的功能,如果两数不相等,则CPU 还会反映出哪个数大,哪个数小,这是用CY(进位位)来实现的,如果前面的数(A 中的)大,则CY=0 ;否则CY=1 ,因此在程序转移后再次利用CY 就可判断出A 中的数比data 大还是小了。
例如:MOV A,R0 ; CJNE A,#10H,L1 ; MOV R1,#0FFH ; AJMP L3 ; L1: JC L2 ; MOV R1,#0AAH ; AJMP L3 ; L2: MOV R1,#0FFH ;L3: SJMP L3 ;
上面的程序中有一条指令我们还没学过,即JC,这条指令的原型是JC rel, 作用和上面的JZ 类似,但是它是判CY 是“0”还是“1”进行转移,如果CY=1 ,则转移到JC 后面的标号处执行;如果CY=0 则顺序执行。
分析一下上面的程序,如果(A)=10H ,则顺序执行,即R1=0 ;如果(A)不等于10H ,则转到L1 处继续执行,在L1 处,再次进行判断,如果(A)>10H ,则CY=1 ,将顺序执行,(即执行MOV R1,#0AAH 指令);而如果(A)<10H ,则将转移到L2 处指行,(即执行MOV R1,#0FFH 指令)。因此最终结果是:本程序执行前,如果(R0)=10H ,则(R1)=00H ;如果(R0)>10H ,则(R1)=0AAH ;如果(R0)<10H,则(R1)=0FFH。
弄懂了这条指令,其它的几条就类似了,第2 条是把A 当中的值和直接地址中的值比较,第3 条则是将直接地址中的值和立即数比较,第4 条是将间址寻址得到的数和立即数比较,这里就不解释了,请大家自行分析一下。下面给出几个相应的例子:
CJNE A,10H;把A 中的值和10H 中的值比较(注意和上题的区别)CJNE 10H,#35H;把10H 中的值和35H 中的值比较CJNE @R0,#35H;把R0 中的值作为地址,从此地址中取数并和35H 比较 (4)循环转移指令A.DJNZ Rn,rel B.DJNZ direct,rel
第1条指令在前面的实验中已经有详细的分析,这里就不解释了;第2条指令,只是将Rn 改成直接地址,其它的也一样。 3.调用及返回指令
在前面的实验中,我们已用过了子程序,只是我们并没有明确地介绍。子程序是干什么用的,为什么要用子程序呢?举个例子,我们数学老师布置了10 道算术题,经过观察,每一道题中都包含一个(5+2)
*3 的运算。我们可以有两种选择,第一种选择,每做一道题,都把这个算式算一遍;第二种选择,我们可以先把这个结果算出来(也就是21),放在一边,然后要用到这个算式时就将21 代进去,这两种方法哪种更好呢?那就不必多言了吧。设计程序时也是这样,有时候一个功能会在程序的不同地方反复使用,我们就可以把这个功能设计成一段程序,每次需要用到这个功能时就“调用”一下,这就是子程序的用途所在,后面我们还会更详细地讲解子程序的用法。
主程序调用了子程序,子程序执行完之后必须再返回到主程序继续执行,不能“一去不回头”, 那么回到什么地方呢?就是回到调用子程序的下面一条指令处继续执行(当然啦,要是还回到这条指令,不又要再调用子程序了吗?那可就没完没了了??)。大家可以回去看一下前面的实验,是不是这样做的? 1 调用指令
2 长调用指令:LCALL addr16 3 短调用指令:ACALL addr11
上面两条指令都是在主程序中调用子程序,两者的区别大家结合前面的知识可以自己分析一下。同样作为初学者,我们可以不必加以区分,也就是说可以用LCALL 指令代替ACALL。
1 返回指令 2 子程序返回:RET 3 中断返回:RETI
RET 用于子程序返回,RETI 用于中断程序返回,这是有区别的,可不能用错了,至于什么是中断返回,我们讲到中断时再来解释。如何从子程序返回呢?很简单,就是执行RET 指令,看一下前面的实验。 10。空操作指令:NOP
所谓空操作,就是什么事也不干,停一个机器周期,一般用作短时间的延时,这个我们已经讲过了。 单片机经典教程15 单片机指令(五) 一.位及位操作指令
位操作指令也叫布尔操作指令。什么是布尔指令?它有什么用呢?这个问题稍微有点复杂,我只能给大家简单的介绍一下。在MCS-51 系列单片机中,有一个功能很强的布尔处理器,它实际上是一个独立的一位处理器,它有一套专门处理布尔变量(布尔变量也叫开关变量,就是以位作为单位的运算和操作)的指令子集,以完成对布尔变量的传送、运算、转移、控制等操作,这个子集的指令就是布尔操作指令。那么为什么要有这样的一套的指令系统?它是如何操作的呢?大家接着往下看: 1.位寻址的概念
为什么要位寻址呢?单片机不是可以有多种寻址方式吗?大家是否还记得,我们第十三课做的那个流水灯实验,用的就是“位”操作,也就是对一盏灯的亮和灭进行控制,而之前我们学的指令却全都是用“字节”来介绍的:字节的移动、加减法、逻辑运算、移位等等,用字节来处理一些数学问题(比如控制空调的温度、电视机的音量等等)非常直观,可以直接用数值来表示;可是如果用它来控制一个开关的打开或者合上,灯的亮或者灭,就有些不直接了。比如我们前面课上的那个流水灯的实验,我们把数值送往P1 口之后并不能马上知道是哪个LED 灭了,而是要化成二进制后才能知道。在工业控制中有很多场合需要处理这类单个的开关输出,比如一个继电器的吸合或者释放、一个指示灯的亮或者灭,用字节来处理就显得有些麻烦了,所以在51 系列单片机中就特意引入了一个位处理机制。那么位处理器有多少地址空间?哪些特殊功能寄存器可以直接进行位寻址呢? 2.可位寻址的特殊功能寄存器
在MCS-51 单片机中,位地址的范围在00H-FFH 之间,其中低128 位处于内部RAM 的20H-2FH 字节单元,其位地址从00H-7FH,看下面的表:
在物理实体上它们与原来的以字节寻址的RAM 及端口是完全一样的,换句话说这些RAM 单元及端口都可以有两种用法。
除此之外,从80H 单元开始除了程序计数器PC 和4 个工作寄存器区外,每8 个字节还安排了21 个特殊功能寄存器(89C52 有26 个),这些SFR 都有一个共同的特点:就是其字节地址均可被8 整除,大家回到前面看一下第九课的表格。这些SFR 都是具有位寻址功能的,也就是说这些RAM 单元的每一个位都可以直接用这个地址来对其直接进行操作。了解了位操作的原理,再来看位操作的指令: 4.位操作指令
(1)位传送指令A.MOV C,bit B.MOV bit,C
指令说明:这两条指令的功能是实现进位位和其它位地址之间的数据传递(这里bit 就是位的意思)。例如:MOV P1.0,CY ;将CY 中的状态送到P1.0 引脚上去(如果是做算术运算,我们就可以通过观察知道现在CY 是多少了)。再如:MOV P1.0,CY;将P1.0 的状态送给CY。
(2)位清零指令A.CLR C B.CLR bit
指令说明:第1 条指令使CY=0 ;第2 条指令使指定的位地址等于“0”。例如:CLR P1.0 ,使P1.0 为“0”。 (3)位置1 指令A.SETB C B.SETB bit
指令说明:第1 条使CY=1 ;第2 条使指定的位地址等于“1”,例如:SETB P1.0 ,使P1.0 为“1”。 (4)取反指令A.CPL C B.CPL bit
指令说明:第1 条使CY 等于原来的相反的值,即由“1”变为“0”,由“0”变为“1”;第2 条使指定位的值等于原来相反的值,(相当于做“非”运算)。例如:CPL P1.0 ,以我们做过的实验为例,如果原来灯是亮的,则执行本指令后灯就灭了;反之就是灯亮。 (5)位逻辑“与”指令A.ANL C,bit B.ANL C,/bit
指令说明:第1 条CY 位与指定的位地址的值相“与”,结果送回CY;第2 条先将指定的位地址中的值取出后取反,再和CY 相“与”,结果送回CY,但需注意?,指定的位地址中的值本身并不发生变化。例如:ANL C,/P1.0 设:执行本指令前,CY=1,P1.0 等于“1”(灯灭),则执行完本指令后CY=0,而P1.0 仍等于“1”。可用下列程序进行验证:
START:MOV SP,#5FH ; MOV P1,#0FFH; SETB C ; ANL C,/P1.0 ;MOV P1.1,C ;将做完的结果送P1.1, 结果应当是P1.1 上的灯亮,而P1.0 上的灯还是亮。
(6)位逻辑“或”指令A.ORL C,bit B.ORL bit,C
这两条指令的功能大家自行分析吧,然后对照上面的例程,自己编一个验证程序,看看自己想得对不对? (7)判CY 条件转移指令A.JC rel B.JNC rel
指令说明:这两条指令叫做判CY 转移指令,第1 条指令的功能是如果CY 等于“1”就转移;如果不等于“1”就顺序执行,那么转移到什么地方去呢?我们可以这样理解:JC 标号,即如果等于“1”就转到标号处执行;第2 条指令则和第1 条指令正好相反,即如果CY=0 就