第4章 程序设计.ppt

上传人:hyn****60 文档编号:70971012 上传时间:2023-01-31 格式:PPT 页数:78 大小:512.50KB
返回 下载 相关 举报
第4章 程序设计.ppt_第1页
第1页 / 共78页
第4章 程序设计.ppt_第2页
第2页 / 共78页
点击查看更多>>
资源描述

《第4章 程序设计.ppt》由会员分享,可在线阅读,更多相关《第4章 程序设计.ppt(78页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、第第4章章程序设计程序设计教学目标教学目标介绍单片机汇编程序设计方法介绍单片机汇编程序设计方法介绍单片机汇编程序常用结构及设计方法介绍单片机汇编程序常用结构及设计方法介绍介绍典型智能仪表单片机系统应用软件设计典型智能仪表单片机系统应用软件设计介绍介绍目前流行的目前流行的MCS-51单片机高级语言单片机高级语言C51学习要求学习要求熟悉单片机编程的步骤、方法和技巧熟悉单片机编程的步骤、方法和技巧掌握单片机汇编程序的常用结构及设计方法掌握单片机汇编程序的常用结构及设计方法掌握典型汇编语言应用程序的编制掌握典型汇编语言应用程序的编制了解单片机高级程序设计语言了解单片机高级程序设计语言C51单片机系统

2、设计由硬件设计和软件单片机系统设计由硬件设计和软件设计两部分组成,设计两部分组成,后者就是设计程序、编制表格,以指挥单片机完成用户交付的任务。本章介绍MCS-51单片机汇编语言程序设计的基本步骤、方法和技巧,并在最后简单地介绍了C51高级程序设计。4.1编程的步骤、方法和技巧编程的步骤、方法和技巧单片机常用于工业测控装置和智能仪表等,这些应用场所往往对实时性提出了要求。使用汇编语言设计程序,虽然比高级语言烦琐,但它能最充分地发挥指令系统的功能与效率,获得最简练的目标程序,能满足实时性要求。用汇编语言设计单片机应用程序往往要经历以下几个步骤:(1)软件任务分析;(2)数据类型和数据结构规划;(3

3、)资源分配;(4)编程与调试。4.1.1软件任务分析软件任务分析软件任务分析是为软件设计作一个总体规划。从功能来看,软件可分为两大类:一类是执行软件,它能完成各种实质性的功能,如测量、计算、显示、打印、输出控制和通信等;另一类是监控软件,它是专门用来协调各执行模块和操作者的关系,在系统软件中充当组织调度角色的软件。这两类软件的设计方法各有特色,执行软件的设计偏重算法效率,与硬件关系密切。监控软件着眼全局,逻辑严密。软件任务分析时,应将各执行模块一一列出,并为每一个执行模块进行功能定义和接口定义(输入、输出定义)。在为各执行模块进行定义时,将要牵涉到的数据结构和数据类型的问题也一并规划好。各执行

4、模块规划好后,就可以规划监控程序了。首先根据系统功能和键盘设置选择一种最合适的监控程序结构。相对来讲,执行模块任务明确单纯,比较容易编程。而监控程序较易出问题。任务分析的另一个内容是如何安排监控软件和各执行模块。整个系统软件可分为后台程序和前台程序。后台程序指主程序及其调用的子程序,这类程序对实时性要求不是很高,延误几十毫秒甚至几百毫秒也没关系,故通常将监控程序(键盘管理程序)、显示程序和打印程序等与操作者打交道的程序放在后台程序中来执行。而前台程序安排一些实时性要求较高的内容,如定时系统和外部中断。在一些特殊场合,也可以将全部程序均安排在前台,后台为踏步等待循环或睡眠状态。4.1.2数据类型

5、和数据结构规划数据类型和数据结构规划前面的软件任务分析只是一个粗糙的分析和大体上的安排,还不能开始编程。为了避免系统中各个执行模块之间的脱节现象,就必须严格规定好各个接口条件,即各接口参数的数据结构和数据类型。从数据类型上来分类,可分为逻辑型和数值型,但通常将逻辑型数据归到软件标志中去考虑。而将数据类型分类理解为数值类型分类。数值类型可分为定点数和浮点数。如果一个参数的变化范围有限,就可用定点数来表示,以简化程序设计和加快运行速度;当参数的变化范围太宽时,只好采用浮点数来表示。如果某参数是一系列有序数据的集合,如采样信号系列,则不光有数据类型问题,还有一个数据存放格式问题,即数据结构问题。在单

6、片机应用系统中,数据结构比较简单,大多采用线性结构,这样有利于数据处理。由于受RAM空间的限制,队列结构广泛采用环行队列结构,为此应规划好两样东西:队列区域和队尾(首)指针,并计算出总共需要的RAM字节数。对于数组,一般采用顺序存放的格式。这样就可以用简单的下标运算来访问数组中的任何一个元素。4.1.3资源分配资源分配完成数据类型和数据结构的规划后,便可开始分配系统的资源了。在微机测控系统中,往往需要定时检测某个物理参数,或按一定的时间间隔来进行某种控制等。这种定时的获得常采用定时/计数器,它还可以对某种事件进行计数,然后根据计数结果来进行控制;单片机在及时处理实时测、控中的许多随机的参数和信

7、息、对外界异步事件包括故障的处理常使用中断,在任务分析时一般要将定时/计数器和中断源等资源分配好。ROM资源用来存放程序和表格,这也是明显的。系统资源ROM、RAM、定时/计数器、中断源等。因此,资源分配的主要工作是RAM资源的分配。片外RAM的容量比片内RAM大,通常用来存放大批量的数据,如采样数据系列。真正需要认真考虑的是片内RAM的分配。片内RAM指00H7FH单元。这128个字节的功能并不完全相同,分配时应注意充分发挥各自的特长,做到物尽其用。00H1FH这32个字节可以作为工作寄存器,其中00H0FH用来作为0区、1区工作寄存器。在一般的应用系统中,后台程序用0区工作寄存器,前台程序

8、用1区工作寄存器。如果有高级中断,则高级中断可用2区工作寄存器(10H17H)。如果前台程序中不使用工作寄存器,则系统只需0区工作寄存器。未作为工作寄存器的其它单元便可以转为其它目的使用了。系统上电复位时,自动定义0区为工作寄存器,1区为堆栈,并向2区、3区延伸。如果前台程序要用1区、2区作为工作寄存器,就应将堆栈空间重新规划。在工作寄存器的8个单元中,R0和R1具有指针功能,是编程的重要角色,应充分发挥其作用,尽量避免用来做其它事情。20H2FH这16个字节具有位寻址功能,用来存放各种软件标志、逻辑变量、位输入信息、位输出信息副本、状态变量、逻辑运算的中间结果等。当这些项目安排好后,保留一两

9、个字节备用,剩下的单元才可改作其它用途。30H7FH为一般通用寄存器,只能存入整字节信息。通常用来存放各种参数、指针、中间结果,或用作数据缓冲区。也常将堆栈安排在片内RAM的高端,如68H7FH。如果将系统的各种开销安排后,所剩单元很少,这往往不是好的兆头。应该留有足够的余地,因为现在还处于规划阶段,随着软件设计的发展进程,几乎都会出现新的资源要求。如果在规划阶段资源已经很紧张,建议修改硬件设计,增加RAM资源。RAM资源规划好后,应列出一张RAM资源的详细分配清单,作为编程依据。4.1.4编程与调试编程与调试 上述各项准备工作都完成后,就可以开始编程了。软件设计有两种方法:一种是自上而下,逐

10、步细化;一种是自下而上,先设计出每一个具体的模块(子程序),然后再慢慢扩大,最后组成一个系统。两种方法各有优缺点。单片机由于本身没有开发能力,故编程均在各种类型的开发系统上进行。基本过程是相同的:用编辑软件编辑出源程序,再用编译软件生成目标代码,如果源程序中有语法错误则返回编辑过程,修改源程序后再继续编译,直到通过这一关。然后对程序进行测试,纠正测试中发现的错误。接着就在开发系统上仿真运行,试运行中将会发现不少设计错误(不是语法错误),再从头修改源程序,如此反复直到基本成功,就可以投入实际环境中使用。4.24.2汇编语言源程序的编辑和汇编汇编语言源程序的编辑和汇编 用助记符和标号地址编写的程序

11、称为汇编语言源程序;而将助记符翻译成机器码以及将标号地址换算成实际地址的工作都由计算机通过一种称为汇编程序的软件完成,这种翻译和换算的过程一般就称为汇编。4.2.1汇编语言源程序的格式汇编语言源程序的格式一般来讲,汇编语言源程序由四部分组成,即标号、操作码、操作数和注释。每两个部分之间要用分隔符隔开,而每一部分内部不采用分割符。可以采用的分割符有:空格“”、冒号“:”、分号“;”,空格的数目可以不止一个。汇编语言源程序的一般形式为:标号:操作码操作数;注释方括号在实际程序中并不书写,也不输入到计算机里,只是表示方括号内的项是任选项,此项可有可无,若不需要时,在某一行可以不包括此项。故对每一行源

12、程序来说,只有操作码是必不可少的,其余三部分都可视情况而定。汇编程序只处理分号“;”以前的字符,对于注释部分,计算机在汇编时不予处理。注释部分便于程序的使用者更好地理解程序的功能,有助于程序的交流使用。软件工作者从一开始就要养成写好注释的良好习惯。对于有些指令,操作数不止一个,有两个甚至三个,在输入计算机时,各操作数之间要用逗号作分割符。一、标号一、标号标标号号由由8个个或或8个个以以下下的的字字母母数数字字构构成成,第第一一个个必必须须是是字字母母。另外还允许使用一个下横线符号“”。其它的符号都不允许在标号中使用。此外,系统中保留使用的字符或字符组不能用作标号,以免引起混淆。如各种特殊功能寄

13、存器名、各个位地址记忆符、各种伪指令等都不能用作标号。以下是一些合法的标号:A1,LOOP等。以下的字符串不能用作标号:4G,F-G,DB,EQU(后两种为保留字)。标号不是每一行都必须要有,而只是在需要时才使用。二、操作数二、操作数对于立即数#data来说,使用时,一般都在#后面跟一个具体的数。这个数可以是二进制数,应以字母“B”作为结束,如#10010011B;也可以是十六进制数,则以字母“H”结尾,如88H,但若最高位为AF之中的字母,则前面还要加一个数字“0”,如#0ABH。如果这个0忘了加上,汇编程序将认为所写的是一个编号。如果数字的最后没有结束字母,则认为是十进制数,如#10。立即

14、数的data也可以用定义过的标号来代替,这种定义要用到伪指令EQU等。对于直接地址direct来说,在实际使用时,也可以有多种选择:1.二进制数,十进制数或十六进制数,如:MOVA,30H等;2.标号地址,如:MOVA,SUM等,SUM应该在程序中某处加以定义;3.带加减的表达式,如:MOVA,SUM+9,SUM为已定义的符号地址;4.特殊功能寄存器名,如:MOVA,SP等。对于偏移量rel,除了可以采用上面提到的各种数值、标号地址以及表达式之外,还可以采用一个专门的符号“$”,它表示相对转移指令所在的地址,例如:LJMP$这条指令实际上是一条自身跳转的死循环。在实际 编 程 时,凡 是 指

15、令 中 用 到 地 址 的 地 方(rel,addr11,addr16)都用标号地址代替实际地址,而将复杂的地址运算交给汇编程序完成。4.2.2伪指令伪指令 每种汇编语言都会定义若干伪指令,用来对汇编过程进行某种控制,或对符号、标号赋值。伪指令和指令是完全不同的。在汇编过程中,由于伪指令并不执行可执行的目的代码,因而大部分伪指令甚至不会影响存储器中的内容。对不同版本的汇编语言,伪指令的符号和含义可能不同,但基本的用法是相似的。下面就介绍一些常用的伪指令。一、一、ORG(汇编起始命令汇编起始命令)其功能是规定下面的目标程序的起始地址,指令格式为:标号:ORG addr16其中括号内是任选项,可以

16、没有,例如:ORG 1000HLAB:MOV A,#3H即,规定了标号LAB所在的起始地址为1000H,第一条指令就从1000H开始存放。一般在一个汇编语言源程序的开始,都用一条ORG伪指令来规定程序存放的起始位置,故称为汇编起始命令。二、二、END(汇编结束命令)汇编结束命令)END是汇编语言源程序的结束标志,在END以后所写的指令,汇编程序都不予处理。一个源程序只能有一个END命令。在同时包含有主程序和子程序的系统中,也只能有一个END命令,并存放到所有指令的最后,否则,就有一部分指令不能被汇编。其格式为:标号:END三、三、EQU(等值命令)等值命令)其功能是将一个数或者特定的汇编符号赋

17、予规定的符号名称,其格式为:字符名称EQU数或汇编符号例如:INPEQUP1MOV A,INP这里将INP等值为汇编符号P1,在指令中INP就可以代替P1来使用。四、四、DATA(数据地址赋值命令)数据地址赋值命令)其功能是将数据地址或代码地址赋予规定的字符名称,其格式为:字符名称DATA表达式DATA伪指令的功能和EQU有些相似,使用时要注意它们的差别:(1)EQU伪指令定义的符号必须先定义后使用,而DATA伪指令的符号可以先使用后定义;(2)用EQU伪指令可以把一个汇编符号赋给一个字符名称,而DATA伪指令则不能。(3)DATA伪指令可将一个表达式的值赋给一个字符名称,所定义的字符名称也可

18、以出现在表达式中,而用EQU定义的字符则不能这样使用。(4)DATA伪指令常在程序中用来定义数据地址。五、五、DB(定义字节指令)定义字节指令)其功能是从规定的地址单元开始,定义若干个8位内存单元的内容,其格式为:标号:DB8位数据表这个伪指令是在程序存储器的某一部分存入一组规定好的8位二进制数,或者是将一个数据表格存入程序存储器。这个伪指令在汇编后,将影响程序存储器的内容。例如:TAB1:DB3FH,55,8,CTAB2:DB10100B设TAB1的对应地址为2000H,则以上伪指令经汇编以后,将对2000H开始的若干内存单元赋值:(2000H)=3FH(2001H)=37H(2002H)=

19、38H(2003H)=43H (2004H)=14H六、六、DW(定义字命令)定义字命令)其功能是从指定地址开始,定义若干个16位数据,其格式为:标号:DW16位数据表每个16位数据要占ROM的两个单元,在MCS-51系统中,16位二进制数的高8位先存入低地址字节,低8位后存入高地址字节。这和MCS-51指令中的16位数据存放的方式一致。例如:ORG1000HDW3964H,6H,20汇编以后结果为:(1000H)=39H(1001H)=64H(1002H)=00H(1003H)=6H(1004H)=00H(1005H)=14H七、七、BIT(位地址符号命令)位地址符号命令)其功能是将位地址赋

20、予所规定的字符名称,其格式为:字符名称 BIT位地址例如:RECORD BITP2.2PLAYBITP2.3这样就把两位位地址分别赋给两个变量RECORD和PLAY,在编程中它们可当作位地址来使用。但不是所有的MCS-51汇编程序都有这条伪指令。当不具备BIT命令时,可以使用EQU命令来定义位地址变量,但这时所赋的值应该是具体的位地址,例如P1.0就要具体地用90H来代替。4.2.3源程序的编辑和汇编源程序的编辑和汇编源程序的编辑可以使用任何可编辑和存储文本格式的文件编辑器,如Windows操作系统提供的写字板(Wordpad)和笔记本(Notebook)、Word文字处理器和各种单片机集成开

21、发软件如MEDWIN、MPLAB、WAVE等。用文本文件编辑器编辑和汇编单片机程序的过程如下:(1)用文件编辑器编辑汇编语言源程序,它的扩展名为.ASM;(2)经检查无明显的语法错误后,再采用单片机汇编程序ASM51进行汇编,产生扩展名为.LST的列表输出文件和扩展名为.HEX的目标代码文件;列表输出文件:包含源程序语句所汇编成的代码,以及有关的地址、语句和符号表等;目标代码文件:包含源程序语句所汇编成的代码,不包含任何符号信息或助记符。用单片机集成开发软件编辑和汇编单片机程序的过程如下:(1)在集成开发环境中编辑器编辑汇编语言源程序,它的扩展名为.ASM;(2)在集成开发环境中设置编译所采用

22、的正确汇编程序(一般为ASM51)后,用鼠标点击编译工具条或菜单可直接进行汇编。若源程序无语法错误,会产生扩展名为.LST的列表输出文件和扩展名为.BIN(或.HEX)的目标代码文件;若源程序有语法错误,一般不会产生列表输出文件和目标代码文件,但会弹出一个信息窗口,指示出错位置和错误类型。用鼠标点击出错指示信息,会直接跳到源程序出错语句,修改正确后,再一次编译,则会弹出信息窗口指示汇编成功,源程序无语法错误,并产生相应的目标代码文件和列表输出文件。4.34.3汇编语言程序设计汇编语言程序设计4.3.14.3.1程序流程图设计及子程序设计程序流程图设计及子程序设计一、程序流程图一、程序流程图1概

23、述概述编制程序的正确做法是先画程序流程图,再开始编程,而不是编完程序后再补画程序流程图。程序流程图在“高级语言程序设计”相关课程中大家已熟悉,它是一种以框图形式表示程序结构的。画程序流程图的过程是进行程序的逻辑设计过程,这中间的任何错误或忽视将会导致程序出错或可靠性下降。可以认为真正的程序设计过程是流程图设计,而上机编程是将设计好的程序流程图转换成程序设计语言而已。2.程序流程图的画法程序流程图的画法正确的流程图画法是先粗后细、一步一个脚印,只考虑逻辑结构和算法,不考虑或少考虑具体指令。这样画流程图就可以集中精力考虑程序的结构,从根本上保证程序的合理性和可靠性,剩下来的任务只是进行指令代换,这

24、时只要消除语法错误,一般就能顺利编出源程序,并且很少大返工。下面用一个例子来说明流程图的画法:有一数据采集系统,将采集到的一批数据存放在片外RAM中,数据类型为双字节十六进制整数,存放格式为顺序存放,高字节在前(低地址),低字节在后(高地址),数据块的首址已知,数据总个数(不超过256)也已知。现要设计一个程序,计算下列公式的值:式中,n为数据总个数,Xi为某个数据,为这n个数据的平均值。要求最后结果以BCD码百分数表示,并精确到0.1%。第第一一步步,先进行最原始的规划,画第一张程序流程图,如图4-2所示。在画第一张程序流程图时,将总任务分解成若干个子任务,安排好它们之间的相互关系,暂不管各

25、个子任务如何完成。这一步看起来简单,但千万不能出错,这一步错误是属于宏观决策错误,有可能造成整体推倒重来。图4-2开始求X求求开平方求V结束第第二二步步,将第一张流程图的各个子任务进行细化。决定每个子任务采用哪种算法,而暂不考虑如何为数据指针、计数器、中间结果配置存放单元等具体问题。由于内容比第一张详细,如果全图画在一起不方便,可以分开画,但要注意各分图之间的连接关系。第二张流程图如图4-3所示。图图4-3开始初始化累加和SUM=0;数据指针i=1;计数器m=nSUM=SUM+Xii=i+1M=m-1M=0?初始化SUM=0;i=1;m=ni=i+1;M=m-1M=0?调开平方子程序V=100

26、%P调用子程序转换为BCD码结束YYNN画出第二张流程图后,还不能马上就进行编程,这时往往需要画第三张流程图,用它来指导编程。第三张流程图以资源分配为策划重点,要为每一个参数、中间结果、各种指针、计数器分配工作单元,定义数据类型和数据结构。在进行这一步工作时,要注意上下左右的关系,本模块的入口参数和出口参数的格式要和全局定义一致,本程序要调用低级子程序时,要和低级子程序发生参数传递,必须协调好它们之间的数据格式。本模块中各个环节之间传递中间结果时,其格式也要协调好。在定点数系统中,中间结果存放格式要仔细设计,避免发生溢出,精度损失。一般中间结果要比原始数据范围大,精度高,才能使最终结果可靠。设

27、数据块首址在3EH和3FH,数据总个数在3DH中。在求平均值的子任务中,用R2、R3、R4存放累加和,用DPTR作数据指针,用R7作计数器,R5和R6作机动单元。这样规划后,第三张流程图的求子程序部分就可以画出来,如图4-4所示。与第二张流程图相比,每一个变量都使具体的,由此来编程就很容易了。对于编程经验比较丰富的人员,有时可以不画第三张程序流程图,在设计好第二张程序流程图后,再编制一张资源分配表,用这张资源分配表对照第二张程序流程图就可以开始进行编程。图图4.4开始初始化R2,R3,R4=0;DPTR=(3F、3EH)R7=(3DH)读取Xi并暂存R5,R6=XiR7=0?(R2,R3,R4

28、)=(R2,R3,R4)+(R5,R6)调整DPTR,指向下一个数据R7=R7-1R7=(3DH)(R3,R4,R5)=(R2,R3,R4)/R73.从程序流程图到程序从程序流程图到程序画好程序流程图后,就可以比较方便地进行编程了。从流程图到程序的过程发生了两个变化,形式上从二维图形变成了一维的程序,内容上从功能描述变成了具体的指令实现。将功能描述变成具体指令实现的过程,一般不会有什么问题,因为算法过程和资源分配已经规划好了。如实现(R2,R3,R4)=(R2,R3,R4)+(R5,R6)的指令串如下:MOV A,R6ADDA,R4MOV R4,AMOV A,R5ADDCA,R3MOV A,R

29、2ADDCA,#0MOV R2,A二、子程序设计二、子程序设计1.结构化的程序设计风格结构化的程序设计风格不仅总体应用程序要设计成模块式结构,子程序也应按结构化设计成具有模块特性:一个输入口和一个输出口,且子程序的内部也设计成由若干个小模块组成。这种模块特性对测试很有利,功能扩展也很方便,要增加新功能,只要增加新模块就能实现,象搭积木一样。模块有如下四种基本结构:(1)顺序结构(DO结构)模块内各个子过程按先后次序排列和执行。如图4-2所示流程图即为顺序结构。(2)选择(分支)结构(IF结构)模块内各个子过程是相互排斥的。按某条件进行选择,被选中的子过程被执行,如图4-6(a)所示。A、B子过

30、程中可以有一个是空过程,如图4-5(a)中的b选择结构就有一边是空过程。IFBAIFAIFCBIFCABYNYNYN(a)(b)(c)图图4-6IF结构结构选择结构有两种常用变形。如果图4-6(a)中的B执行块本身也是选择结构,就变为图4-6(b)所示的多级选择结构,常称为分选(筛选)结构;如果互斥的执行块较多,常用一种“散转”结构,如图4-6(c)所示,通过对某一索引值进行运算,直接选中某一执行块。(3)循环结构(WHILE或FOR结构)WHILE结构模块内只有一个执行块,但在执行前要先对某条件进行检查,当条件成立(为真)时执行该模块,如果条件不成立(为假)则退出该模块。执行后继续检查条件,

31、如果仍然成立,则还要执行,如图4-7所示。FOR结构这种结构和WHILE结构有相似的地方,且可多次执行,但控制次数方法不同,如图4-8所示。这种结构引入一个循环控制变量I,在进入模块时,对I进行初始化,赋以初值I0,然后执行其中的实质程序块(循环体),执行完一遍后控制变量进行调整,增加一个步长量,例如加1,再和预定终值比较,达到或超过终止值就停止循环,退出模块,否则继续执行。NYNYNY 图4-7WHILE结构图4-8FOR结构图4-9REPEAT结构判断执行块判断执行块IIe循环体I=I0I=I+(3)重复结构(重复结构(REPEAT结构)结构)这种结构和WHILE结构类似,模块中也只有一个

32、执行块和一个条件判断过程,但先后次序不同,如图4-9所示。这种结构是先执行后判断,如果某条件尚未成立则反复执行,直到某条件成立为止,故有时又称这种结构叫“直到”结构。2.参数的传递参数的传递子程序在执行过程中,有时要使用一些数据;子程序运行后,产生的一些数据有时要被主程序使用。也就是参数在主程序和子程序之间的传递问题。以主程序传递参数给子程序为例,基本上可分为三种方法:(1)通过存储单元传递。子程序有自己的参数存放单元,如工作寄存器R0R7,主程序将要传递的参数复制到工作寄存器指定的单元中,就可以调用该子程序了。例例4-1用这种方法调用双字节十六进制整数转换成双字节BCD码整数的子程序HTB2

33、,待转换的双字节十六进制整数在R7R6中,转换后三字节BCD码整数在R5R4R3中,主程序和子程序如下:MAIN:MOVR7,#12HMOVR6,#34HACALLHTB2HTB2:CLRAMOVR3,AMOVR4,AMOVR5,AMOVR2,#10HRLCAMOVR7,AHTB3:MOVA,R7RET(2)通过指针传递。主程序对指针(例如R0,R1)进行赋值,使它指向要传递的参数存放的位置,然后调用子程序。子程序通过指针,用间接寻址的方式来使用参数。例例4-2用这种方法调用将RAM数据区清零子程序SUBBT的主程序和子程序为:MAIN:MOVR0,#30H;传递RAM数据区的起始地址MOVR

34、7,#0AH;传递RAM数据区的长度ACALLSUBBTSUBBT:MOVA,#00H;将片内RAM的一组单元清零子程序LOOP:MOVR0,AINCR0DJNZR7,LOOPRET(3)通过堆栈传递参数例例4-3仍以RAM数据区清零为例,假定数据区的起始地址预先存放在70H单元,被清零单元的个数预先存放在71H单元,则主程序为:MAIN:PUSH70H;将起始地址送堆栈PUSH71H;将数据区长度送堆栈ACALLSUBBT;调用清零子程序为了适应这种方法,子程序SUBBT应作如下变动:SUBBT:POPDPH;将返回地址送到DPTR中暂存POPDPLPOPR7;取出数据区长度POPR0;取出

35、数据区首址SUB1:MOVA,#00HLOPP:MOVR0,AINCR0DJNZR7,LOOPPUSHDPL;将返回地址送堆栈PUSHDPHRET(3)通通过过堆堆栈栈传传递递参参数数。通过PUSH,POP指令完成对参数的交换工作。例例4-3仍以RAM数据区清零为例,假定数据区的起始地址预先存放在70H单元,被清零单元的个数预先存放在71H单元,则主程序为:MAIN:PUSH70H;将起始地址送堆栈PUSH71H;将数据区长度送堆栈ACALLSUBBT;调用清零子程序为了适应这种方法,子程序SUBBT应作如下变动:SUBBT:POPDPH;将返回地址送到DPTR中暂存POPDPLPOPR7;取

36、出数据区长度POPR0;取出数据区首址SUB1:MOVA,#00HLOPP:MOVR0,AINCR0DJNZR7,LOOPPUSHDPL;将返回地址送堆栈PUSHDPHRET(4)隐含参数传递方式隐含参数传递方式。主程序直接调用子程序,要使用的参数已隐含在子程序之中了。例如固定延时子程序和特定操作子程序等。在这种参数传递方法中,有的是以立即数方式在指令中给出,有的是以绝对地址方式给出参数存放地址。3子程序设计其它要求子程序的设计要求满足:对主程序具有很好的透明性;各子程序具有相容性,即一个子程序的出口现场与后续子程序的入口条件互相兼容,主程序不需要进行协调工作,只要为每个子程序补充新的操作数就

37、可以了;子程序容错性,即子程序除了能在正常情况下完成指定功能外,还应能处理异常情况,及时发现并妥善处理,从而保证系统不出现重大事故。4.3.2顺序程序设计顺序程序设计顺序结构程序是指一种无分支的直接执行程序,即从第一条指令开始依次执行每一条指令,直到最后一条,程序就算执行完。这种程序虽然比较简单,但也能完成一定的功能,并且往往也是构成复杂程序的基础。例例4-44-4 将十六进制数表示的ASCII代码转换成4位二进制数。我们知道,“字符0”“字符9”的ASCII码值为“30H”“39H”,它 们 与 30H之 差 恰 好 为“00H”“09H”,结果均0则转移到LOP1MOV A,#0FFH;X

38、0则Y=-1SJMP LOP2LOP1:MOV A,#01HLOP2:MOV DATA2,A二、散转程序散转程序是一种并行分支程序,它能根据某种输入或运算结果分别转向各个操作程序。在MCS-51中,提供了散转指令JMPA+DPTR来实现散转。该指令把累加器A的8位无符号数与16位数据指针的内容相加,并把相加的结果装入程序计数器PC,控制程序转向目标地址去执行。1采用转移指令表的散转程序在许多场合下,需要根据标志单元的内容是0,1,2,n分别转向散转操作程序0,1,2,n。这时,可以先用无条件转移指令AJMP或LJMP按序组成一个转移表,将标志单元的内容装入累加器A作为变址值,然后执行指令:JM

39、PA+DPTR实现转移。例例4-6要求根据R7的内容转向各个操作程序。即当R7=0,转向OP0R7=1,转向OP1R7=n,转向OPn程序清单如下:JMPP1:MOVDPTR,#JPTAB;指向转移表MOVA,R7ADDA,R7;修正变址值JNCNADD;判断有否进位INCDPH;有进位加到高字节地址NADD:JMPA+DPTR;转向形成的散转地址JPTAB:AJMPOP0;转移指令表AJMPOP1AJMPOPn2采用地址偏移量表的散转程序采用地址偏移量表的散转程序如果散转点较少,而且所有操作程序处在同一页(256B)内,则可以使用地址偏移量表的方法实现散转。例例4-7要求按R7的内容转向5个

40、操作程序。程序清单如下:JMPP2:MOVA,R7MOVDPTR,#TAB2;指向地址偏移量表MOVCA,A+DPTR;散转点入口地址在A中JMP A+DPTR;转向相应的操作程序入TAB2:DBOP0-TAB2;地址偏移量表DBOP1-TAB2DBOP2-TAB2DBOP3-TAB2DBOP4-TAB2OP0:(操作程序0)OP1:(操作程序1)OP2:(操作程序2)OP3:(操作程序3)OP4:(操作程序4)3采用转向地址表的散转程序采用转向地址表的散转程序前面讨论的采用地址偏移量表的方法,其转向范围局限于一页之内,在使用时,受到较大的限制。若需要转向较大的范围,可以建立一个转向地址表,即

41、将所要转向的二字节地址组成一个表,在散转时,先用查表的方法获得表中的转向地址,并将该地址装入数据指针DPTR中,然后清除累加器A,执行JMPA+DPTR指令,便能转向到相应的操作程序中去。例例4-8要求根据R7的内容转向相应的操作程序中去。设各操作程序的转向地址分别为OP0,OP1,OPn。程序清单如下:JMPP3:MOVDPTR,#TAB3;指向转向地址表MOVA,R7ADDA,R7JNCNADDINCDPHNADD:MOVR3,AMOVCA,A+DPTR;取转向地址高8位XCHA,R3INCAMOVCA,A+DPTR;取转向地址低8位MOVDPL,AMOVDPH,R3CLRAJMPA+DP

42、TRTAB3:DWOP0DWOP1DWOPn4.3.44.3.4循环程序设计循环程序设计 前面讲过,循环有WHILE和FOR两种结构,为了构成循环程序,DJNZ指令是很有用的,特别是在根据计数器的值决定循环是否结束时可以直接使用。但也可以根据其它条件来判断循环结束条件。例例4-94-9 内存中以STRING开始的区域有若干个字符和数字,一般称为一个字符串,最末一个字符为“$”,试统计这些字符数字的数目,结果存入NUM单元。本题可采用WHILE结构,用CJNE指令来和关键字符作比较,比较时要将关键字符用其对应的ASCII码来表示。符号“$”的ASCII码是24H。NUMDATA20HSTRING

43、DATA21HCLRA;A作为计数器,先清零MOVR0,#STRING;首地址送R0LOP:CJNER0,#24H,LOP2;与$比较,不等转移SJMPLOP3;找到$,结束循环LOP2:INCA;计数器加1INCR0;修改地址指针SJMPLOP;循环LOP3:INCA;再计这个$字符MOVNUM,A;存结果4.3.5查表程序设计查表程序设计如果一元单值函数的解析式比较复杂,那么,基于这种函数关系,采用查表法往往使得问题得解决要简单得多。所谓查表法,就是预先将满足一定精度要求的表示变量x与函数y=f(x)值之间关系的一张表求出,然后把这张表存于单片机的程序存储器中。这时自变量值为单元地址,相应

44、的函数值为该地址单元中的内容。而查表就是根据给定的自变量x,在表格中查找y,使y=f(x)。在MCS-51中,查表时的数据表格是存放在程序ROM而不是数据RAM中。相应地,用于查表的指令有两条:MOVCA,A+DPTRMOVCA,A+PC使用DPTR作为基地址查表比较简单,可通过三步操作来完成:(1)将所查表格的首地址存入DPTR数据指针寄存器;(2)将所查表格的项数(即在表中的位置是第几项)送累加器A;(3)执行查表指令MOVCA,A+DPTR进行读数,查表结果送回累加器A。若使用PC作为基地址查表,则操作有所不同,也可分为三步:(1)将所查表格的项数送累加器A,在MOVCA,A+PC指令之

45、前先写上一条ADDA,#data指令,data的值待定;(2)计算从MOVCA,A+PC指令执行后的地址到所查表的首地址之间的距离(以字节数表示),用这个计算结果取代加法指令中的data,作为A的调整量;(3)执行查表指令MOVCA,A+PC进行查表,查表结果送回累加器A。例例4-10在一个温度测量装置中,测出的电压与温度为非线性关系。设测得电压值为x,用10位二进制数表示(占2B)。现要求采用查表法实现线性化处理。这个问题的解决办法是,先通过实验测出与1024(210)个电压值相对应的温度值,并按电压由小到大的顺序构造一个表,表中存放温度值y(一个定字长数,高字节在前),则:存放温度值y的单

46、元地址=表首址+(x*2)设测得电压值x已存放在20H,21H单元中(高字节在20H),查表得到的温度值y存放在22H,23H(高字节在22H单元)。查表程序如下:STB1:MOVDPTR,#TAB;首址送DPTRMOVA,21H;(20H)(21H)乘2CLRCRLCAMOV21H,AMOVA,20HRLCAMOV20H,AMOVA,21H;表首址+(x*2)ADDA,DPLMOVDPL,AMOVA,20HADDCA,DPHMOVDPH,ACLRAMOVCA,A+PC;查表得温度值高位字节MOV22H,A;存放高字节INCDPTR;指向温度低位字节CLRAMOVCA,A+PC;查表得温度值高

47、低字节MOV23H,A;存放低字节RETTAB:DW;温度值表4.4综合程序应用编程综合程序应用编程单片机常用于测控领域,其中智能仪表是最典型的单片机应用系统。它具有典型的硬件电路和软件结构。因此,智能仪表系统最有可能实现硬件的标准化和软件的模块化。本节以智能仪表的应用软件设计为例说明综合程序应用编程的问题。4.4.1智能仪表的典型软件结构智能仪表的典型软件结构智能仪表是一种较完整的单片机应用系统。一般硬件电路除基本扩展部分外,都配置有采集电路、显示器、按键、打印机等。相应的软件有采集控制、数据处理、显示、结果打印等。图4-10是智能仪表的一种典型软件结构。按其功能可分为三部分,即初始化监视程

48、序、键功能散转程序和系统控制程序。图4-10智能仪表典型软件结构图4-11初始化监视程序正常?系统测试初始化提示符显示键盘扫描键按下?初始化监视程序上电复位键功能散转程序系统控制程序4.5C51程序设计简介程序设计简介当单片机用于一般商用和民用场合,如作为掌上电脑微处理器时,对实时性要求不高,但对编程的简单和使用的方便性提出了较高要求,这时采用高级语言来设计单片机应用程序就显得较合适。在这里介绍一种目前流行的MCS-51单片机高级语言C51。4.5.1C51程序结构程序结构C51程序结构与一般C语言没有什么差别。一个C51程序大体上是一个函数定义的集合,在这个集合中有且仅有一个名为main的函

49、数(主函数)。主函数是程序的入口,主函数中的所有语句执行完毕,则程序执行结束。在这里,其它函数称为子函数。下面所示一个C51程序的大体结构:#include/*头文件(包含库函数)*/#defineuintunsignedint/*数据类型符号定义*/#defineucharunsignedcharuncharbdataFLAG/*变量,数组等定义*/voidinport(ucharstate)/*子函数*/*相关语句*/main()/*主函数*/*相关语句*/inport()/*子函数调用*/函数定义由类型、函数名、参数表和函数体四部分组成。函数名是一个标识符,标识符都是大小可区别的,最长为

50、255个字符。参数表是用圆括号括起来的若干参数,项项之间用逗号隔开。函数体是用大括号括起来的若干C语句,语句与语句之间用分号隔开,最后一个语句一般是return语句(在主函数中可以省略)。每一个函数都返回一个值,该值由return语句中的表达式指定(省略时为零)。函数的类型就是返回值的类型。函数类型(除整型外)均需在函数名前加以指定。C51函数的一般格式为函数的一般格式为:类型函数名(参数表)参数说明;数据说明部分;执行语句部分;一一个个函函数数在在程程序序中中可可以以三三种种形形态态出出现现:函数定义、函数调用和函数说明。函数定义相当于汇编中的一般子程序。函数调用相当于调用子程序的CALL语

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 生活常识

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁