精品文档 你我共享
DEMODE: M0V P2,#00H ; MOVX A,@RO ;取数 MOV B,A ;暂存以备用 ANL A,#0F0H ;截取高4位
SWAP A ;高4位为0,低4位为60H单元中的低4位 MOVX @RO,A ;送结果1 ANL B,#0FH ;截取低4位
MOV A,B ;高4位为0,低4位为60H单元中的低4位 INC RO ;修改指针 MOVX @RO,A, ;送结果2 END ;结束
MOV RO,#60H ;设置地址指针RO初值
3.2.2分支程序设计
1、分支结构
计算机具有逻辑判断能力,它能根据条件进行判断并根据判断结果选择相应的程序入口。这种逻辑判断功能是计算机分支程序的基础。
在进行编程时常常会遇到:根据不同的条件,要求进行相应的处理,此时就应采用分支结构。通常用条件转移指令形成简单分支结构。指令JZ JNZ、JC ,JNC、JB、JNB、CJNE、DJNZ等都可以作为程序分支的依据。另外,在MCS-51指令系统中还有一类指令JMP @A+DPTR稍后再讲。
2、分支程序设计
例3.5 设a存放在累加器A中,b存放在寄存器B中,要求按下式计算y值并将结果y存入累加器A中。试编制相应的程序。
分析:
本题的关键是判断a是正数还是负数,这可以通过检测a的符号位(最高位)的状态来实现。若ACC.=7(a 为正数),则执行a-b运算;否则,执行a+b运算。
程序如下:
ORG 4000H
BRMPNA:JB ACC.7 ,PLUS ;a为负数?若是则转PLUS CLR C ;若为正数,则清C SUBB A,B ;执行a-b操作 SJMP BRDONE、
PLUS; ADD A,B ;若为负数,则执行a+b操作 BRDONE: SJMP BRDONE ;等待 END ;结束
例3.6 两个带符号数分别存在ONE和TWO两单元。试比较它们的大小,将较大者存入MAX单元中。 分析:
两个带符号数的大小比较,可将两个数相减后的正负数和溢出标志结合在一起判断,即: 当x-y>0为正时,若OV=0,则x>y;如果OV=1,则x
腹有诗书气自华
精品文档 你我共享
当x-y=0,则x=y. 程序如下:
ORG 4000H
COMP: CLR C :做减法,清Cy MOV A,ONE ;取x到A中 SUBB A,TWO ;x-y JZ XMAX ;x=y ?
JB ACC.7, NEG ;x-y<0,转NEG JB OV,YMAX ;x-y>0,OV=1,则y>x SJMP XMAX ;x-y>0,OV=0,则x>y NEG: JB OV, XMAX ;x-y<0,OV=0,则x
ONE DATA 30H ;数据地址 TWO DATA 31H MAX DATA 32H END
3-3 单片机汇编语言程序设计
【课 题】MCS-51汇编语言编程-循环结构与循环程序、子程序 【授课方法】在专业教室讲授,举例说明、分析程序 【目的要求】了解本课程汇编语言编程的基本方法和技巧;
理解MCS-51汇编语言编程方法,注总事项; 掌握常见的几种程序设计方法。
【重点难点】单片机汇编程序设计。单片机程序例题深入分析。 【教学内容】
练习四、循环结构与循环程序设计 4.1、循环结构程序
前面介绍了顺序程序和分支程序,对于前者每条指令只执行一次,后者则根据不同条件会跳过一些指令,执行另一些指令。这两种程序的特点是每条指令至多只执行一次。但是,在处理实际问题时,有时要求某些程序段多次重复执行,此时就应采用循环结构实现。这样不但可使程序简练而且可大大节省存储单元、典型循环程序包含四部分:初始化部分、循环处理部分、循环控制部分和循环结束部分。下面分别介绍这四个组成部分。
腹有诗书气自华
精品文档 你我共享
(1)初始化部分 (2)循环处理部分 (3)循环控制部分 (4)结束部分
*例3.9 设有一带符号的数组存放在8031单片机内部RAM以20H为首址的连续单元中,其长度为90,要求找出其中的最大值将其存放到内部RAM的1FH单元中,试编写相应的程序。 分析:
开始时将第一单元内容送A,接着从第二位起依次将其内容x与A比较,如x>A,那么将x送A;如果A≥x,那么A值不变,直到最后一个单元内容与A比较、操作完毕,则A中就是该数组中的最大数,这里需要解决如何判别两个带符号数A,x的大小。通常可以采用如下的方法:首先判断A,x是否是同号,若是同号,则进行A-X操作,如差>0,那么A>X;如果差<0,那么A ORG 1000H SCMPPMA:MOV RO,#20H ;置取数指针R0初值 MOV B,#59H ;置循环计数器B初值 MOV A,@RO ;第一个数送A SCLOOP: INC RO ;修改指针 MOV R1,A ;暂存 XRL A,@RO ;两数符号相同? JB ACC.7,RESLAT ;若相异,则转RESLAT MOV A,R1 ;若相同,则恢复A原来值 CLR C ;C清0 SUBB A,@R ;两数相减,以判两者的大小 JNB ACC. 7 SMEXT1;若A为大,则转SMEXT1 CXAHER:MOV A,@RO ;若A为小,则将大数送入A SJMP SMEXT2 RESLAT:XRL A,@RO ;恢复A原值 JNB ACC.7 SMEXT2 ;若A为正,侧转SMEXT2 SJMP CXAHER ;若A为负,则转XCAHER SMEXT1:ADD A,@RO ;恢复A原值 SMEXT2:DJNZ,B,SCLOOP ;所有的单元均比较过?未比较完,则继续进行 MOV 1FH,A ;最大者送1FH单元 END ②循环次数未知的循环程序 有些程序事先不知道循环计数器,这时需要根据判断循环条件的成立与否,或用建立标志的方法,控制循环程序的结束. (2)多重循环设计 前面例子都是单循环程序。在现实中往往还会遇到多重循环,一个循环程序的循环体中还包含一个或多个循环的结构,即双重循环或多重循环。 例3.10 设8031单片机使用12MHz 晶振(机器周期T为lμs),试设计延迟100ms的延 腹有诗书气自华 精品文档 你我共享 时程序。前面程序中已用过这样的程序,这里详细分析如下: 延时程序的功能相当于硬件定时器的功能。延时程序的延迟时间就是该程序的执行时间为512T(0FFH*2=512)。若取每条指令执行时间是T=1us (12MHZ),则最长的延时为512μs,故可采用双重循环程序实现延时100 ms。 程序如下: ORG 4000H 指令延时 DEYPRG:MOV R2,#COUNTS ;置外循环计数器R2初值为COUNTS,如#0FFH 1μs LOOPS:MOV B,#COUNTR ;置内循环计数器B初值为COUNTR COUNTS﹡2μs LOOPR:DJNZ B,LOOPR ;内循环计数并判内循环结束否? COUNTR* COUNTS﹡2μs DJNZ R2,LOOPS ;外循环计数并判外循环结束否? COUNTS﹡2μs END 下面计算COUNTR及COUNTS的值。设内循环程序的延时为500us,则COUNTR*2μs =500μs 于是可得COUNTR=250=0FAH, 外循环程序要求执行时间为100ms,则1μs +(500+2+2)μs *COUNTS=100 000μs 可得COUNTS=198.8取199=0C7H。此延迟程序的实际延迟时间为 [1+(502+2)*199]*1us=100.098ms 把每条指令执行次数乘指令周期即为总延时。 例3.11 设在单片机8031内部RAM的数据缓冲区存放一无符号数数组,其长度为100,起始地址为30H。要求将它们从大到小顺序排列,排序后存放在原数据缓冲区中,试编写相应的程序。 程序如下: ORG 4000H BUBBLE:MOV RO,#30H ;置地址指针RO初值 MOV R2,#100 ;置长度计数器R2初值#64H CLR 10H ;交换标志位(10H单元)清0 DEC R2 ;长度计数 BULOOP:MOV A,@RO ;取比较的第一个数 MOV 20H, A ;暂存 INC RO ;修改指针R0,以指向下一单元 MOV 21H,@RO ;取数比较的第二个数 CJNE A,21H,BUNEU ;两个比较,若(20H)-(21H),转BUNEU BUNEU: JNC BUNEXT ;若(20H)≥(21H),则转BUNEXT MOV A,@RO ;若(20H)<(21H),则两者交换 MOV @RO,20H ;(20H)的数小送高地址 DEC RO MOV @RO,A ; (21H)数大送低地址 INC RO ;恢复RO原值,准备下一次比较。 SETB 10H ;置交换标志位为1 BUNEXT:DJNZ R2, BULOOP ;长度计数器为0?若不为0,则继续比较 JB 10H,BUBBLE ;判交换标志。若为1,则继续循环 END ;为0则循环结束,完成排序 腹有诗书气自华 精品文档 你我共享 3.5.1、子程序结构 在程序设计的实践中,经常会遇到在不同的程序中或在同一程序不同的地方,要求实现某些相同的操作,如延时、代码转换、数制转换、检索与排序、函数计算以及对某些外设的实时控制等。 例3.15 十六进制数的ASCII码转换成相应的十六进制子程序SUBASH。 十六进制的ASCII码值不是连续的:0~9的ASCII码为30~39H此时只要将ASCII码值减去30H即可得到相应的十六进制数;而0AH~0FH的ASCII码为41H~46H,此时要将ASCII码值减去37H才是相应的十六进制数。由于本程序是子程序,所以(SP)及(SP)-1所指示的是返回地址,而(SP)-2所指示的才是欲转换的ASCII码,SUBASH子程序流程大家分析程序后自己画出。 ;子程序名称:SUBASH ;入口参数:被转换的十六进制数的ASCII码存放在(SP)-2所指示单元中 ;出口参数:转换后的十六进制数仍放在原单元中 ;所用寄存器:A,RO ;子程序清单: SUBASH:MOV RO,SP ;SP值不能改变,否则不能正确返回 DEC RO DEC RO XCH A,@RO ;从堆栈取出被转换的数送A CLR C SUBB A,#3AH ;为0~9的ASCII码否?小于3AH?, 共减30H JC ASCDTG ;若是小于,则转ASCDTG SUBB A,#07H ;若否,则再减去7,(A)-3A-7+0A=(A)-37 ASCDTG:ADD A,#0AH ;转换成十六进制数, XCH A,@RO ;转换后的十六进制数压入堆栈 RET 调用程序设计见下例。 例3.16 设有50个十六进制数的ASCII码存放在8031单片机内部RAM以30H为首址的连续单元中。要求将其转换成相应的十六进制数并存放到外部RAM以4100H为首址的25个连续单元中。根据上述要求,试编制SUBASH子程序的调用程序。 相应的程序如下: ORG 4000H MAIASH: MOV RO,#2FH ;置取数指针RO初值, 从30H开始 MOV DPTR ,#40FFH ;置数据指针DPTR,下一个地址是4100H MOV SP,#20H ;置堆栈SP初值 MOV R2,#19H ;置循环计数器R2初值25 NELOOP: INC RO :修改RO INC DPTR ;修改DPTR指下一个 MOV A,@RO ;取被转换时ASCII码并压入堆栈 PUSH ACC ACALL SUBASH ;调用SUBASH子程序(上一例) POP IFH ;相应的十六进制数送1FH单元 INC RO ;修改RO 腹有诗书气自华