4.1程序编制的方法和技巧4.2源程序的编辑和汇编4.3基本程序结构4.4常用程序举例第4章80C51的程序设计4.1程序编制的方法和技巧4.1.1程序编制的步骤一、预完成任务的分析首先,要对单片机应用系统预完成的任务进行深入的分析,明确系统的设计任务、功能要求和技术指标。其次,要对系统的硬件资源和工作环境进行分析。这是单片机应用系统程序设计的基础和条件。任务分析算法优化流程图绘制编程调试二、进行算法的优化算法是解决具体问题的方法。应用系统经过分析、研究和明确规定后,对应实现的功能和技术指标可以利用严密的数学方法或数学模型来描述,从而把实际问题转化成由计算机进行处理的问题。同一个问题的算法可以有多种,结果也可能不尽相同,所以,应对各种算法进行分析比较,并进行合理的优化。比如,用迭代法解微分方程,需要考虑收敛速度的快慢(即在一定的时间里能否达到精度要求)。而有的问题则受内存容量的限制而对时间要求并不苛刻。对于后一种情况,速度不快但节省内存的算法则应是首选。三、程序总体设计及流程图绘制经过任务分析、算法优化后,就可以进行程序的总体构思,确定程序的结构和数据形式,并考虑资源的分配和参数的计算等。然后根据程序运行的过程,勾画出程序执行的逻辑顺序,用图形符号将总体设计思路及程序流向绘制在平面图上,从而使程序的结构关系直观明了,便于检查和修改。•清晰正确的流程图是编制正确无误的应用程序的基础和条件。所以,绘制一个好的流程图,是程序设计的一项重要内容。•流程图可以分为总流程图和局部流程图。•总流程图侧重反映程序的逻辑结构和各程序模块之间的相互关系。•局部流程图反映程序模块的具体实施细节。对于简单的应用程序,可以不画流程图。但是当程序较为复杂时,绘制流程图是一个良好的编程习惯。常用的流程图符号有:开始和结束符号、工作任务符号、判断分支符号、程序连接符号、程序流向符号等开始或结束符号工作任务符号判断分支符号程序连接符号程序流向符号程序流向符号4.1.2编制程序的方法和技巧一、采用模块化程序设计方法应用系统的程序由包含多个模块的主程序和各种子程序组成。各程序模块都要完成一个明确的任务,实现某个具体的功能,如:发送、接收、延时、打印和显示等。模块化的程序设计方法具有明显的优点。把一个多功能的复杂的程序划分为若干个简单的、功能单一的程序模块,有利于程序的设计和调试,有利于程序的优化和分工,提高了程序的阅读性和可靠性,使程序的结构层次一目了然。二、尽量采用循环结构和子程序采用循环结构和子程序可以使程序的长度减少、占用内存空间减少。(多重循环,注意各重循环的初值和循环结束条件,避免出现“死循环”现象;)通用的子程序,除了用于存放子程序入口参数的寄存器外,子程序中用到的其它寄存器的内容应压入堆栈进行现场保护,并要特别注意堆栈操作的压入和弹出的平衡;中断处理子程序除了要保护程序中用到的寄存器外,还应保护标志寄存器。4.1.3汇编语言的语句格式语句行由四个字段组成:[标号:]操作码[操作数][;注释]括号内的部分可以根据实际情况取舍。每个字段之间要用分隔符分隔,可以用作分隔符的符号有空格、冒号、逗号、分号等。如:LOOP:MOVA,#7FH;A←7FH一、标号标号是语句地址的标志符号,用于引导对该语句的非顺序访问。有关标号的规定为:二、操作码操作码用于规定语句执行的操作。它是汇编语句中唯一不能空缺的部分。它由指令助记符表示。①由1~8个ASCII字符组成。第一个字符必须是字母,其余字符可以是字母、数字或其他特定字符;②不能使用已经定义了的符号作为标号。如指令助记符、寄存器符号名称等;③后边必须跟冒号。三、操作数操作数用于给指令的操作提供数据或地址。在一条汇编语句中操作数可能是空缺的,也可能包括一项,还可能包括两项或三项。各操作数间以逗号分隔。操作数字段的内容可能包括以下几种情况:①工作寄存器名;②特殊功能寄存器名;③标号名;④常数;⑤符号“$”,表示程序计数器PC的当前值;⑥表达式。四、注释注释只是对语句的说明。注释字段可以增加程序的可读性,有助于编程人员的阅读和维护。对计算机而言,“注释”是“看不见”的。注释字段必须以分号“;”开头,长度不限,当一行书写不下时,可以换行接着书写,但换行时应注意要在开头使用分号“;”。五、数据的表示形式数据可以有以下几种表示形式:①二进制数,末尾以字母B标识。如:10001111B;②十进制数,末尾以字母D标识或将字母D省略。如:88D,66;③十六进制数,末尾以字母H标识。如:78H,0A8H(但应注意的是,十六进制数以字母A~F开头时应在其前面加上数字“0”。);④ASCII码,以单引号括起来标识。如:‘AB’,‘1245’4.2源程序的编辑和汇编一、源程序的编辑源程序的编写要依据80C51汇编语言的基本规则,特别要用好常用的汇编命令(即伪指令),例如下面的程序段:ORG0040HMOVA,#7FHMOVR1,#44HEND这里的ORG和END是两条伪指令,其作用是告诉汇编程序此汇编源程序的起止位置。编辑好的源程序应以“.ASM”扩展名存盘,以备汇编程序调用。4.2.1源程序的编辑与汇编二、源程序的汇编将汇编语言源程序转换为单片机能执行的机器码形式的目标程序的过程叫汇编。常用的方法有两种:•手工汇编,把程序用助记符指令写出后,通过手工方式查指令编码表,逐个把助记符指令翻译成机器码,然后把得到的机器码程序(以十六进制形式)键入到单片机开发机中,并进行调试。•机器汇编是在常用的个人计算机PC上,使用交叉汇编程序将汇编语言源程序转换为机器码形式的目标程序。生成的目标程序由PC机传送到开发机上,经调试无误后,再固化到单片机的程序存储器ROM中。源程序经过机器汇编后,形成的若干文件中含有两个主要文件,一是列表文件,另一个是目标码文件。因汇编软件的不同,文件的格式及信息会有一些不同。但主要信息如下:列表文件:地址目标码汇编程序ORG0040H0040H747FMOVA,#7FH0042H79AAMOVR1,#0AAHEND目标码文件:首地址末地址目标码0040H0044H747F79AA4.2.2伪指令伪指令是汇编程序能够识别并对汇编过程进行某种控制的汇编命令。它不是单片机执行的指令,所以没有对应的可执行目标码,汇编后产生的目标程序中不会再出现伪指令。一、起始地址设定伪指令ORG格式为:ORG表达式该指令的功能是向汇编程序说明下面紧接的程序段或数据段存放的起始地址。表达式通常为16进制地址,也可以是已定义的标号地址。ORG8000HSTART:MOVA,#30H……此时规定该段程序的机器码从地址8000H单元开始存放。在每一个汇编语言源程序的开始,都要设置一条ORG伪指令来指定该程序在存储器中存放的起始位置。若省略ORG伪指令,则该程序段从0000H单元开始存放。在一个源程序中,可以多次使用ORG伪指令规定不同程序段或数据段存放的起始地址,但要求地址值由小到大依序排列,不允许空间重叠。二、汇编结束伪指令END格式为:END该指令的功能是结束汇编。汇编程序遇到END伪指令后即结束汇编。处于END之后的程序,汇编程序将不处理。三、字节数据定义伪指令DB[标号:]DB字节数据表功能是从标号指定的地址开始,在ROM中定义字节数据。该伪指令将字节数据表中的数据根据从左到右的顺序依次存放在指定的存储单元中。一个数据占一个存储单元。例如:DB“howareyou?”DB-2,-4,-6,8,10,18四、字数据定义伪指令DW[标号:]DW字数据表功能是从标号指定的地址单元开始,在程序存储器中定义字数据。该伪指令将字或字表中的数据根据从左到右的顺序依次存放在指定的存储单元中。应特别注意:16位的二进制数,高8位存放在低地址单元,低8位存放在高地址单元。例如:ORG1400HDATA:DW324AH,3CH……汇编后,(1400H)=32H,(1401H)=4AH,(1402H)=00H,(1403H)=3CH。五、空间定义伪指令DS[标号:]DS表达式功能是从标号指定的地址单元开始,在程序存储器中保留由表达式所指定的个数的存储单元作为备用的空间,并都填以零值。例如:ORG3000HBUF:DS50……汇编后,从地址3000H开始保留50个存储单元作为备用单元。六、赋值伪指令EQU符号名EQU表达式功能是将表达式的值或特定的某个汇编符号定义为一个指定的符号名。LENEQU10SUMEQU21HBLOCKEQU22HCLRAMOVR7,#LENMOVR0,#BLOCKLOOP:ADDA,@R0INCR0DJNZR7,LOOPMOVSUM,AEND该程序的功能是,把BLOCK单元开始存放的10个无符号数进行求和,并将结果存入SUM单元中。七、位地址符号定义伪指令BIT格式为:符号名BIT位地址表达式功能是将位地址赋给指定的符号名。其中,位地址表达式可以是绝对地址,也可以是符号地址。STBITP1.0将P1.0的位地址赋给符号名ST,在其后的编程中就可以用ST来代替P1.0。SETBST八、定义数据存储器地址伪指令DATA格式:标示符DATA数据存储器地址BUF1DATA30HMOVBUF1,#55HMOVBUF1+1,#0AAH4.3基本程序结构78H56H34H12H00H2EH2DH2CH2BH2AHACC78H56H34H12H00H2EH2DH2CH2BH2AHACC00H4.3.1顺序程序顺序程序是指无分支、无循环结构的程序。其执行流程是依指令在存储器中的存放顺序进行的。一、数据传送例内部RAM的2AH~2EH单元中存储的数据如图所示。试编写程序实现图示的数据传送结果。三种算法,那种最优?方法一:MOVA,2EH;2bytes,1TmMOV2EH,2DH;3bytes,2TmsMOV2DH,2CH;3bytes,2TmsMOV2CH,2BH;3bytes,2TmsMOV2BH,2AH;3bytes,2TmsMOV2AH,#00H;3bytes,2Tms注意存储单元的先后顺序,有用的数据要保存着。方法二:CLRA;1byte,1TmXCHA,2AH;2bytes,1TmXCHA,2BH;2bytes,1TmXCHA,2CH;2bytes,1TmXCHA,2DH;2bytes,1TmXCHA,2EH;2bytes,1Tm把要搬移的数据暂存在A中。方法三:R0=源数据初始地址R1=目的数据初始地址R7=字节数把R0指向的单元数据读入A,再把A写入R1指向的单元。R7-1=0?NY开始结束MOVB,2EHMOVR0,#2DHMOVR1,#2EHMOVR7,#04H;循环四次LOOP:MOVA,@R0;取数MOV@R1,A;存放数据DECR0;修正地址DECR1DJNZR7,LOOP;循环四次MOVA,BACC782EH78R1→2EH56R0→2DH562DH342CH342CH122BH122BH002AH002AH00→#2000HDPTR→(20H)A→(A+DPTR)A→A21H开始结束ORG1000HSTART:MOVDPTR,#2000HMOVA,20HMOVCA,@A+DPTRMOV21H,ASJMP$ORG2000HTABLE:DB00,01,04,09,16,25END二、查表例有一变量存放在片内RAM的20H单元,其取值范围为:00H~05H。要求编制一段程序,根据变量值求其平方值,并存入片内RAM的21H单元。50H低8位←R051H高8位60H低8位←R161H高8位三、简单运算由于80C51指令系统中只有单字节加法指令,因此对于多字节的相加运算必须从低位字节开始分字节进行。除最低字节可以使用ADD指令外,其他字节相加时要把低字节的进位考虑进去,这时就应该使用ADDC指令。例双字节无符号数加法。设被加数存放在内部RAM的51H、50H单元,加数存放在内部RAM的61H、60H单元,相加的结果存放在内部RAM的51H、50H单元,进位存放在位寻址区的00H位中。R0=一个加数低位地址,R1=另一加数低位地址把R0指