第十一章 循环程序设计第 1节,循环程序基本结构
(1) 循环程序组成从以上循环程序实例中,我们看到循环程序的特点是程序中含有可以重复执行的程序段。循环程序由以下 4部分组成:
(1) 初始化部分。程序在进入循环处理之前必须先设立初值,例如循环次数计数器、工作寄存器以及其它变量的初始值等,为进入循环做准备。
(2) 循环体部分。循环体也称为循环处理部分,是循环程序的核心。循环体用于处理实际的数据,是重复执行部分。
(3) 循环控制部分。在重复执行循环体的过程中,不断修改和判别循环变量,直到符合循环结束条件。一般情况下,循环控制有以下几种方式:
①计数循环 —— 如果循环次数已知,用计数器计数来控制循环次数,这种控制方式用得比较多。循环次数要在初始化部分预置,在控制部分修改,每循环一次,计数器内容减 1。例 4.6、例 4.7都属于计数循环控制方式。
②条件控制循环 —— 在循环次数未知的情况下,一般通过设立结束条件来控制循环的结束,例 4.8就是用条件 A=0来控制循环结束的。
③开关量与逻辑尺控制循环 —— 这种方法经常用在过程控制程序设计中,
这里不再详述。
(4) 循环结束处理。这部分程序用于存放执行循环程序所得结果以及恢复各工作单元的初值等。
(2) 循环程序的基本结构循环程序通常有两种编制方法:一种是先处理再判断,另一种是先判断后处理,如图 4.18所示。
图 4.18循环程序的两种基本结构
( a)先执行后判断;( b)先判断后执行第 2节 循环控制指令
循环指令和转移指令的功能基本一致,都是完成程序流程的转移,所不同的是循环指令会隐含使用 CX寄存器作为记数器,每执行一次循环指令,( CX)就会自动被减 1。
机器指令格式:
OPCODE( 8位) DISP( 8位)
DISP和条件转移指令中的位移量解释相同,作为相对位移量,转移范围也是 -128到 127。
执行步骤:
1) CX<=( CX) -1
2)若循环条件满足,IP<=( IP) +DISP
循环条件主要是指( CX)是否为 0,如果( CX) =0则停止循环,不改变程序的执行流程,否则执行流程转移,继续循环。
有些循环指令在循环条件中还加上了对 ZF标志的判断。
标志位影响:所有转移指令和循环指令都不会影响任何的标志位(虽然它们有时会对标志位的当前取值进行判断)
( 1) LOOP指令格式,LOOP目标地址执行步骤:
1) CX<=( CX) -1
2)如果( CX) ≠0,转移到目标地址,否则停止循环,顺序执行下一条指令使用前提:在使用 LOOP指令控制循环以前(进入程序的循环体以前),
必须把循环次数保存到 CX。
( 2) LOOPZ / LOOPE指令格式,LOOPZ / LOOPE目标地址执行步骤:
1) CX<=( CX) -1
2)如果( CX) ≠0ANDZF=1,则转移到目标地址,否则停止循环,顺序执行下一条指令。
( 3) LOOPNE / LOOPNZ指令格式,LOOPNE / LOOPNZ目标地址执行步骤:
1) CX<=( CX) -1
2)如果( CX) ≠0ANDZF=0,则转移到目标地址,否则停止循环,顺序执行下一条指令。
( 4) JCXZ指令在循环程序中的作用进入循环体之前,首先使用 JCXZ指令判断( CX)是否为 0,如果为 0就跳转到循环体结束的位置,以免执行错误的循环过程。
第 3节 串操作与重复前缀指令
1.串操作指令
(1)各种串操作指令具有一些共同的特征:
a.源串必须在当前数据段 DS中,目的串必须在附加数据段 ES中,DS
和 ES可以重叠。
b.源串的偏移首地址必须在 SI中,目的串的偏移首地址必须在 DI中。
所有串操作指令均以寄存器间接寻址方式访问操作数。
c.每执行一条串操作指令只能完成串中一个字或一个字节的操作,
同时自动修改 SI和 DI的内容,以指向串中下一个元素。
d.标志位 DF决定串操作的方向,是按增量还是按减量修改。若
DF=0,则按增量修改,字节操作时加 1,字操作时加 2;若 DF=I,则按减量修改,字节操作时减 1,字操作时减 2。
下面依次介绍 MOVS,LODS,STOS,CMPS,SCAS等串操作指令。
MOVS,LODS,STOS三类指令不影响标志位,CMPS,SCAS两类指令影响标志位。
(2)串传送指令格式:
一,MOVS DOPD,SOPD
二,MOVSB
三,MOVSW
功能:将以 SI为指针的源串中的一个字节或字数据传送到以 DI为指针的目的串中。
说明:
a.格式一带有两个操作数,它们是目的串和源串的符号地址,由串定义隐含指出了串的传送类型。
对格式二、三,明确地指定了串的传送类型为字节与字,不能带操作数,后面的指令是类似的情况。
b.与 MOV指令不同,串传送指令允许目的串和源串都是存储器操作数。
(3)串装入指令格式:
—,LODS SOPD
二,LODSB
三,LODSW
功能:将 SI所指源串的一个字节或字数据送寄存器 AL或 AX中。
说明:格式一含有一个源操作数,它隐含说明了源串的类型
(4)串存储指令格式:
—,STOS DOPD
二,STOSB
三,STOSW
功能:将寄存器 AL或 AX中内容存入 DI所指目的串中的字节或字单元中。
说明:与 LODS指令相似,只不过这里的操作数是目的操作数罢了。
(5)串比较指令格式:
—,CMPS DOPD,SOPD
二,CMPSB
三,CMPSW
功能:将 SI所指源串中的一个字节或字数据与 DI所指目的串中相应字节或字数据进行比较。
说明:
a.对标志位的影响与 CMP指令相同。
b.串比较指令与一般比较指令有一个重要区别,比较时用源操作数减目的操作数。
(6)串扫描指令格式:
—,SCAS DOPD
二,SCASB
三,SCASW
功能:在目的串中扫描 AL或 AX的内容,通过标志位的变化描述 AL或 AX的内容是否在目的串中出现。
说明:对字节扫描,以 AL-[DI]影响标志位;对字扫描,以 AX--[DI]影响标志位。
2.重复前缀指令重复前缀指令包括无条件重复前缀指令 REP、条件重复前缀指令 REPZ/ REPE与
REPNZ/ R PNE,它们必须被置于串操作指令之前,其间用空格做分隔,不能独立使用。
使用重复前缀指令时,还必须先将重复次数送入寄存器 CX。每执行一次串操作指令,CX
自动减 1,直到 CX等于 O时终止重复。
(1)无条件重复前缀指令 REP
(2)条件重复前缀指令 REPz,REPE
(3)条件重复前缀指令 REPNz,REPNE
最后有三点说明:
(1)循环控制指令和重复前缀指令乍一看很像,但仔细分析两者差别很大。
首先从功能上看,循环控制指令用于循环执行某一程序段若干次,而重复前缀指令是重复执行某一串操作指令若干次。其次从控制上看,循环控制指令是先将 cx的内容减 l,然后再判断 cx是否等于 0,
若不等于 0,则循环执行;而重复前缀指令是首先判断 Cx是否等于 0,若不等于 0,则重复执行要重复的串操作指令。
(2)重复前缀和串操作指令只能写在一行中,但在用 DEBUG调试程序反汇编调试时,两者却是各占一行。
(3)重复前缀指令可以用循环控制指令实现。
第 4节,循环程序控制方法
1、用计数器控制循环
在循环初始化时设置循环次数 → CX。循环体每工作一次,(CX)-
1→ CX进行调整。当 (CX)= 0,满足结束条件,退出循环。
例 5:存储在 BLOCK为首地址内存中 100个 16bit带符号数,找出最大值后存在 MAX单元中。
取一次
比较 99次
交换 (待定 )
NAME FOUND;定义程序名
DATA SEGMENT;数据段说明开始
BLOCK DW 65C8H,- 35,694AH,……,0A398H
COUNT EQU ($- BLOCK)/2 - 1; $为当前地址
MAX DW;设置 MAX的内存空间
DATA ENDS;数据段说明结束
STACK SEGMENT;堆栈段说明开始
DB 100 DUP(?);保留 100字节堆栈空间
STACK ENDS;堆栈段说明结束
CODE SEGMENT;代码段说明开始
ASSUME CS,CODE,DS,DATA,SS,STACK
FOUND PROC FAR;作为 DOS系统的子程序说明
BEGIN,PUSH DS; DOS的 DS入栈保护
SUB AX,AX; DOS的数据段首地址入栈保护
PUSH AX
MOV AX,DATA
MOV DS,AX;设置本程序的 DS
LEA BX,BLOCK;本程序的运行程序开始
MOV AX,[BX]
INC BX
INC BX
MOV CX,COUNT
AGAIN,CMP AX,[BX]
JG NEXT
MOV AX,[BX]
NEXT,INC BX
INC BX
LOOP AGAIN
MOV MAX,AX;本程序运行结束
RET;调用内部中断返回 DOS
FOUND ENDP;子程序结束说明
CODE ENDS;代码段结束说明
END BEGIN;编译结束说明
2、按条件控制循环当循环次数不确定,则可按循环体工作后是否满足条件的判断确定是否结束循环。按条件控制循环常用于迭代运算或逼近运算。
例 6:牛顿逐次逼近迭代运算 16bit无符号数的平方根。迭代方程为:
Xi+1=(N / Xi +Xi) / 2X1 = (N / 200 ) + 2
迭代结束条件,X i+1-Xi ≤ε。
例如,N=90000,则 X1=( 90000/200) +2=452
X2=( 90000/452+452) / 2 = 326
X3=( 90000/326+326) / 2 = 301
X4=( 90000/301+301) / 2 = 300
第 5节 多重循环程序设计
循环中包含另一个循环。每一循环都有各自的循环计数器和终点判断。多重循环程序的设计方法与单循环程序相同,
但应注意:
*各重循环的初始条件的控制;
*内循环可以嵌套在外循环中,也可以几个内循环并列在外循环中,但各层循环之间不能交叉,内循环可以跳到外循环中,不可以从外循环直接跳进内层循环;
*不能让循环回到初始条件,以免出现死循环。
例:气泡法排序。由小到大有序排列以 BUFFER为首地址的 10个数据无序列,使其成为有序列
1)、排序的关键是比较和交换。
2)、每次循环从数组的底部开始比较,每次循环完成一个小数的气泡升顶。
3)、排序循环的结束条件是:在循环中未出现过交换。
1、关于数据段初始化
DATA SEGMENT
BUFFER DW 22,-12,…,40
COUNT EQU $- BUFFER; (COUNT=20)
DATA ENDS
2、关于比较循环次数对于 10个字数据,比较 9次
MOV CX,COUNT
MOV SI,CX
DEC SI
DEC SI; 第一次取尾字的变址值
SHR CX,1; 20/2= 10个字数据
DEC CX; 10-1= 9次循环
3、关于取数和比较采用变址寻址,其基地址为
BUFFER的地址。
MOV AX,BUFFER [SI];
((SI)+OFFSET BUFFER)--AX
即 Ej --AX
CMP AX,BUFFER [SI-2];
Ej- Ej-1 --PSW
4、关于交换
XCHG AX,BUFFER [SI-2]
MOV BUFFER[SI],AX
因为内存之间不能交换,所以必须通过 AX作为过渡。
第 6节 循环程序设计举例
例 1 对数据区的 30H单元开始清零 64个单元
MOV R0,#30H
MOV R7,#64
MOV A,#0
LOOP,MOV @R0,A
INC R0
DJNZ R7,LOOP
例 2
计算一串 8位二进制无符号数之和,假定数串长度 50个,排放在 30H单元开始的 RAM中,并假定累加和不大于 8位二进制数。
MOV R0,#30H
MOV R1,#50
MOV A,#0
LOOP,ADD A,@R0
INC R0
DJNZ R1,LOOP
STOP,MOV 65H,A
例 3 软件延时 —— 多重循环
※ 时序的概念一条指令可分解成若干微操作,而这些微操作所对应的脉冲信号在时间上有严格的先后次序,这种次序就是计算机的时序。
计算机时序的基本概念:
①振荡周期:为单片机提供定时信号的振荡源周期。
P3页图是常用的振荡电路,它用外接晶振作为定时单元,晶振频率 f在 1.2MHZ~ 12MHZ之间。
1振荡周期 =1/f
② 状态周期,1状态周期 =2× 振荡周期常又把一个状态周期分为两个状态,称 P1状态,P2状态。
③机器周期,1机器周期 =12× 振荡周期 =12/f
可用机器周期把一条指令划分成若干阶段,每个机器周期完成某些规定动作
④指令周期:指完成一条指令所需的全部时间。各条指令不等。
以 6MHZ晶振为例:
1振荡周期 =1/6M=1/6μs
1状态周期 =2× 振荡周期 =1/3μs
1机器周期 =12/f= 2μs
1指令周期 =2~ 8μs
执行每条指令需要的机器周期数可在指令表中查到。
延时程序就是计算机重复执行一些指令,累积的时间就是软件延时的时间。