您的位置: 网站首页 > 电子与嵌入式 > 单片机原理与应用 > 第4章 汇编语言程序设计 > 【4.3 循环程序设计】

4.3 循环程序设计

 

所谓循环是指计算机反复执行某一段程序,这个程序段通常称为循环体。循环是在一定条件控制下进行的,这些条件决定是继续执行循环或是结束循环。程序循环是通过条件转移指令进行控制的。

1.循环程序的结构

循环程序的结构一般包括下面几个部分。

1)置循环的初值。

用于循环过程的工作单元,在循环开始时应置初值。例如,工作寄存器设置计数初值、累加器A清零,以及设置地址指针、长度等。置初值是循环程序中的一个重要部分。

2)循环体循环工作部分)。

重复执行的程序段可分为循环工作部分和循环控制部分。循环控制部分每循环一次检查一次结束条件,当满足条件时,就停止循环向下继续执行其他程序。

3)修改控制变量。

在循环程序中,必须给出循环结束条件。常见的是计数循环,当循环了一定的次数后就停止循环。在单片机中,一般用一个工作寄存器或内部RAM单元作为计数器,给这个计数器赋初值作为循环次数,每循环一次令其减“1”,即修改循环控制变量,当计数器减为零时,就停止循环。

4)循环控制部分。

根据循环结束条件,判断是否结束循环。MCS-51可采用“DJNZ”指令来自动修改控制变量并能结束循环。

上述4个部分有两种组织方式,如图4-7所示。

a)先循环后判断                 b)先判断后循环

4-7  循环组织方式流程图

【例4-9 将内部数据RAM20H3FH单元的内容传送到外部数据存储器以2000H开始的连续单元中去。

解:20H3FH共计32个单元,需传送32次数据。将Rl作为循环计数器,程序流程图如图4-7所示。具体程序如下。

START:  MOV R0,#20H          ;设置R0为内部RAM首地址

         MOV DPTR,#2000H     ;设置外部RAM首地址

         MOV R1,#32           ;Rl为计数器

LOOP:   MOV A,@R0            ;取内部RAM

         MOVX @DPTR,A        ;送外部RAM

         INC R0               ;调整内部RAM指针,指向下一个数据

         INC DPTR             ;调整外部RAM指针

         DJNZ R1,LOOP         ;未完继续

         SJMP $               ;暂停

2.多重循环程序

如果一个循环中包含了其他的循环程序,则称该循环程序为多重循环程序。

【例4-10 设计20 ms延时程序。

解:延时程序与MCS-51指令执行时间有很大的关系。在使用12MHz晶振时,一个机器周期为lms,执行一条DJNZ指令的时间为2ms20ms=2ms×10 000,由于8位的计数值最大为256,这时可用双重循环方法20ms=2ms×100×100。延时20ms的程序如下。

DL20MS:MOV R4,#100          ;20 ms=2μs×100×100,外循环初值=100

DELAY1:MOV R3,#100         ;内循环初值=100

DELAY2:DJNZ R3,DELAY2      ;100×2=200=0.2ms

         DJNZ R4,DELAY1      ;0.2×100=20ms

            RET

上述程序中,第24句要运行100次,100×1+2=300=0.3 ms,该段程序的延时时间约20.3 ms。若需要延时更长时间,可采用多重循环,如1秒延时可用3重循环,而用7重循环可延时几年!

【例4-11 排序。把片内RAM 40H49H单元中的10个无符号数逐一比较,并按从小到大的顺序依次排列在这片单元中。

解:为了把10个单元中的数按从小到大的顺序排列,可从40H单元开始,取前数与后数比较,如果前数小于后数,则顺序继续比较下去;如果前数大于后数则前数和后数交换后再继续比较下去。第一次循环将在最后单元中得到最大的数,要得到所有数据从小到大的升序排列(冒泡法)需要经过多重循环。程序流程图如图4-9所示。具体程序如下。

         

4-8  程序流程图                   4-9  数据排序程序流程图

START:  CLR F0          ;清除交换标志位F0

         MOV R3,#9       ;10个数据循环次数

         MOV R0,#40H     ;数据存放区首址

         MOV A,@R0       ;取前数

L2:         INC R0         

         MOV R2A       ;保存前数

         SUBB A@R0     ;前数减后数

         MOV A,R2        ;恢复前数

         JC L1           ;顺序则继续比较

         SETB F0         ;逆序则建立标志位

         XCH A,@R0       ;前数与后数交换

         DEC R0          ;指向前数单元

         XCH A,@R0      

         INC R0          ;仍指向后数单元

L1:         MOV A,@R0       ;取下一个数

         DJNZ R3,L2      ;依次重复比较

         JB F0,START     ;交换后重新比较

         RET

3.编写循环程序时应注意的问题

从上面几个例子不难看出,循环程序的结构大体上是相同的,在编写这类程序时有以下几个问题要注意。

1)在进入循环之前,应合理设置循环初始变量。

2)循环体只能执行有限次,如果无限执行的话,称为“死循环”,应尽量避免。

3)不能破坏或修改循环体,尤其应避免从循环体外直接跳转到循环体内。

4)多重循环的嵌套,应当是图4-10a)、b)所示的两种形式,应避免图4-10c)的情况。由此可见,多重循环是从外层向内层一层层进入,从内层向外层一层层退出。

a              b                 c

4-10  多重循环嵌套的形式

5)循环体内可以直接转移到循环体外或外层循环中,实现一个由多个条件控制结束的循环结构。

6)循环体的编程要仔细推敲、合理安排。对其进行优化时,应主要放在缩短执行时间上,其次是程序的长度。

【例4-12 在片内RAM30H3FH连续16个单元中存放单字节无符号数。求16个无符号数之和(假定和0FFFFH),并存入片内RAM 41H40 H单元中。

分析:这是重复相加问题。设R0作加数地址指针,R7作循环次数计数器,R2作和的高字节寄存器,则程序流程图如图4-11所示。编程如下。

解:

MAIN:   MOV     R7,#15          ;R7作循环次数计数器

         MOV     R2,#0           ;R2作和高字节寄存器

         MOV     A,30H           ;取被加数

         MOV         R0#31H        ;R0作加数地址指针

LOOP:   ADD     A,@R0           ;加法运算

         JNC     NEXT            ;CY=0,转移

         INC         R2              ;CY=1,高字节加1

NEXT:   INC     R0              ;修改R0地址指针

         DJNE    R7,LOOP         ;未完,重复加

         MOV     41H,R2          ;存和数的高8

         MOV     40H,A           ;存和数的低8

         SJMP    $          

         END

【例4-13 把片内RAM60H6FH单元中的16个补码数逐一取出,若为正数则放回原单元,若为负数则求补后放回原单元。

分析:本题是求机器数的真值。补码定义:正数的补码是其本身,负数的补码是其反码加1。求机器数的真值流程图如图4-12所示。

        

4-11  多字节加法程序流程图              4-12  求机器数的真值流程图

解:编程如下。

         ORG     30H

MAIN:   MOV     R0,#60H          ;设置数据指针

         MOV     R7,#10H          ;设置循环控制数

LOOP:   MOV     A,@R0            ;取数

         JNB     ACC.7,NEXT      ;判断该数是否为负数

         CPL     A                ;是负数,求反

         INC     A                ;该数求反后,再加1,求出其真值

         MOV     @R0,A            ;把该数的真值放回原处

NEXT:   INC     R0               ;修改数据指针,指向下一个要转换的数

         DJNE    R7,LOOP          ;所有的数转换完否?没有,则继续

         SJMP    $                ;转换完,则停止

         END