第四章80C51汇编语言程序设计主要内容:•顺序程序的设计•循环程序的结构与设计•子程序结构与设计教学目的通过本章学习,使学生:•了解汇编语言源程序的结构•掌握使用汇编语言进行程序设计4.1汇编语言程序设计的步骤与基本结构1.汇编语言程序设计的基本步骤使用程序设计语言编写程序的过程称为程序设计。在程序设计过程中,应在完成规定功能的前提下,使程序占用空间小,执行时间短。同时,在程序设计时要按照规定的步骤进行。程序设计步骤如下:(1)分析问题,确定算法和解题思路。(2)根据算法和解题思路画出程序流程图。(3)根据流程图编写程序。(4)程序调试,找出错误更正后再调试直至通过。(5)编写相关说明。2.程序的基本结构由于所处理的问题不同,不同程序的结构也就不尽相同。但是,结构化程序的基本结构只有三种:顺序结构、分支结构、循环结构。三种基本结构的流程图:(a)顺序结构(b)分支结构(c)循环结构图4.1程序的基本结构流程4.2汇编语言程序程序设计顺序结构的程序多用来处理比较简单的问题。特点是:程序中的语句由前向后顺序执行,最后一条指令执行完毕,整个程序也随之结束4.2.1顺序程序设计例4.1将20H中存放的压缩BCD数转换成二进制数存放在累加器A中。编程如下:ORG1000HSTART:MOVA,20H;取数,(A)←(20H)ANLA,#0F0H;屏蔽低4位SWAPA;高低4位互换MOVB,#0AH;(B)←10MULAB;BCD数的高4位乘以10MOVB,A;乘积暂存BMOVA,20H;取数ANLA,#0FH;屏蔽高4位ADDA,B;得到结果END例4.2设两个16位无符号数,分别存放在30H、31H单元和32H、33H单元,求它们的和,结果保存在34H和35H单元中。默认为(低字节和高字节)编程如下:MOVA,30HADDA,32HMOV34H,AMOVA,31HADDCA,33HMOV35H,A例4.3将内部RAM30H单元的高4位和31H单元的低4位拼成一个数,存入32H单元。编程如下:MOVA,30HANLA,#0F0HMOV32H,AMOVA,31HANLA,#0FHORLA,32HMOV32H,A例4.4计算Y=X1+X2-X3X1=38H,X2=2AH,X3=19H,Y=BUF编程如下:START:MOVA,#38HADDA,#2AHCLRCSUBBA,#19HMOVBUF,A4.2.2分支程序设计分支程序就是条件分支程序,即根据不同的条件,执行不同的程序段。例4.5设变量X存放于VAR单元,函数值Y存放在FUNC单元。试按照下式的要求给Y赋值。编程如下:VAREQU30HFUNCEQU31HMOVA,VAR;取出XJZCOMP;X=0则转移到COMPJNBACC.7,POSI;X0则转移到POSIMOVA,#0FFH;X0则转移到Y=-1SJMPCOMPPOSI:MOVA,#1;X0则Y=1COMP:MOVFUNC,A;存函数值100010xyxxORG8000HCLRCMOVA,40HCJNEA,41H,COMPSJMPDONECOMP:JNCDONEMOVA,41HDONE:MOV42H,ASJMP$ENDORG8000HCLRCMOVA,40HSUBBA,41HJNCLOOPMOV42H,41HRETLOOP:MOV42H,40HRET例4.6将存储单元40H和41H中较大的一个数存入42H单元中例4.7从内部RAM22h单元开始存有一个无符号数数据块,长度n存于21h中。求出数据块中的最小数,存于20h中。初始化yxy→x取新数yN-1=0?yyNNEND编程如下:ORG0030HMOVR0,#22H;数据块起始地址MOVR1,21H;数据个数nMOV20H,#0FFH;最大数LOOP:MOVA,@R0;取新数INCR0;为取下一个新数作准备CJNEA,20H,LOOP1;与原最大数比较LOOP1:JNCNEXT;大,原最小数保留MOV20H,A;小,改变最小数NEXT:DJNZR1,LOOP;循环ENDORG4000HSTART:MOVA,30HJZLP2JBACC.7,LP1MOV31H,#01HRETLP1:MOV31H,#0FFHRETLP2:MOV31H,#00HRET100010xyxx例4.8设变量X放在30H单元中结果放在31H单元中散转程序设计例4.9根据R7中的内容,转向各个子程序。R7=0,转入Prog0R7=1,转入Prog1R7=2,转入Prog2……R7=n,转入Progn处理0处理1处理nR7=?01nORG0030HJUMP1:MOVDPTR,#TABCLRAMOVA,R7ADDA,R7AJMP@A+DPTRORG0100HTAB:AJMPProg0AJMPProg1AJMPProg2……*AJMP…即把PC指向子程序的起始地址;*R7x2是AJMP@A+DPTR的机器码匹配;此处n127;*如用LJMP@A+DPTR,则R7x3,程序还要作相应修改。MOVDPTR,#KEYMOVA,50HRLAADDA,50HJMP@A+DPTRKEY:LJMPKEY0LJMPKEY1......LJMPKEYn例4.10根据50H单元内容转向各处理程序,处理程序的入口地址分别是KEY0、KEY1、KEY2、......KEYn。(散转指令)FRT:MOVA,40H;取行李重量G放在40HMOVR3,AMOVB,#03H;M=G×3MULABMOVR2,A;暂存3×G在R2MOVA,R3;取回GCJNEA,#06H,L1;G≤5?L1:JCWETC;是,转至WETCSUBBA,#05H;否则M=3G+2(G-5)RLCAADDA,R2MOVR2,AWETC:MOV41H,A;最后结果M存41HEND例11:行李计价:当G≤5,M=G×3;当G>5,M=G×3+(G-5)×(5-3)指出本程序的条件限制4.2.3循环程序设计循环程序一般由4部分组成:(1)置循环初值(2)循环体(3)循环修改(4)循环控制图4.2循环程序结构流程图开始循环结束?置循环初值循环处理循环修改结束处理结束开始置循环初值循环结束?循环处理循环修改结束处理结束YNYN(a)先执行后判断(b)先判断后执行例4.12在外部RAM2000H单元开始存放有20个无符号数,找出其最大值,把它放在内部RAM30H单元中。解:ORG1000HMAIN:MOVDPTR,#2000HMOVR7,#20MOVR5,#00HLOOP:MOVXA,@DPTRCLRCSUBBA,R5JCNEXTMOVXA,@OPTRMOVR5,AINCDPTRNEXT:DJNZR7,LOOPMOV30H,R5END例4.13编写无符号数排序程序。假设在片内RAM中,起始地址为40H的10个单元中存放有10个无符号数。试进行升序排序。解:数据排序采用冒泡排序法。执行时从前向后进行相邻数的比较,如数据的大小次序与要求的顺序不符就将这两个数互换,否则不互换。对于升序排序,通过这种相邻数的互换,使小数向前移动,大数向后移动;从前向后进行一次冒泡(相邻数的互换),就会把最大的数换到最后;再进行一次冒泡,就会把次大的数排在倒数第二的位置。依此类推,完成由小到大的排序。程序中:•R7做比较次数计数器,初始值为09H,•位地址00H作为冒泡过程中是否有数据互换的标志位若(00H)=0,表明无互换发生,已排序完毕若(00H)=1,表明有互换发生。图4.3冒泡法排序程序流程图开始数据区首址→R0置交换标志前数与后数交换取后一个操作数取前一个操作数置交换标志比较次数→R7前数后数本地比较完毕?本轮有交换结束YNY程序如下:ORG4000HSTART:MOVR0,#40H;数据区首址送R0MOVR7,#09H;各次冒泡比较次数送R7CLR00H;互换标志位清零LOOP:MOVA,@R0;取前数送A中MOV2BH,A;暂存到2BH单元中INCR0;修改地址指针MOV2AH,@R0;取后数暂存到2AH单元中CLRC;清CYSUBSA,@R0;前数减后数JCNEXT;前数小于后数,则转(不互换)MOV@R0,2BH;前数大于后数,两数交换;续前DECR0MOV@R0,2AHINCR0;地址加1,准备下一次比较SETB00H;置互换标志NEXT:DJNZR7,LOOP;未比较完,进行下一次比较JB00H,START;有交换,表示未排完序,进行下一;轮冒泡END例4.8编写50ms软件延时程序。解:软件延时程序一般都是由DJNZRn,rel指令构成。执行一条DJNZ指令需要两个机器周期。在使用12MHz晶振时,一个机器周期为1μs,执行一条DJNZ指令需要两个机器周期,即2μs。延时50ms需用双重循环,源程序如下:DEL:MOVR7,#125;执行时需1个机器周期DELI:MOVR6,#200DEL2:DJNZR6,DEL2;200×2=400μs;(内循环时间)DJNZR7,DEL1;0.4ms×125=50ms;(外循环时间)RET1niiyx例4.14一组10个数存放在片内RAM50H开始的连续单元,求和,高字节放R3,低字节放R4中。源程序:ADD1:MOVR7,#10;循环次数n=10MOVR3,#0;存放结果的高8位MOVR4,#0;存放结果的低8位MOVR0,#50H;求和的数据存放在从内部RAM50H;开始的单元中;注意(50H)=?不知道LOOP:MOVA,R4;ADDA,@R0;(R4)+(50H)→AMOVR4,A;结果送回R4CLRAADDCA,R3;把进位位C加到高8位去MOVR3,AINCR0;为下一轮循环作准备DJNZR7,LOOPEND解释:高8位低8位(R3)(R4)+(50H)C(A)MOVA,R4ADDA,@R0MOVR4,ACLRAADDCA,R3MOVR3,A(50H)中是什么,不知道,不能用ADDA,#50H4.2.4查表程序程序设计中,有时会遇到比较复杂的运算或转换过程,直接编程的困难较大,采用查表的方法使解决这种问题的有效涂径。在编程时可以很方便地通过DB伪指令把表格的内容存入ROM。用于查表的指令有两条:•MOVCA,@A+DPTR•MOVCA,@A+PC使用DPTR作为基地址查表,可通过三步操作来完成:①将所查表格的首地址存入DPTR数据指针寄存器;②将所查表的项数(即在表中的位置是第几项)送到累加器;③执行查表指令MOVCA,@A+DPTR,进行读数,查表的结果送回累加器A。例4.15计算X2,设X为小于10的非负整数,存放在内部RAM20H单元中,结果保存在内部RAM21H单元中。解:计算平方运算,可采用乘法实现,也可采用查表的方法实现,本例采用查表程序设计。源程序如下:SQR:MOVDPTR,#TABMOVA,20HMOVCA,@A+DPTRMOV21H,ARETTAB:DB0,1,4,9,16DB25,36,49,64,81例4.16利用查表法求函数值Y=3X2,X=0~9。设X存放在30H单元中,Y存放在31H单元中。编程如下:START:MOVDPTR,#TABMOVA,30HMOVCA,@A+DPTRMOV31H,ATAB:DB0,3,12,27,48,75DB108,147,192,243END4.9.6子程序为能完成某种功能单独编成一个独立的可以被反复使用的程序段,,过个独立的程序段称为子程序。子程序放在程序存储器的特定区域,执行时由主程序来调用它。子程序调用,就是暂时中断主程序的执行,而转到子程序的入口地址去执行子程序,执行完毕后,自动返回主程序,主程序再继续向下执行。…CALLS…CALLS主程序…………子程序SRET80C51单片机指令系统提供了两条子程序调用指令:ACALLaddr11和LCALLaddr16指令中的地址为子程序的入口地址,在实际的程序中通常用标号来代表。在主程序调用子程序时,只需执行调用指令,单片机即