经过前面的学习,咱们现已了解了单片机内部的结构,而且也现已知道,要操控单片机,让它为咱们干学,要用指令,咱们已学了几条指令,但很零星,从现在开端,咱们即将体系地学习8051的指令部份。
一、概述
1、指令的格局
咱们已知,要让计算机干事,就得给计算机以指令,而且咱们已知,计算机很“笨”,只能懂得数字,如前面咱们写进机器的75H,90H,00H等等,所以指令的榜首种格局便是机器码格局,也说是数字的办法。但这种办法实在是尴尬咱们人了,太难记了,所以有另一种格局,助记符格局,如MOV P1,#0FFH,这样就好记了。 这两种格局之间的联系呢,咱们不难理解,本质上它们彻底等价,仅仅办法不相同罢了。
2、汇编
咱们写指令运用汇编格局,而计算机只懂机器码格局,所以要将咱们写的汇编格局的指令转化为机器码格局,这种转化有两种办法:手艺汇编和机器汇编。手艺汇编实际上便是查表,因为这两种格局纯粹是格局不同,所以是一一对应的,查一张表格就行了。不过手艺查表总是嫌费事,所以就有了计算机软件,用计算机软件来代替手艺查表,这便是机器汇编。
二、寻址
让咱们先来温习一下咱们学过的一些指令:MOV P1,#0FFH,MOV R7,#0FFH这些指令都是将一些数据送到相应的方位中去,为什么要送数据呢?榜首个因为送入的数能够让灯全灭掉,第二个是为了要完成延时,从这儿咱们能够看出来,在用单片机的编程言语编程时,常常要用到数据的传递,事实上数据传递是单片机编程时的一项重要作业,一共有28条指令(单片机共111条指令)。下面咱们就从数据传递类指令开端吧。
剖析一下MOV P1,#0FFH这条指令,咱们不难得出结论,榜首个词MOV是指令动词,也便是决议做什么作业的,MOV是MOVE少写了一个E,所以便是“传递”,这便是指令,规则做什么作业,后边还有一些参数,剖析一下,数据传递有必要要有一个“源”也便是你要送什么数,有必要要有一个“意图”,也便是你这个数要送到什么当地去,明显在上面那条指令中,要送的数(源)便是0FFH,而要送达的当地(意图地)便是P1这个寄存器。在数据传递类指令中,均将意图地写在指令的后边,而将源写在终究。
这条指令中,送给P1是这个数自身,换言之,做完这条指令后,咱们能够明确地知道,P1中的值是0FFH,但是并不是任何时分都能够直接给出数自身的。例如,在咱们前面给出的延时程序例是这样写的:
MAIN: SETB P1.0 ;(1)
LCALL DELAY ;(2)
CLR P1.0 ;(3)
LCALL DELAY ;(4)
AJMP MAIN ;(5)
;以下子程序
DELAY: MOV R7,#250 ;(6)
D1: MOV R6,#250 ;(7)
D2: DJNZ R6,D2 ;(8)
DJNZ R7,D1 ;(9)
RET ;(10)
END ;(11)
表1
MAIN: SETB P1.0 ;(1)
MOV 30H,#255
LCALL DELAY ;
CLR P1.0 ;(3)
MOV 30H,#200
LCALL DELAY ;(4)
AJMP MAIN ;(5)
;以下子程序
DELAY: MOV R7,30H ;(6)
D1: MOV R6,#250 ;(7)
D2: DJNZ R6,D2 ;(8)
DJNZ R7,D1 ;(9)
RET ;(10)
END ;(11)
这样一来,我每次调用延时程序延时的时刻都是相同的(大致都是0.13S),假如我提出这样的要求:灯亮后延时时刻为0.13S灯灭,灯灭后延时0.1秒灯亮,如此循环,这样的程序还能满足要求吗?不能,怎样办?咱们能够把延时程序改成这样(见表2):调用则见表2中的主程,也便是先把一个数送入30H,在子程序中R7中的值并不固定,而是依据30H单元中传过来的数确认。这样就能够满足要求。
从这儿咱们能够得出结论,在数据传递中要找到被传递的数,许多时分,这个数并不能直接给出,需求改变,这就引出了一个概念:怎样寻觅操作数,咱们把寻觅操作数地点单元的地址称之为寻址。在这儿咱们直接运用数地点单元的地址找到了操作数,所以称这种办法为直接寻址。除了这种办法之外,还有一种,假如咱们把数放在作业寄存器中,从作业寄存器中寻觅数据,则称之为寄存器寻址。例:MOV A,R0便是将R0作业寄存器中的数据送到累加器A中去。提一个问题:咱们知道,作业寄存器便是内存单元的一部份,假如咱们挑选作业寄存器组0,则R0便是RAM的00H单元,那么这样一来,MOV A,00H,和MOV A,R0不就没什么差异了吗?为什么要加以区别呢?确实,这两条指令履行的成果是彻底相同的,都是将00H单元中的内容送到A中去,但是履行的进程不同,履行榜首条指令需求2个周期,而第二条则只需求1个周期,榜首条指令变成终究的方针码要两个字节(E5H 00H),而第二条则只需一个字节(E8h)就能够了。
这么锱铢必较!不就差了一个周期吗,假如是12M的晶振的话,也就1个微秒时刻了,一个字节又能有多少?
不对,假如这条指令只履行一次,或许无所谓,但一条指令假如履行上1000次,便是1毫秒,假如要履行1000000万次,便是1S的差错,这就很可观了,单片机做的是实时操控的事,所以有必要如此“锱铢必较”。字节数相同如此。
再来提一个问题,现在咱们已知,寻觅操作数能够经过直接给的办法(当即寻址)和直接给出数地点单元地址的办法(直接寻址),这就够了吗?
看这个问题,要求从30H单元开端,取20个数,别离送入A累加器。
就咱们现在把握的办法而言,要从30H单元取数,就用MOV A,30H,那么下一个数呢?是31H单元的,怎样取呢?仍是只能用MOV A,31H,那么20个数,不是得20条指令才干写完吗?这儿只要20个数,假如要送200个或2000个数,那岂不要写上200条或2000条指令?这不免太笨了吧。为什么会呈现这样的情况?是因为咱们只会把地址写在指令中,所以就没办法了,假如咱们不是把地址直接写在指令中,而是把地址放在别的一个寄存器单元中,依据这个寄存器单元中的数值决议该到哪个单元中取数据,比方,当时这个寄存器中的值是30H,那么就到30H单元中去取,假如是31H就到31H单元中去取,就能够处理这个问题了。怎样个处理法呢?既然是看的寄存器中的值,那么咱们就能够经过必定的办法让这儿面的值发生改变,比方取完一个数后,将这个寄存器单元中的值加1,仍是履行同一条指令,但是取数的目标却不相同了,不是吗。经过比如来阐明吧。
MOV R7,#20
MOV R0,#30H
LOOP:MOV A,@R0
INC R0
DJNZ R7,LOOP
这个比如中大部份指令咱们是能看懂的,榜首句,是将当即数20送到R7中,履行完后R7中的值应当是20。第二句是将当即数30H送入R0作业寄存器中,所以履行完后,R0单元中的值是30H,第三句,这是看一下R0单元中是什么值,把这个值作为地址,取这个地址单元的内容送入A中,此刻,履行这条指令的成果就相当于MOV A,30H。第四句,没学过,便是把R0中的值加1,因而履行完后,R0中的值便是31H,第五句,学过,将R7中的值减1,看是否等于0,不等于0,则转到标号LOOP处持续履行,因而,履行完这句后,将转去履行MOV A,@R0这句话,此刻相当于履行了MOV A,31H(因为此刻的R0中的值已是31H了),如此,直到R7中的值逐次相减等于0,也便是循环20次停止,就完成了咱们的要求:从30H单元开端将20个数据送入A中。
这也是一种寻觅数据的办法,因为数据是间接地被找到的,所以就称之为间址寻址。留意,在间址寻址中,只能用R0或R1寄存等寻觅的数据。
二、指令
数据传递类指令 1) 以累加器为意图操作数的指令
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。
2)以寄存器Rn为意图操作的指令
MOV Rn,A
MOV Rn,direct
MOV Rn,#data
这组指令功用是把源地址单元中的内容送入作业寄存器,源操作数不变。