平凡的单片机教程 自学单片机第11页共60页 90HP1口锁存器 IH18DH定时器计数器1(高8位) TH08CH定时器/计数器1(低8位) 18H定时器计数器0(高8位) L08AH定时器/计数器0(低8位) TMOD89A定时器计数器方式控制寄存器 TCON88H定时器/计数器控制寄存器 DPH83H数据地址指针(高8位) DPL82H数据地址指针(低8位) 81H堆栈指针 80HP0口锁存器 PCON87H电源控制寄存器 下面,我们介绍一下几个常用的SFR,看图2。 ACC:累加器,通常用A表示。这是个什么东西,可不能从名字上理解,它是一个寄存器,而不是一个做加法 的东西,为什么给它这么一个名字呢?或许是因为在运算器做运算时其中一个数一定是在ACC中的缘故吧。它 的名字特殊,身份也特殊,稍后我们将学到指令,可以发现,所有的运算类指令都离不开它。 2、B:一个寄存器。在做乘、除法时放乘数或除数,不做乘除法时,随你怎么用。 3、PSW:程序状态字。这是一个很重要的东西,里面放了CPU工作时的很多状态,借此,我们可以了解CPU 的当前状态,并作出相应的处理。它的各位功能请看表2 D7 D6 D5 D4 D3 D2 DI DO CY AC FO RSI RSO OV 表2 下面我们逐一介绍各位的用途 (1)CY:进位标志。8051中的运算器是一种8位的运算器,我们知道,8位运算器只能表示到0-255,如果做 加法的话,两数相加可能会超过255,这样最高位就会丢失,造成运算的错误,怎么办?最高位就进到这里来。 这样就没事了。 例:78H+97H(011110010010111) (2)AC:半进位标志 例:57H+3AH(0101011+00111010) (3)F0:用户标志位,由我们(编程人员)决定什么时候用,什么时候不用 (4)RS1、RS0:工作寄存器组选择位。这个我们已知了。 (5)0V:溢出标志位。什么是溢出我们稍后再谈吧。 (6)P:奇偶校验位:它用来表示ALU运算结果中二进制数位“1”的个数的奇偶性。若为奇数,则P=1,否则
平凡的单片机教程 自学单片机第 11 页 共 60 页 11 P1 90H P1 口锁存器 TH1 8DH 定时器/计数器 1(高 8 位) TH0 8CH 定时器/计数器 1(低 8 位) TL1 8BH 定时器/计数器 0(高 8 位) TL0 8AH 定时器/计数器 0(低 8 位) TMOD 89A 定时器/计数器方式控制寄存器 TCON 88H 定时器/计数器控制寄存器 DPH 83H 数据地址指针(高 8 位) DPL 82H 数据地址指针(低 8 位) SP 81H 堆栈指针 P0 80H P0 口锁存器 PCON 87H 电源控制寄存器 表 1 下面,我们介绍一下几个常用的 SFR,看图 2。 ACC:累加器,通常用 A 表示。这是个什么东西,可不能从名字上理解,它是一个寄存器,而不是一个做加法 的东西,为什么给它这么一个名字呢?或许是因为在运算器做运算时其中一个数一定是在 ACC 中的缘故吧。它 的名字特殊,身份也特殊,稍后我们将学到指令,可以发现,所有的运算类指令都离不开它。 2、B:一个寄存器。在做乘、除法时放乘数或除数,不做乘除法时,随你怎么用。 3、PSW:程序状态字。这是一个很重要的东西,里面放了 CPU 工作时的很多状态,借此,我们可以了解 CPU 的当前状态,并作出相应的处理。它的各位功能请看表 2 D7 D6 D5 D4 D3 D2 D1 D0 CY AC F0 RS1 RS0 OV P 表 2 下面我们逐一介绍各位的用途 (1)CY:进位标志。8051 中的运算器是一种 8 位的运算器,我们知道,8 位运算器只能表示到 0-255,如果做 加法的话,两数相加可能会超过 255,这样最高位就会丢失,造成运算的错误,怎么办?最高位就进到这里来。 这样就没事了。 例:78H+97H(01111000+10010111) (2)AC:半进位标志。 例:57H+3AH(01010111+00111010) (3)F0:用户标志位,由我们(编程人员)决定什么时候用,什么时候不用。 (4)RS1、RS0:工作寄存器组选择位。这个我们已知了。 (5)0V:溢出标志位。什么是溢出我们稍后再谈吧。 (6)P:奇偶校验位:它用来表示 ALU 运算结果中二进制数位“1”的个数的奇偶性。若为奇数,则 P=1,否则
平凡的单片机教程 自学单片机第12页共60页 为0 例:某运算结果是78H(01100显然1的个数为偶数,所以P=0。 4、DPIR(DPH、DPL):数据指针,可以用它来访问外部数据存储器中的任一单元,如果不用,也可以作为通 用寄存器来用,由我们自已决定如何使用 5、P0、P1、P2、P3:这个我们已经知道,是四个并行输入输出口的寄存器。它里面的内容对应着管脚的输出 6、SP:堆栈指针 堆栈介绍:日常生活中,我们都注意到过这样的现象,家里洗的碗,一只一只摞起来,最晚放上去的放在最上面 而最早放上去的则放在最下面,在取的时候正好相反,先从最上面取,这种现象我们用一句话来概括:“先进后 出,后进先出”。请大家想想,还有什么地方有这种现象?其实比比皆是,建筑工地上堆放的砖头、材料,仓库 里放的货物,都是“先进后出,后进先出”,这实际是一种存取物品的规则,我们称之为“堆栈 在单片机中,我们也可以在RAM中构造这样一个区域,用来存放数据,这个区域存放数据的规则就是“先进后 出,后进先出”,我们称之为“堆栈”。为什么需要这样来存放数据呢?存储器本身不是可以按地址来存放数据吗? 对,知道了地址的确就可以知道里面的内容,但如果我们需要存放的是一批数据,每一个数据都需要知道地址那 不是麻烦吗?如果我们让数据一个接一个地放置,那么我们只要知道第一个数据所在地址单元就可以了(看图2) 如果第一个数据在2H,那么第二、三个就在28H、29H了。所以利用堆栈这种方法来放数据可以简化操作 那么51中堆栈什么地方呢?单片机中能存放数据的区域有限,我们不能够专门分配一块地方做堆栈,所以就在 内存(RAM)中开辟一块地方,用于堆栈,但是用内存的哪一块呢?还是不好定,因为51是一种通用的单片机, 各人的实际需求各不相同,有人需要多一些堆栈,而有人则不需要那么多,所以怎么分配都不合适,怎样来解决 这个问题?分不好干脆就不分了,把分的权利给用户(编程者),根据自已的需要去定吧,所以51单片机中堆栈 的位置是可以变化的。而这种变化就体现在SP中值的变化,看图2,SP中的值等于27H不就相当于是一个指针 指向2ⅦH单元吗?当然在真正的51机中,开始指针所指的位置并非就是数据存放的位置,而是数据存放的前 个位置,比如一开始指针是指向27H单元的,那么第一个数据的位置是28H单元,而不是27H单元,为什么会 这样,我们在学堆栈命令时再说明 2CH 其它的SFR,我们在用到时再介绍。 单片机第八课(寻址方式与指令系统) 通过前面的学习,我们已经了解了单片机内部的结构,并且也已经知道,要控制单片机,让它为我们干学,要用 指令,我们已学了几条指令,但很零散,从现在开始,我们将要系统地学习8051的指令部份。 、概述 1、指令的格式 我们已知,要让计算机做事,就得给计算机以指令,并且我们已知,计算机很“笨”,只能懂得数字,如前面我们 进机器的75H,9OH,OO等等,所以指令的第一种格式就是机器码格式,也说是数字的形式。但这种形式实在 是为难我们人了,太难记了,于是有另一种格式,助记符格式,如MOVP1,#OFFH,这样就好记了。这两种格 式之间的关系呢,我们不难理解,本质上它们完全等价,只是形式不一样而已 2、汇编 我们写指令使用汇编格式,而计算机只懂机器码格式,所以要将我们写的汇编格式的指令转换为机器码格式,这
平凡的单片机教程 自学单片机第 12 页 共 60 页 12 为 0。 例:某运算结果是 78H(01111000),显然 1 的个数为偶数,所以 P=0。 4、DPTR(DPH、DPL):数据指针,可以用它来访问外部数据存储器中的任一单元,如果不用,也可以作为通 用寄存器来用,由我们自已决定如何使用。 5、P0、P1、P2、P3:这个我们已经知道,是四个并行输入/输出口的寄存器。它里面的内容对应着管脚的输出。 6、SP:堆栈指针。 堆栈介绍:日常生活中,我们都注意到过这样的现象,家里洗的碗,一只一只摞起来,最晚放上去的放在最上面, 而最早放上去的则放在最下面,在取的时候正好相反,先从最上面取,这种现象我们用一句话来概括:“先进后 出,后进先出”。请大家想想,还有什么地方有这种现象?其实比比皆是,建筑工地上堆放的砖头、材料,仓库 里放的货物,都是“先进后出,后进先出”,这实际是一种存取物品的规则,我们称之为“堆栈”。 在单片机中,我们也可以在 RAM 中构造这样一个区域,用来存放数据,这个区域存放数据的规则就是“先进后 出,后进先出”,我们称之为“堆栈”。为什么需要这样来存放数据呢?存储器本身不是可以按地址来存放数据吗? 对,知道了地址的确就可以知道里面的内容,但如果我们需要存放的是一批数据,每一个数据都需要知道地址那 不是麻烦吗?如果我们让数据一个接一个地放置,那么我们只要知道第一个数据所在地址单元就可以了(看图 2) 如果第一个数据在 27H,那么第二、三个就在 28H、29H 了。所以利用堆栈这种方法来放数据可以简化操作 那么 51 中堆栈什么地方呢?单片机中能存放数据的区域有限,我们不能够专门分配一块地方做堆栈,所以就在 内存(RAM)中开辟一块地方,用于堆栈,但是用内存的哪一块呢?还是不好定,因为 51 是一种通用的单片机, 各人的实际需求各不相同,有人需要多一些堆栈,而有人则不需要那么多,所以怎么分配都不合适,怎样来解决 这个问题?分不好干脆就不分了,把分的权利给用户(编程者),根据自已的需要去定吧,所以 51 单片机中堆栈 的位置是可以变化的。而这种变化就体现在 SP 中值的变化,看图 2,SP 中的值等于 27H 不就相当于是一个指针 指向 27H 单元吗?当然在真正的 51 机中,开始指针所指的位置并非就是数据存放的位置,而是数据存放的前一 个位置,比如一开始指针是指向 27H 单元的,那么第一个数据的位置是 28H 单元,而不是 27H 单元,为什么会 这样,我们在学堆栈命令时再说明。 其它的 SFR,我们在用到时再介绍。 单片机第八课(寻址方式与指令系统) 通过前面的学习,我们已经了解了单片机内部的结构,并且也已经知道,要控制单片机,让它为我们干学,要用 指令,我们已学了几条指令,但很零散,从现在开始,我们将要系统地学习 8051 的指令部份。 一、概述 1、指令的格式 我们已知,要让计算机做事,就得给计算机以指令,并且我们已知,计算机很“笨”,只能懂得数字,如前面我们 写进机器的 75H,90H,00H 等等,所以指令的第一种格式就是机器码格式,也说是数字的形式。但这种形式实在 是为难我们人了,太难记了,于是有另一种格式,助记符格式,如 MOV P1,#0FFH,这样就好记了。 这两种格 式之间的关系呢,我们不难理解,本质上它们完全等价,只是形式不一样而已。 2、汇编 我们写指令使用汇编格式,而计算机只懂机器码格式,所以要将我们写的汇编格式的指令转换为机器码格式,这
平凡的单片机教程 自学单片机第13页共60页 种转换有两种方法:手工汇编和机器汇编。手工汇编实际上就是査表,因为这两种格式纯粹是格式不同,所以是 对应的,查一张表格就行了。不过手工查表总是嫌麻烦,所以就有了计算机软件,用计算机软件来替代手工 查表,这就是机器汇编 寻址 让我们先来复习一下我们学过的一些指令:MOVP1,#0FFH,MOVR7,#OFFH这些指令都是将一些数据送到相应 的位置中去,为什么要送数据呢?第一个因为送入的数可以让灯全灭掉,第二个是为了要实现延时,从这里我们 可以看出来,在用单片机的编程语言编程时,经常要用到数据的传递,事实上数据传递是单片机编程时的一项重 要工作,一共有28条指令(单片机共111条指令)。下面我们就从数据传递类指令开始吧 分析一下MoVP1,#0FF这条指令,我们不难得出结论,第一个词MoN是命令动词,也就是决定做什么事情的, M0V是MVE少写了一个E,所以就是“传递”,这就是指令,规定做什么事情,后面还有一些参数,分析一下,数 据传递必须要有一个“源”也就是你要送什么数,必须要有一个“目的”,也就是你这个数要送到什么地方去,显然 在上面那条指令中,要送的数(源)就是OFFH,而要送达的地方(目的地)就是P1这个寄存器。在数据传递类 指令中,均将目的地写在指令的后面,而将源写在最后。 这条指令中,送给P1是这个数本身,换言之,做完这条指令后,我们可以明确地知道,P1中的值是OFFH,但是 并不是任何时候都可以直接给出数本身的。例如,在我们前面给出的延时程序例是这样写的 MAIN: SETB P1. 0 (1) LCALL DELAY:(2) CLR P1. 0 ;(3) LCALL DELAY:(4) AJMP MAIN (5) 以下子程序 DELAY: MOV R7, #250:(6) Dl:MOVR6,#250;(7) D2: DJNZ R6, D2 DJNZ R7, DI (9) RET END (11) 表1 MAIN: SETB Pl. 0 ;(1) MoV 30H, #255 LCALL DELAY CLR P1. 0 (3) MOV30H,#200 LCALL DELAY ;(4) AJMP MAIN (5) ;以下子程序 DELAY: MOV R7, 30H DI: MOV R6, #2 (7) DJNZ R7, DI (9) RET (10) END (11)
平凡的单片机教程 自学单片机第 13 页 共 60 页 13 种转换有两种方法:手工汇编和机器汇编。手工汇编实际上就是查表,因为这两种格式纯粹是格式不同,所以是 一一对应的,查一张表格就行了。不过手工查表总是嫌麻烦,所以就有了计算机软件,用计算机软件来替代手工 查表,这就是机器汇编。 二、寻址 让我们先来复习一下我们学过的一些指令: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)
平凡的单片机教程 自学单片机第14页共60页 这样一来,我每次调用延时程序延时的时间都是相同的(大致都是0.13S),如果我提出这样的要求:灯亮后 延时时间为0.13S灯灭,灯灭后延时0.1秒灯亮,如此循环,这样的程序还能满足要求吗?不能,怎么办?我们 可以把延时程序改成这样(见表2):调用则见表2中的主程,也就是先把一个数送入3OH,在子程序中R7中的值 并不固定,而是根据3OH单元中传过来的数确定。这样就可以满足要求 从这里我们可以得出结论,在数据传递中要找到被传递的数,很多时候,这个数并不能直接给出,需要变化,这 就引出了一个概念:如何寻找操作数,我们把寻找操作数所在单元的地址称之为寻址。在这里我们直接使用数所 在单元的地址找到了操作数,所以称这种方法为直接寻址。除了这种方法之外,还有一种,如果我们把数放在工 作寄存器中,从工作寄存器中寻找数据,则称之为寄存器寻址。例:MOVA,R0就是将RO工作寄存器中的数据 送到累加器A中去。提一个问题:我们知道,工作寄存器就是内存单元的一部份,如果我们选择工作寄存器组0, 则RO就是RAM的00H单元,那么这样一来,MOVA,0OH,和MVA,RO不就没什么区别了吗?为什么要加以区 分呢?的确,这两条指令执行的结果是完全相同的,都是将00H单元中的内容送到A中去,但是执行的过程不同 执行第一条指令需要2个周期,而第二条则只需要1个周期,第一条指令变成最终的目标码要两个字节(E5HO0H) 而第二条则只要一个字节(E8h)就可以了 这么斤斤计较!不就差了一个周期吗,如果是12M的晶振的话,也就1个微秒时间了,一个字节又能有多少? 不对,如果这条指令只执行一次,也许无所谓,但一条指令如果执行上1000次,就是1毫秒,如果要执行100000 万次,就是1S的误差,这就很可观了,单片机做的是实时控制的事,所以必须如此“斤斤计较”。字节数同样如 此。 再来提一个问题,现在我们已知,寻找操作数可以通过直接给的方式(立即寻址)和直接给出数所在单元地址的 方式(直接寻址),这就够了吗? 看这个问题,要求从30H单元开始,取20个数,分别送入A累加器 就我们目前掌握的办法而言,要从30H单元取数,就用MVA,3OH,那么下一个数呢?是31H单元的,怎么取 ?还是只能用MA,31H,那么20个数,不是得20条指令才能写完吗?这里只有20个数,如果要送200个 或2000个数,那岂不要写上200条或2000条命令?这未免太笨了吧。为什么会出现这样的状况?是因为我们只 会把地址写在指令中,所以就没办法了,如果我们不是把地址直接写在指令中,而是把地址放在另外一个寄存器 单元中,根据这个寄存器单元中的数值决定该到哪个单元中取数据,比如,当前这个寄存器中的值是3OH,那么 就到3OH单元中去取,如果是3ⅢH就到3ⅢH单元中去取,就可以解决这个问题了。怎么个解决法呢?既然是看的 寄存器中的值,那么我们就可以通过一定的方法让这里面的值发生变化,比如取完一个数后,将这个寄存器单元 中的值加1,还是执行同一条指令,可是取数的对象却不一样了,不是吗。通过例子来说明吧 MOV DV RO, #30H LOOP: MOVA, RO INC RO DJNZ R7, LOOP 这个例子中大部份指令我们是能看懂的,第一句,是将立即数20送到R7中,执行完后R7中的值应当是20。第 句是将立即数30H送入RO工作寄存器中,所以执行完后,RO单元中的值是30H,第三句,这是看一下R0单元 中是什么值,把这个值作为地址,取这个地址单元的内容送入A中,此时,执行这条指令的结果就相当于MOVA, 30H。第四句,没学过,就是把R0中的值加1,因此执行完后,RO中的值就是31H,第五句,学过,将R7中的 值减1,看是否等于0,不等于0,则转到标号LOOP处继续执行,因此,执行完这句后,将转去执行MOVA,@R0 这句话,此时相当于执行了MoVA,3IH(因为此时的R0中的值已是31H了),如此,直到R7中的值逐次相减 等于0,也就是循环20次为止,就实现了我们的要求:从3OH单元开始将20个数据送入A中 这也是一种寻找数据的方法,由于数据是间接地被找到的,所以就称之为间址寻址。注意,在间址寻址中,只能 用RO或R1存放等寻找的数据
平凡的单片机教程 自学单片机第 14 页 共 60 页 14 这样一来,我每次调用延时程序延时的时间都是相同的(大致都是 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 存放等寻找的数据
平凡的单片机教程 自学单片机第15页共60页 单片机教程第九课:数据传递指 数据传递类指令 1)以累加器为目的操作数的指令 mov A, Rn Mov A, direct mov A, Ri MOv A, #data 第一条指令中,Rn代表的是R0-R7。第二条指令中, direct就是指的直接地址,而第三条指令中,就是我们刚 才讲过的。第四条指令是将立即数data送到A中。 下面我们通过一些例子加以说明: MOVA,R1:将工作寄存器R1中的值送入A,R中的值保持不变 MOVA,3OH;将内存30H单元中的值送入A,3OH单元中的值保持不变 MOVA,eR1:先看R1中是什么值,把这个值作为地址,并将这个地址单元中的值送入A中。如执行命令前R1 中的值为20H,则是将20H单元中的值送入A中。 MOVA,#34H;将立即数34H送入A中,执行完本条指令后,A中的值是34H。 2)以寄存器Rn为目的操作的指令 Mov Rn. A Mov Rn. direct MOV Rn, #data 这组指令功能是把源地址单元中的内容送入工作寄存器,源操作数不变。 单片机指令(二) 数据传递类指令 3)以直接地址为目的操作数的指令 Mov direct,A例:MoV20H, AMoy direct,RnMV20H,R1 Mov directl. direct mov 20H 30H mov direct @Ri Mov 20H OR1 Mov direct, #data MOV 20H, #34H (4)以间接地址为目的操作数的指令 MOV Ri,A例: MOV OR0,AMOV@Ri, direct Mov oR1,20H MOV GRi, #data mov @Ro. #34H (5)十六位数的传递指令 MOV DPTR,#data168051是一种8位机,这是唯一的一条16位立即数传递指令,其功 能是将一个16位的立即数送入DPTR中去。其中高8位送入DPH,低8位送入DPL。例: MOV DPTR,#1234H,则 执行完了之后DPH中的值为12H,DPL中的值为34H。反之,如果我们分别向DPH,DAL送数,则结果也一样。如 有下面两条指令: MOV DPH,#35H, MOV DPL,#12H。则就相当于执行了 MOV DPTR,#3512H。综合练习: 给出每条指令执行后的结果 MOV 23H, #30HMOV 12H, #34H MOV RO. #23H MOV R7. #22H RI, 12H MOV A ERO MOV 34H, eRI (RO)=23H (R7)=22H (R1)=12H
平凡的单片机教程 自学单片机第 15 页 共 60 页 15 单片机教程第九课:数据传递指令 数据传递类指令 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 这组指令功能是把源地址单元中的内容送入工作寄存器,源操作数不变。 单片机指令(二) 数据传递类指令 (3)以直接地址为目的操作数的指令 MOV direct,A 例: MOV 20H,AMOV direct,Rn MOV 20H,R1 MOV direct1,direct2 MOV 20H,30H MOV direct,@Ri MOV 20H,@R1 MOV direct,#data MOV 20H,#34H (4)以间接地址为目的操作数的指令 MOV @Ri,A 例:MOV @R0,AMOV @Ri,direct MOV @R1,20H MOV @Ri,#data MOV @R0,#34H (5)十六位数的传递指令 MOV DPTR,#data168051 是一种 8 位机,这是唯一的一条 16 位立即数传递指令,其功 能是将一个 16 位的立即数送入 DPTR 中去。其中高 8 位送入 DPH,低 8 位送入 DPL。例:MOV DPTR,#1234H,则 执行完了之后 DPH 中的值为 12H,DPL 中的值为 34H。反之,如果我们分别向 DPH,DPL 送数,则结果也一样。如 有下面两条指令:MOV DPH,#35H,MOV DPL,#12H。则就相当于执行了 MOV DPTR,#3512H。综合练习: 给出每条指令执行后的结果 MOV 23H,#30HMOV 12H,#34H MOV R0,#23H MOV R7,#22H MOV R1,12H MOV A,@R0 MOV 34H,@R1 (23h)=30h (12h)=34h (R0)=23H (R7)=22H (R1)=12H