
3.5 汇编语言程序设计
3.5.1 程序设计步骤和基本结构
1.汇编语言程序设计的步骤
1)分析题意。明确课题要达到的目的、技术指标等。
2)确定算法。根据要求和条件,确定所采用的计算公式和计算方法。这是程序设计的依据。
3)画程序流程图。程序流程图是用流程图的方式使程序的算法具体化的表示,它直观清晰地表现了程序的设计思路。对于较大的程序,流程图有助于对程序进行高效的设计和调试。程序流程图的常用符号如图3-3所示,用这些符号可以构成不同算法的程序流程。

图3-3 程序流程图常用符号
4)分配内存工作单元,确定程序与数据区的存放地址。
5)编写源程序代码。按照汇编语言程序设计格式,用指令和伪指令实现流程图的功能代码,形成完整的程序。
6)程序优化。主要是指缩短程序代码长度、减少程序执行时间及节省内部工作单元。
7)上机调试、修改和最后确定源程序。利用软件仿真技术和系统仿真方法对程序仿真运行,并对程序进行测试和修改,直至满足要求。
2.结构化程序设计
单片机的结构化程序主要包括5种结构:顺序结构、分支机构、循环结构、子程序及中断服务程序。其中,中断服务程序将在第7章介绍。
(1)顺序结构
顺序结构是指程序中的语句由前往后顺序执行,如图3-4a所示。

图3-4 三种基本的程序结构
(2)分支结构
分支结构程序的特点是程序中含有转移指令。由于转移指令有无条件转移(LJMP、AJMP、SJMP、JMP)和条件转移(JZ、JNZ、CJNE、JC、JNC、JB、JNB)之分,因此分支程序也可分为无条件分支程序和条件分支程序两类。
分支结构程序首先要对问题的条件进行判断,根据判断结果转向不同的分支程序段。图3-4b、c是常用的两种分支情况,相对于顺序执行的程序而言,图3-4b是一种“单分支”,图3-4c是一种“双分支”,对于多分支,可以通过多次应用“双分支”或“散转”方法实现。
【例3-14】 编程实现如下分段函数,设自变量X放在30H单元,并将Y存入FUNC单元。

解:这是一个三分支归一的条件转移问题,程序实现通常可分为“先分支后赋值”和“先赋值后分支”两种求解办法。这里用“先分支后赋值”方法编程。程序流程图如图3-5所示。

图3-5 例3-14流程图

散转指令JMP @A + DPTR可以实现无条件转移。其中,DPTR装入多分支转移程序的首地址,用累加器A的内容来动态选择其中的某一个分支予以转移。这样一条指令可实现以DPTR内容为起始地址的256字节范围内的选择转移。
【例3-15】设有一个键值处理子程序KEYREAD,能把读取的按键“0~9”转换为对应的数值并传给累加器A。编写程序对读入的不同键值0~9,分别转入对应的键控程序段KEY0 ~ KEY9执行。
解:按题目要求编写程序如下:

(3)循环结构
对于需要重复执行的同类操作,如统计数据个数等,可采用循环程序实现。
循环程序结构有“先处理后判断”和“先判断后处理”两种,如图3-4d、e所示。
循环程序一般由4部分组成,即循环变量初值、循环变量变化方式(每执行一次循环体加1或减1)、循环体(重复执行部分)及循环变量终值(循环结束的条件)。
【例3-16】将外部RAM的1000H单元开始的10个数据传送到内部RAM中50H起始的连续单元。
解:为了使读者对两种循环结构有一个全面了解,以便进行分析比较,现给出两种设计方案。
方案一:“先处理后判断”

方案二:“先判断后处理”

(4)子程序
在汇编语言程序设计时,对于一些经常需要执行的程序段,为避免重复编制程序,节省程序代码所占的存储空间,可将其编制成独立的子程序段,在需要的位置采用特定的指令调用该子程序,执行后再返回到调用位置继续执行后序程序指令。
子程序结构:

子程序可以和主程序之间传递参数,主程序传给子程序的参数为入口参数,通过约定的工作寄存器R0~R7、特殊功能寄存器SFR、内存单元或堆栈等传送给子程序使用;子程序执行的结果传给主程序的参数为出口参数,通过约定的R0~R7、SFR、内存单元或堆栈等传递给主程序使用。
【例3-17】请编程实现c = a2+b2。设a放在30H单元,b放在31H单元,运算结果放在32单元,a和b皆为小于10的整数。
解:本程序由主程序和子程序两部分组成。主程序通过累加器A传送子程序的入口参数a或b,子程序也通过累加器A传送出口参数a2、b2给主程序,子程序为求一个数的平方的通用子程序。程序如下:

上述程序采用了查表法求一个1位十进制数的平方,并且通过子程序调用求两个数的平方和。
【例3-18】请编写一个延时子程序,延时时间系数放在30H单元(设fosc=6MHz)。
解:本子程序入口参数是延时时间系数,延时的时间由程序指令的执行时间确定。程序如下:

上述子程序采用二层循环。由fosc=6MHz知道机器周期为2μs,DJNZ指令执行1次要2个周期,所以内循环的时间为1ms。外循环次数由入口参数确定,若入口参数为N,则调用一次DELAY子程序,延时时间约为N ms,改变入口参数,可以得到不同的时延。