第7课51单片机汇编程序设计汇编程序设计流程顺序程序设计条件分支程序循环程序模块汇编程序设计流程•掌握基础的汇编语言编程,是理解微型计算机(单片机)的有效途径,不应认为有了C语言就完全可以不学汇编语言了。•本章汇编语言侧重于理解程序指令流程,编程思想。•汇编程序设计是把计算机执行任务的每一步细节都设计详细,然后转换为计算机可执行指令的过程。因此汇编程序一般都较长,较繁琐。但是执行效率却是最高的。因为用任何其他高级语言编写的程序,也都需要经过编译器自动编译成对应的汇编程序。3-2.2顺序程序设计•故名思议:将程序语句一条一条按顺序执行下来,即完成整个任务的程序设计方式。•例1:编程将外部数据存储器的1000H和1020H单元的内容相交换。•*首先需要想一想怎样验证程序执行的正确性*一、顺序程序设计•为了验证程序:可以先向两个对应单元存储两个常数43H和78H。•读写片外XRAM单元必须使用MOVX指令•交换两个单元,则需要一个中间存储单元ORG0000HMAIN:MOVDPTR,#1000HMOVA,#43HMOVX@DPTR,AMOVDPTR,#1020HMOVA,#78HMOVX@DPTR,AEXCH:MOVDPTR,#1000HMOVXA,@DPTRMOVR1,AMOVDPTR,#1020HMOVXA,@DPTRMOVDPTR,#1000HMOVX@DPTR,AMOVDPTR,#1020HMOVA,R1MOVX@DPTR,AEND•例2:查表程序。设变量放在片内RAM的20H单元,取值范围0~9,要求编写查表程序,查出变量的平方值,并放入片内RAM21H单元.(注:所查表格为0~9的平方值的BCD码)程序思路:被查变量预先存储于20H单元,肯定是用MOV指令使用查表指令查表需要用DB伪指令定义BCD码的常数表格表格内容需要时0~9的平方值DPTR用于指向表格首地址•ORG0000H;起始地址•MOV20H,#9;预先存一个数•MOVDPTR,#BCDTAB;给DPTR赋表格首地址•MOVA,20H;读取被查数•MOVCA,@A+DPTR;查表BCD送入A•MOV21H,A;转存21H单元•SJMP$;本地挂起•BCDTAB:DB00H,01H,04H,09H,16H,25H,36H,•DB49H,64H,81H例:一个十六进制数放在HEX单元的低四位,将其转换成ASCII码查表程序:解:十六进制0~9的ASCII码为30H~39H,A~F的ASCII码为41H~46H,利用查表指令MOVCA,@A+DPTR先用伪指令DB或DW把表格的数据存入ROM来获得数据ASCII码表格的首址为ASCIITABASCTAB:DB30H,31H,32H,33HDB34H,35H,36H,37HDB38H,39H,41H,42HDB43H,44H,45H,46HEND编程1:0123456789ABCDEFORG0200HHEXEQU30HHEXASC:MOVA,HEXMOVDPTR,#ASCTABMOVCA,@A+DPTRMOVHEX,ARETANLA,#0FHDPTR(A)=333H(A)=1546H将内部RAM的20H单元中的8位无符号二进制数,转换为3位BCD码,并将结果存放在FIRST(百位)和SECOND(十位、个位)两个单元中。例3解:可将被转换数除以100,得百位数;余数除以10得十位数;最后余数即为个位数。例如:255(十进制)除以100,得2(百位数)余数除以10,得5(十位数)最后余数5即为个位数55H程序(设(20H)=0FFH):;取数;除数B;除100;百位BCD;除以10,十位在A,个位在B;除数10→B;十位数送高位;A为十位、个位BCDORG0000HFIRSTDATA21HSECONDDATA22H;存十位、个位数A0FFHB64H02H37H0AH37H05H05H50H55H0FFHRAM21H22H20H02HFIRSTSECONDMOVA,20HMOVB,#64HDIVABMOVFIRST,AMOVB,#0AHDIVABSWAPAORLA,BMOVSECOND,ASJMP$MOVA,B;余数A•例4:将片内20H单元的一个压缩BCD数(例如36H)转换成2字节的ASCII码,分别存入40H,41H单元。•思路:取出20H单元数据,高低4位拆分开,分别加上(位或)30H,则转换成ASCII码,再存储于40H,41H单元。•参考编程:•ORG0000H•MOV20H,#36H•MOVA,20H•ANLA,#0FH•ORLA,#30H•MOV41H,A•MOVA,20H•ANLA,#0F0H•SWAPA•ORLA,#30H•MOV40H,A换一个方法:ORG0000HMOV20H,#36HMOV40H,20HMOV41H,20HANL40H,#0FHORL40H,#30HMOVA,41HSWAPAORLA,#30HMOV41H,A二、分支条件程序•先回顾下C语言中分支条件语句有哪些?如何执行?•(1)if(条件){执行…}•(2)if(条件){执行1…}else{执行2…}•(3)if(条件1){执行1…}•elseif(条件2){执行2…}•…•(4)switch(表达式)case:break;…•voidmain()•{chara,b,z;•a=100;b=57;•if(ab){z=a;}•if(ab){z=b;}•if(a==b){z=a+b;}•printf(“Outz=%d\n”,z);•}voidmain(){chara,b,z;a=100;b=57;if(ab){z=a;}elseif(ab){z=b;}else{z=a+b;}printf(“Outz=%d\n”,z);}思考:上述两个例子程序在执行流程和执行结果上有个区别?一个C程序样例对比•条件分支的几种基本类型程序段A条件成立?下条指令YN单分支条件=if…程序段A条件成立?下条指令Y程序段BN单分支条件=if…else…条件1成立?程序段1Y条件2成立?程序段2YN条件3成立?程序段3YN判断模块出口多分支条件判断if…elseif….elseif…else例1:在片内RAM中40H和41H单元有2个无符号数,编程比较这两个数的大小,并将大数存于内部RAM的GR单元,小数存于LE单元,如果两数相等,则分别送入GR和LE地址单元。验证:40H可先存入35H,41H先存入48H,GR和LE单元地址可分配为GR=30H,LE=31H算法分析:可采用CJNE指令,除相等比较外还可以通过CY标志位判断2个数的大小。条件判断程序样例•GREQU30H•LEEQU31H•ORG0000H•MOV40H,#35H•MOV41H,#48H•CMP:CLRC;清零CY•MOVA,40H•CJNEA,41H,NEQ;比较•MOVGR,A•MOVLE,A•SJMP$NEQ:JCLESSMOVGR,AMOVLE,41HSJMP$LESS:MOVLE,AMOVGR,41HSJMP$例2:设30H单元存放的是一元二次方程ax2+bx+c=0根的判别式△=b2–4ac的值。试根据30H单元的值,编写程序,判断方程根的三种情况。在31H中存放“0”代表无实根,存放“1”代表有相同的实根,存放“2”代表两个不同的实根。解:△为有符号数,有三种情况,这是一多重分支程序即小于零,等于零、大于零。可以用两个条件转移指令来判断,首先判断符号位,用指令JNBACC.7,rel判断,若ACC.7=1,则一定为负数;此时0若ACC.7=0,则△≥0。此时再用指令JNZrel判断若△≠0,则△0,否则△=0流程图:A←△Acc.7=0?ENDSTARTNY(A)=0?31H←031H←2YN31H←1△0△=0△0程序:ORG1000HSTART:MOVA,30HJNBACC.7,YESMOV31H,#0SJMPFILISHYES:JNZTOWMOV31H,#1SJMPFILISHTOW:MOV31H,#2FILISH:SJMP$END;△值送A;△≥0转YES;△0无实根;△=0有相同实根;△0转TOW;有两个不同实根模块类型3:循环程序模块循环程序:类比while(){}、do{}while()和for(;;)利用比较转移指令CJNE、减1不为“0”转移指令DJNZ等实现例1:在内部RAM30H~4FH连续32个单元中存放了单字节无符号数,求32个无符号数之和,并存入内部RAM51H,50H中。解:这是重复相加问题,要设置一些工作单元设:R0做加数地址指针,R7做循环次数计数器,R3做和数的高字节寄存器。程序的流程图如下:流程图:31→R7#0→R3(30H)→A#31H→R0CY=0?ENDSTART(R7)-1=0?51H←(R3)50H←(A)YN(A)+((R0))→A(R0+1)→R0(R3)+1→R3NYNY(A)+((R0))→A(R3)+1→R3程序:;R7作循环次数计数器;R3作和数高字节寄存器;取被加数;R0作加数地址指针;CY=0,和256,则转;作加法;CY=1,加到高字节;修改R0指针;未完,重复加;存和数初始化部分循环体部分结束部分ORG0000HSTART:MOVR7,#31MOVR3,#0MOVA,30HMOVR0,#31HLOOP:ADDA,@R0JNCNEXTINCR3NEXT:INCR0DJNZR7,LOOPMOV51H,R3MOV50H,ASJMP$END循环执行直到R7=0程序:实际延时:例2:延时20ms子程序DELYDELY:MOVR7,#100DLY0:MOVR6,#98NOPDLY1:DJNZR6,DLY1DJNZR7,DLY0RET98×2=196µs1µs1µs设:主频为12MHZ,标准80512µs(196+2+2)×100+3=20003µs=20.003ms2µs1µs+3采用STC15W4K单片机,软件延时子程序可以用STC-ISP软件生成延时代码子程序的调用和返回•汇编子程序同C语言中的用户子函数是类似的。把某些特定功能的程序段用子程序方式保存起来,以供随时调用。C语言用户子函数的调用和返回的过程对用户是不可见的,而单片机汇编程序的子程序调用和返回过程则是有明确的进口和出口的,逻辑非常清楚。•通过例题理解子程序的调用和返回过程子程序的调用和返回样例ORG0000HMOVR0,#20HMOVA,#00HMOVR1,#10CPY:MOV@R0,AINCR0INCADJNZR1,CPYMOVR0,#20HMOVR2,#10MOVR1,#30H***ORG0050HTRANS:MOVA,@R0LCALLLUKTBLMOV@R1,AINCR0INCR1DJNZR2,TRANSSJMP$ORG0100HLUKTBL:MOVDPTR,#TBLMOVCA,@A+DPTRRETORG0200HDB0,1,4,9,16,25,36,49,64,81STC51开发板可选实物练习题1.编程实现P2.0口的LED灯闪烁,闪烁间隔可变,用软件延时实现。2.编程使数码管的最低位静态的显示一个数字‘5’,可以采用查表方式实现。3.加入软件延时循环,让最低位依次从0显示到9,再回到0,重复循环4.循环读取按键KY1,KY2,当KY1按下时让LED1闪烁,KY2按下时让KY2闪烁。忠告:要静下心来思考逻辑,一句一句的编写调试,忌浮躁,忌抄袭拷贝。