单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,第,4,章,AT89S51,汇编语言程序设计,2,4.1.2,汇编语言语句和格式,两种基本语句:,指令语句,和,伪指令语句,。,(,1,)指令语句,汇编语言,四分段,格式,:,START,:,MOV A,,,#00H,;,0,A,MOV R1,,,#10,;,10,R1,MOV R2,,,#00000011B,;,03H,R2,LOOP,:,ADD A,,,R2,;,(A)+(R2),A,DJNZ R1,,,LOOP,;,R1,减,1,不为零,则跳,LOOP,处,NOP,HERE,:,SJMP HERE,标号字段,(LABLE),操作码字段,(OPCODE),操作数字段,(OPRAND),注释字段,(COMMENT),(,2,)伪指令语句,又,称为,汇编程序控制命令,。,没有相应的机器代码产生。,伪指令具有控制汇编程序的输入,/,输出、定义数据和符号、条件汇编、分配存储空间等功能。,1,ORG,(,ORiGin,)汇编起始地址命令,例如:,ORG2000H,START,:,MOVA,,,#00H,在一源程序中,可多次用,ORG,指令,规定不同程序段的起始地址,。,地址,必须由小到大排列,且不能交叉,、,重叠。,2.,END(END of Assembly),汇编终止命令,源程序,结束标志,,,终止源程序的汇编工作。,3,EQU,(,EQUate,)标号赋值命令,用于,给标号赋值,。赋值后,标号值在整个程序有效。,例如:,TEST,EQU 2000H,TEST=2000H,,汇编时,凡是遇到,TEST,时,均以,2000H,来代替。,4,DB,(,Define Byte,)定义数据字节命令,在程序存储器单元中定义字节数据。例如:,ORG2000H,DB30H,,,40H,,,24,,,C,,,B,汇编后,(2000H)=30H,(2001H)=40H,(2002H)=18H(,十进制数,24),(2003H)=43H(,字符“,C,”的,ASCII,码,),(2004H)=42H(,字符“,B,”的,ASCII,码,),十进制数,自然转换成十六进制数,字母按,ASCII,码存储。,6,5,DW,(,Define Word,)定义数据字命令,在程序存储器单元中定义,16,位的数据字。例如:,ORG2000H,DW1246H,,,7BH,,,10,汇编后,(2000H)=12H,;第,1,个字,(2001H)=46H,(2002H)=00H,;第,2,个字,(2003H)=7BH,(2004H)=00H,;第,3,个字,(2005H)=0AH,DB,、,DW,和,DS,命令,只能对程序存储器有效,,不能对数据存储器,使用。,6,DS,(,Define Storage,)定义存储区命令,NOP,从指定地址开始,保留指定数目的字节单元作为存储区。,例如:,TABEL,:,DS10,表示从,TABEL,代表的地址开始,保留,10,个连续的地址单元。,例如,:,ORG2000H,DS10 H,表示从,2000H,地址开始,保留,16,个连续地址单元。,7,BIT,位定义命令,用于给字符名称赋以位地址,位地址可以是绝对位地址,也可是符号地址。例如:,QABIT P1.6,功能是把,P1.6,的位地址赋给变量,QA,。,4.2,汇编语言源程序的汇编,汇编可分为,手工汇编,和,机器汇编,两类。,4.3 AT89S51,汇编语言程序设计举例,4.3.1,子程序设计,优点:,程序结构简单,缩短程序设计时间,减少存储空间。,1,子程序的设计原则和应注意的问题,(,1,)子程序入口地址,前必须有标号。,(,2,)主程序是通过调用指令来实现。有,两条子程序调用指令。,ACALL,addr11,。,addr11,指出了调用的目的地址,,PC,中,16,位地址中的高,5,位不变,即只能在同一个,2KB,区内。,LCALL addr16,长调用指令,。,(,3,)子程序结构中必须用到堆栈,用来进行断点和现场的保护。(,4,)子程序返回主程序时,最后一条指令必须是,RET,指令。,(,5,)子程序可以嵌套,即主程序可以调用子程序,子程序又可以调用另外的子程序。,2,子程序的基本结构,MAIN,:,;,MAIN,为主程序入口标号,LCALL SUB,;调用子程序,SUB,子程序,SUB,:,PUSH PSW,;现场保护,PUSH Acc,POP Acc,;现场恢复,注意要先进后出,POP PSW,RET,;最后一条指令必须为,RET,子程序处理程序段,子程序,4.3.2,查表程序设计,(,1,),MOVC A,,,A+DPTR,(,2,),MOVC A,,,A+PC,【,例,4-3】,设计一子程序,功能是根据累加器,A,中的数,x,(,0,9,之间)查,x,的平方表,y,,根据,x,的值查出相应的平方,y,。本例中的,x,和,y,均为单字节数。,地 址,子程序,Y3Y2Y1Y0,ADD A,,,#01H,Y3Y2Y1Y0+2,MOVC A,,,A+PC,Y3Y2Y1Y0+3,RET,Y3Y2Y1Y0+4,DB 00H,,,01H,,,04H,,,09H,,,10H DB 19H,,,24H,,,31H,,,40H,,,51H,;数,0,9,的平方表,如果,DPTR,已被使用,则在查表前必须保护,DPTR,,且结束后恢复,DPTR,,,例,4-3,可改成如下形式:,PUSH DPH,;保存,DPH,PUSH DPL,;保存,DPL,MOV DPTR,,,#TAB1,MOVC A,,,A+DPTR,POP DPL,;恢复,DPL,POP DPH,;恢复,DPH,RET,TAB1,:,DB 00H,,,01H,,,04H,,,09H,,,10H,;平方表,DB 19H,,,24H,,,31H,,,40H,,,51H,【,例,4-4】,有一巡回检测报警装置,需对,16,路(,x,),输入进行检测,每路有一个,最大允许值(,y,),,为,双字节数,。,需根据测量的路数(,x,),查表找出对应该路的最大允许值(,y,),,看输入值是否大于最大允许值,如果大于就报警。,取路数为,x,(,0,x,15,),,y,为最大允许值,放在表格中。设进入查表程序前,假设路数,x,已放于,R2,中,查表后该路的最大允许值,y,放于,R3R4,中。查表程序如下:,TB3,:,MOV A,,,R2,ADD A,,,R2,;,(R2)*2,(A),MOV R3,,,A,;保存指针,ADD A,,,#6,;加偏移量,MOVC A,,,A+PC,;查第一字节,XCH A,,,R3,ADD A,,,#3,MOVC A,,,A+PC,;查第二字节,MOVR4,,,A,RET,TAB3,:,DW 1520,,,3721,,,42645,,,7580,;最大值表,DW 3483,,,32657,,,883,,,9943,DW 10000,,,40511,,,6758,,,8931,DW 4468,,,5871,,,13284,,,27808,【,例,4-5】,以,AT89S51,为核心的温度控制器,温度传感器输出的电压与温度为非线性关系,传感器输出的电压已由,A/D,转换为,10,位二进制数。测得的不同温度下的电压值数据构成一个表,表中温度值为,y,(双字节无符号数),,x,(双字节无符号数)为电压值数据。设测得电压值,x,放入,R2R3,中,根据,电压值,x,,查找对应的,温度值,y,,仍放入,R2R3,中。程序如下:,LTB2,:,MOVDPTR,,,#TAB2,MOVA,,,R3,CLRC,RLCA,MOVR3,,,A,XCHA,,,R2,RLCA,XCHR2,,,A,MOV R3,,,A,ADDA,,,DPL,;,(R2R3)+(DPTR),(DPTR),MOVDPL,,,A,MOVA,,,DPH,ADDC A,,,R2,MOVDPH,,,A,CLRA,MOVC A,,,A+DPTR,;查第一字节,MOVR2,,,A,;第一字节存入,R2,中,CLRA,INCDPTR,MOVC A,,,A+DPTR,;查第二字节,MOVR3,,,A,;第二字节存入,R3,中,RET,TAB2,:,DW,,,,,;温度值表,4.3.3,关键字查找程序设计,数据检索,有两种方法,即,顺序检索,和,对分检索,。,1,顺序检索,要检索的表是,无序,的,检索时,只能从第,1,项开始逐项查找,,判断所取数据是否与关键字相等。,【,例,4-6】,从,50,个字节的无序表中查找一个关键字“,xxH,”。,ORG 1000H,MOV 30H,,,#xxH,;关键字,xxH,送,30H,单元,MOV R1,,,#50,;查找次数送,R1,MOV A,,,#14,;修正值送,A,MOV DPTR,,,#TAB4,;表首地址送,DPTR,LOOP,:,PUSH Acc,MOVC A,,, A+PC,;查表结果送,A,CJNE A,,,40H,,,LOOP1,;,(40H),不等于关键字则转,LOOP1,MOV R2,,,DPH,;查到关键字,把地址送,R2,,,R3,MOV R3,,,DPL,DONE,:,RET,LOOP1,:,POP Acc,;修正值弹出,INC A,;,A+1,A,INC DPTR,;修改数据指针,DPTR,DJNZ R1,,,LOOP,;,R1,0,,未查完,继续查找,MOVR2,,,#00H,;,R1=0,,,R2,和,R3,清,0,MOVR3,,,#00H,;表中,50,个数已查完,AJMPDONE,;从子程序返回,TAB4,:,DB ,,,,,;,50,个无序数据表,2,对分检索,对分检索的前提是检索的数据表,已经排好序,,以便于按照对分原则取数。,对分检索的方法,:,取数据表中间位置的数与关键字进行比较,如相等,则查找结束。,如果,取数大于关键字,,则下次对分检索的范围是从数据区起点到本次取数处。,如果,取数小于关键字,,则下次对分检索的范围是从本次取数数据区起点到数据区终点。依此类推,逐渐缩小检索范围,减少次数,大大提高查找速度。,21,4.3.4,数据极值查找程序设计,【,例,4-7】,片内,RAM,中存放一批数据,查找出最大值并存放于首地址中。设,R0,中存放首地址,,R2,中存放字节数。程序如下:,MOV R2,,,n,;,n,为要比较的数据字节数,MOV A,,,R0,;存首地址指针,MOV R1,,,A,DEC R2,MOV A,,,R1,LOOP,:,MOV R3,,,A,DEC R1,CLR C,SUBB A,,,R1,;两个数比较,JNC LOOP1,;,C=0,,,A,中数大,跳,LOOP1,MOV A,,,R1,;,C=1,,则大数送,A,SJMP LOOP2,LOOP1,:,MOV A,,,R3,LOOP2,:,DJNZ R2,,,LOOP,;是否比较结束?,MOV R0,,,A,;存最大数,RET,4.3.5,数据排序程序设计,第一次冒泡的过程是:,6,、,4,、,1,、,2,、,5,、,7,、,3,;原始数据的排列,4,、,6,、,1,、,2,、,5,、,7,、,3,;逆序,互换,4,、,1,、,6,、,2,、,5,、,7,、,3,;逆序,互换,4,、,1,、,2,、,6,、,5,、,7,、,3,;逆序,互换,4,、,1,、,2,、,5,、,6,、,7,、,3,;逆序,互换,4,、,1,、,2,、,5,、,6,、,7,、,3,;正序,不互换,4,、,1,、,2,、,5,、,6,、,3,、,7,;逆序,互换,第一次冒泡,结束,如此进行,各次冒泡的结果如下,:,第,1,次冒泡结果:,4,、,1,、,2,、,5,、,6,、,3,、,7,第,2,次冒泡结果:,1,、,2,、,4,、,5,、,3,、,6,、,7,第,3,次冒泡结果:,1,、,2,、,4,、,3,、,5,、,6,、,7,第,4,次冒泡结果:,1,、,2,、,3,、,4,、,5,、,6,、,7,;已完成排序,第,5,次冒泡结果:,1,、,2,、,3,、,4,、,5,、,6,、,7,第,6,次冒泡结果:,1,、,2,、,3,、,4,、,5,、,6,、,7,对于,n,个数,,,理论上应进行(,n,-1,)次冒泡,才能完成排序,实际上有时不到,(,n,-1,)次,就已完成排序。,例如,上面的,7,个数,,应进行,6,次,冒泡,,但,实际上,第,4,次,冒泡时就已经完成,排序。,如何判定排序是否已经完成,?就是看各次冒泡中,是否有,互换,发生,,如果有,则排序,还没完成,;否则就表示已经排好序。在程序设计中,常用,设置互换标志,的方法,用标志的状态表示是否有互换进行。,【,例,4-8】,一批单字节无符号数,以,R0,为首地址指针,,R2,中为字节数,将这批数进行升序排列。程序框图如,图,4-2,所示。,程序如下:,24,图,4-2,单字节无符号数排序程序,MAIN: MOV SP,#60H,MOV PSW,#00H,LP03,:,CLR F0,;互换标志位,F0,清,0,MOV R0,,,#30H,;数据首地址,R0,MOV R2,,,#0AH,;字节数送入,R2,DEC R2,LP02,:,MOV A,,,R0,MOV R3,,,A,INC R0,MOV A,,,R0,;比较大小,CLR C,SUBB A,,,R3,JNC LP01,MOV A,,,R3,;,XCH A,,,R0,;两个数互换,DEC R0,XCH A,,,R0,SETB F0,;互换标志位,F0,置,1,INC R0,LP01,:,DJNZ R2,,,LP02,JB F0,,,LP03,END,4.3.6,分支转移程序设计,分为无条件转移,和,有条件转移,。,无条件分支转移程序很简单,不讨论。有条件分支转移程序按结构类型来分,又分为,单分支,选择结构,和,多分支,选择结构,。,1,单分支选择结构,仅有,两个出口,,,两者选一,。一般根据运算结果的状态标志,用,条件判跳指令,来选择并转移。,【,例,4-9】,求单字节有符号数的二进制补码,正数补码,是其本身,,负数补码,是其,反码加,1,。应首先判被转换数的符号,负数进行转换,正数本身即为补码。,设二进制数放在,A,中,其补码放回到,A,中,参考程序如下:,CMPT,:,JNB Acc.7,,,RETURN,;,(A)0,,不需转换,MOV C,,,Acc.7,;符号位保存,CPL A,;,(A),求反,加,1,ADD A,,,#1,MOV Acc.7,,,C,;符号位存在,A,的最高位,RETURN,:,RET,图,4-3,求单字节有符号二进制数补码,此外,单分支选择结构还有,图,4-4,、,图,4-5,所示的几种形式。,图,4-4,单分支选择结构,2,图,4-5,单分支选择结构,3,2,多分支选择结构,当程序的判别部分有,两个以上,的,出口,时,为多分支选择结构。有两种形式,如,图,4-6,和,图,4-7,所示。,图,4-6,多分支选择结构,1,图,4-7,多分支选择结构,2,指令系统提供了非常有用的,两种多分支选择指令,:,间接转移指令,JMP A+DPTR,比较转移指令,CJNE A,,,direct,,,rel,CJNE A,,,#data,,,rel,CJNE R,n,,,#data,,,rel,CJNE R,i,,,#data,,,rel,间接转移指令“,JMP A+DPTR,”由数据指针,DPTR,决定多,分支转移,程序的,首地址,,由,A,的内容选择对应分支。,4,条,比较转移指令,CJNE,能对两个欲比较的单元内容进行比较,当,不相等,时,程序实现相对转移;若,两者相等,,则顺序往下执行。,简单的分支转移程序的设计,常采用,逐次比较法,。,缺点,是程序太长,有,n,种可能的情况,就需有,n,个判断和转移。,【,例,4-10】,求符号函数的值。符号函数定义如下:,X,存放在,40H,单元,,Y,存放在,41H,单元,如,图,4-6,所示。,SIGNFUC,:,MOV A,,,40H,CJNE A,,,#00H,,,NZEAR,AJMP NEGT,NZEAR,:,JB Acc.7,,,POSI,MOV A,,,#01H,AJMPNEGT,POSI,:,MOVA,,,#81H,NEGT,:,MOV41H,,,A,END,Y,=,1,X, 0,X, 0,X,= 0,0,-,1,实际中,经常遇到,图,4-7,的分支转移程序设计,,典型例子,就是当单片机系统中的,键盘按下,时,就会得到一个键值,根据,不同的键值,,,跳向不同的键处理程序入口,。此时,可,用直接转移指令(,LJMP,或,AJMP,指令)组成一个转移表,,然后把该单元的内容读入累加器,A,,转移表首地址放入,DPTR,中,再利用间接转移指令实现分支转移。,【,例,4-11】,根据寄存器,R2,的内容,转向各个处理程序,PRG,X,(,X,=0,n,)。,(R2)=0,,转,PRG0,(R2)=1,,转,PRG1,(R2)=,n,,转,PRG,n,程序如下:,JMP6,:,MOVDPTR,,,#TAB5,;转移表首地址送,DPTR,MOV A,,,R2,;分支转移参量送,A,MOV B,,,#03H,;乘数,3,送,B,MUL AB,;分支转移参量乘,3,MOV R6,,,A,;乘积的低,8,位暂存,R6,MOV A,,,B,;乘积的高,8,位送,A,ADD A,,,DPH,;乘积的高,8,位加到,DPH,中,MOV DPH,,,A,MOV A,,,R6,JMP A+DPTR,;多分支转移选择,TAB5,:,LJMP PRG0,;多分支转移表,LJMP PRG1,LJMP PRG,n,;,重点,R2,中的,分支转移参量乘,3,是由于长跳转指令,LJMP,要占,3,个单元。本例程序可位于,64KB,程序存储器空间的任何区域。,4.3.7,循环程序设计,1,循环程序的结构,(,1,)循环初始化,完成循环前的,准备工作,。循环控制计数初值设置、地址指针起始地址设置、为变量预置初值等。,(,2,)循环处理,完成实际的处理工作,反复循环执行部分,故又称循环体。,(,3,)循环控制,在重复执行循环体过程中,不断修改循环控制变量,直到符合结束条件,就结束循环程序执行。,循环结束控制方法分为,循环计数控制法,和,条件控制法,。,(,4,)循环结束,这部分是对循环程序执行的结果进行分析、处理和存放,。,2,循环结构的控制,分为,循环计数控制结构,和,条件控制结构,。,图,4-8,计数循环控制结构 图,4-9,条件控制结构,(,1,)计数循环控制结构,DJNZ R,n,,,rel,;以工作寄存器作控制计数器,DJNZ direct,,,rel,;以直接寻址单元作控制,计数器,例如,,计算,n,个数据的和,计算公式为 。,图,4-10,求数据和的程序框图,【,例,4-12】,求,n,个单字节无符号数,x,i,的和,,x,i,按,i,顺序存放在内,RAM,从,50H,开始单元中,,n,放在,R2,中,和(双字节)在,R3R4,中。程序如下:,ADD1,:,MOV R2,,,#n,;加法次数,n,送,R2,MOV R3,,,#0,;,R3,存放和的高,8,位,初始值为,0,MOV R4,,,#0,;,R4,存放和的低,8,位,初始值为,0,MOV R0,,,#50H,LOOP,:,MOV A,,,R4,ADD A,,,R0,MOV R4,,,A,INC R0,CLR A,ADDC,A,,,R3,MOV R3,,,A,DJNZ R2,,,LOOP,;判加法循环次数是否已到?,END,(,2,)条件控制结构,【,例,4-13】,一串字符,依次存放在内部,RAM,从,30H,单元开始的连续单元中,,字符串,以,0AH,为,结束标志,,测试,字符串长度,。,如果字符与“,0AH,”,不等,,则,长度计数器,和,字符串指针,都加,1,;如果比较,相等,,则表示该字符为“,0AH,”,,字符串结束,,计数器值就是字符串的长度。程序如下:,MOV,R4,,,#0FFH,;,长度计数器初值送,R4,MOV R1,,,#2FH,;字符串指针初值送,R1,NEXT,:,INC R4,INC R1,CJNE, R1,,,#0AH,,,NEXT,;,比较,不等则进行下一字符比较,END,【,例,4-14】,50ms,延时程序。,在使用,12MHz,晶振,时,一个机器周期为,1s,,执行一条,DJNZ,指令的时间为,2s,。,DEL,:,MOV R7,,,#200,;本指令执行时间,1s,DEL1,:,MOV R6,,,#125,;本指令执行时间,1s,DEL2,:,DJNZ R6,,,DEL2,;指令执行,1,次为,2s,,计,;,125,2 s=250s,DJNZ R7,,,DEL1,;指令执行时间,2s,,本循环体 ; 执行,125,次,RET,;指令执行时间,2s,以上延时程序,不是太精确,,如把所有指令的执行时间计算在内,它的延时时间为,1+,(,1+250+2,),200+2,s,=50.603ms,,如要求,比较精确的延时,,应对上述程序进行修改,才能达到较为精确的延时时间。但要注意,用软件实现延时程序,,不允许有中断,,否则将严重影响定时的准确性。,对于延时更长的时间,可采用多重的循环,如,1s,延时,可用三重循环。,ORG 0000H,MOV SP,#60H,MOV PSW,#00H,LP01:MOV 00H,#00H,MOV 08H,#00H,MOV 10H,#00H,MOV 18H,#00H,CLR A,LP10:CJNE A,#00H,LP03,SJMP LP10,LP03:MOV B,A,LP13:MOV A,R0,CJNE A,#00H,LP02,SJMP LP13,LP02:MOV PSW,#08H,SJMP LP06,LP06:MOV A,R0,CJNE A,#00H,LP05,LP05:MOV PSW,#10H,LP07:MOV A,R0,CJNE A,#00H,LP08,SJMP LP07,LP08:MOV PSW,#18H,LP09:MOV A,R0,CJNE A,#00H,LP11,SJMP LP09,LP11:CLR C,MOV A,B,ADD A,00H,MOV 00H,A,MOV A,B,ADD A,08H,MOV 08H,A,MOV A,B,ADD A,10H,MOV 10H,A,MOV A,B,ADD A,18H,MOV 18H,A,LP12:SJMP LP12,END,2,、用子程序求,1+2+100=?,,结果放在,ORG 0000H,R3R2,中。编写程序框图。,MOV SP,#60H,MOV PSW,#00H,LP01:MOV R2,#00H,MOV R3,#00H,MOV R0,#64H,MOV R1,#00H,INC R1,LP10:MOV A,R2,ADD A,R1,MOV R2,A,MOV A,R3,ADDC A,#00H,MOV R3,A,INC R1,DJNZ R0,LP10,LP13:SJMP LP13,END,1,、,A,中内容为,1-10,,分别用,PC,指针、,DPTR,指针求平方,结果存入,20H,单元。,TABLE,表放在程序存储器,030H,开始地址。,ORG 0000H,MOV DPTR,#TABLE,MOVC A,A+DPTR,LP01:SJMP LP01,ORG 0100H,TABLE:DB 00H, 01H,04H,09H,DB 10H,19H,24H,31H,DB 40H,51H,64H,ORG 0000H,LP01:MOV PSW,#00H ADD A,R0,MOV SP,#60H MOV R2,A,CLR C POP PSW,MOV A,R1 POP ACC,ADD A,R0 RET,LCALL LP10 END,LP02:SJMP LP02,ORG 100H,LP10:PUSH ACC,PUSH PSW,MOV PSW,#08H,CLR C,MOV A,R1,3,、将,30H-40H,单元内容从大到小排序,结果放回,30H-40H,。,4,、编写延时,1,秒子程序,用主程序调延时子程序,延时,10,秒。,