版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第4章章 程序设计程序设计 教学目标教学目标 介绍单片机汇编程序设计方法介绍单片机汇编程序设计方法 介绍单片机汇编程序常用结构及设计方法介绍单片机汇编程序常用结构及设计方法 介绍介绍典型智能仪表单片机系统应用软件设计典型智能仪表单片机系统应用软件设计 介绍介绍目前流行的目前流行的MCS-51单片机高级语言单片机高级语言C51 学习要求学习要求 熟悉单片机编程的步骤、方法和技巧熟悉单片机编程的步骤、方法和技巧 掌握单片机汇编程序的常用结构及设计方法掌握单片机汇编程序的常用结构及设计方法 掌握典型汇编语言应用程序的编制掌握典型汇编语言应用程序的编制 了解单片机高级程序设计语言了解单片机高级程序设
2、计语言C51 单片机系统设计由硬件设计和软件单片机系统设计由硬件设计和软件 设计两部分组成,设计两部分组成,后者就是设计程 序、编制表格,以指挥单片机完成 用户交付的任务。本章介绍MCS-51 单片机汇编语言程序设计的基本步 骤、方法和技巧,并在最后简单地 介绍了C51高级程序设计。 4.1编程的步骤、方法和技巧编程的步骤、方法和技巧 单片机常用于工业测控装置和智能仪表等, 这些应用场所往往对实时性提出了要求。使用 汇编语言设计程序,虽然比高级语言烦琐,但 它能最充分地发挥指令系统的功能与效率,获 得最简练的目标程序,能满足实时性要求。用 汇编语言设计单片机应用程序往往要经历以下 几个步骤:
3、(1)软件任务分析; (2)数据类型和数据结构规划; (3)资源分配; (4)编程与调试。 4.1.1软件任务分析软件任务分析 软件任务分析是为软件设计作一个总体规 划。从功能来看,软件可分为两大类:一类是 执行软件,它能完成各种实质性的功能,如测 量、计算、显示、打印、输出控制和通信等; 另一类是监控软件,它是专门用来协调各执行 模块和操作者的关系,在系统软件中充当组织 调度角色的软件。这两类软件的设计方法各有 特色,执行软件的设计偏重算法效率,与硬件 关系密切。监控软件着眼全局,逻辑严密。 软件任务分析时,应将各执行模块 一一列出,并为每一个执行模块进行功 能定义和接口定义(输入、输出定义
4、)。在 为各执行模块进行定义时,将要牵涉到 的数据结构和数据类型的问题也一并规 划好。 各执行模块规划好后,就可以规划 监控程序了。首先根据系统功能和键盘 设置选择一种最合适的监控程序结构。 相对来讲,执行模块任务明确单纯,比 较容易编程。而监控程序较易出问题。 任务分析的另一个内容是如何安排监控软 件和各执行模块。整个系统软件可分为后台程 序和前台程序。后台程序指主程序及其调用的 子程序,这类程序对实时性要求不是很高,延 误几十毫秒甚至几百毫秒也没关系,故通常将 监控程序(键盘管理程序)、显示程序和打印程 序等与操作者打交道的程序放在后台程序中来 执行。而前台程序安排一些实时性要求较高的 内
5、容,如定时系统和外部中断。在一些特殊场 合,也可以将全部程序均安排在前台,后台为 踏步等待循环或睡眠状态。 4.1.2数据类型和数据结构规划数据类型和数据结构规划 前面的软件任务分析只是一个粗糙的分析 和大体上的安排,还不能开始编程。 为了避免 系统中各个执行模块之间的脱节现象,就必须 严格规定好各个接口条件,即各接口参数的数 据结构和数据类型。 从数据类型上来分类,可分为逻辑型和数 值型,但通常将逻辑型数据归到软件标志中去 考虑。而将数据类型分类理解为数值类型分类。 数值类型可分为定点数和浮点数。 如果一个参数的变化范围有限,就可用定 点数来表示,以简化程序设计和加快运行速度; 当参数的变化
6、范围太宽时,只好采用浮点数来 表示。 如果某参数是一系列有序数据的集合,如 采样信号系列,则不光有数据类型问题,还有 一个数据存放格式问题,即数据结构问题。在 单片机应用系统中,数据结构比较简单,大多 采用线性结构,这样有利于数据处理。由于受 RAM空间的限制,队列结构广泛采用环行队列 结构,为此应规划好两样东西:队列区域和队 尾(首)指针,并计算出总共需要的RAM字节数。 对于数组,一般采用顺序存放的格式。这样就 可以用简单的下标运算来访问数组中的任何一 个元素。 4.1.3资源分配资源分配 完成数据类型和数据结构的规划后,便可开始分 配系统的资源了。在微机测控系统中,往往需要定时 检测某个
7、物理参数,或按一定的时间间隔来进行某种 控制等。这种定时的获得常采用定时/计数器,它还可 以对某种事件进行计数,然后根据计数结果来进行控 制;单片机在及时处理实时测、控中的许多随机的参 数和信息、对外界异步事件包括故障的处理常使用中 断,在任务分析时一般要将定时/计数器和中断源等资 源分配好。ROM资源用来存放程序和表格,这也是明 显的。系统资源ROM、RAM、定时/计数器、中断源 等。因此,资源分配的主要工作是RAM资源的分配。 片外RAM的容量比片内RAM大,通常用来存放大批量 的数据,如采样数据系列。真正需要认真考虑的是片 内RAM的分配。 片内RAM指00H7FH单元。这128个字节
8、的功能并不完全相同,分配时应注意充分发挥 各自的特长,做到物尽其用。 00H1FH这32个字节可以作为工作寄存器, 其中00H0FH用来作为0区、1区工作寄存器。 在一般的应用系统中,后台程序用0区工作寄 存器,前台程序用1区工作寄存器。如果有高 级中断,则高级中断可用2区工作寄存器 (10H17H)。如果前台程序中不使用工作寄存 器,则系统只需0区工作寄存器。未作为工作 寄存器的其它单元便可以转为其它目的使用了。 系统上电复位时,自动定义0区为工作寄存器, 1区为堆栈,并向2区、3区延伸。如果前台程 序要用1区、2区作为工作寄存器,就应将堆栈 空间重新规划 。 在工作寄存器的8个单元中,R0
9、和R1具有 指针功能,是编程的重要角色,应充分发挥其 作用,尽量避免用来做其它事情。 20H2FH这16个字节具有位寻址功能,用 来存放各种软件标志、逻辑变量、位输入信息、 位输出信息副本、状态变量、逻辑运算的中间 结果等。当这些项目安排好后,保留一两个字 节备用,剩下的单元才可改作其它用途。 30H7FH为一般通用寄存器,只能存入整 字节信息。通常用来存放各种参数、指针、中 间结果,或用作数据缓冲区。也常将堆栈安排 在片内RAM的高端,如68H7FH。 如果将系统的各种开销安排后,所剩单元 很少,这往往不是好的兆头。应该留有足够的 余地,因为现在还处于规划阶段,随着软件设 计的发展进程,几乎
10、都会出现新的资源要求。 如果在规划阶段资源已经很紧张,建议修改硬 件设计,增加RAM资源。 RAM资源规划好后,应列出一张RAM资源 的详细分配清单,作为编程依据。 4.1.4编程与调试编程与调试 上述各项准备工作都完成后,就可以开始编程了。 软件设计有两种方法:一种是自上而下,逐步细化; 一种是自下而上,先设计出每一个具体的模块(子程序), 然后再慢慢扩大,最后组成一个系统。两种方法各有 优缺点。 单片机由于本身没有开发能力,故编程均在各种 类型的开发系统上进行。基本过程是相同的:用编辑 软件编辑出源程序,再用编译软件生成目标代码,如 果源程序中有语法错误则返回编辑过程,修改源程序 后再继续
11、编译,直到通过这一关。然后对程序进行测 试,纠正测试中发现的错误。接着就在开发系统上仿 真运行,试运行中将会发现不少设计错误(不是语法错 误),再从头修改源程序,如此反复直到基本成功,就 可以投入实际环境中使用。 4.24.2汇编语言源程序的编辑和汇编汇编语言源程序的编辑和汇编 用助记符和标号地址编写的程序称 为汇编语言源程序;而将助记符翻译成机 器码以及将标号地址换算成实际地址的 工作都由计算机通过一种称为汇编程序 的软件完成,这种翻译和换算的过程一 般就称为汇编。 4.2.1汇编语言源程序的格式汇编语言源程序的格式 一般来讲,汇编语言源程序由四部分组成,即标 号、操作码、操作数和注释。每两
12、个部分之间要用分 隔符隔开,而每一部分内部不采用分割符。可以采用 的分割符有:空格“ ”、冒号“:”、分号“;”, 空格的数目可以不止一个。 汇编语言源程序的一般形式为: 标号:操作码 操作数 ;注释 方括号 在实际程序中并不书写,也不输入到计算机里, 只是表示方括号内的项是任选项,此项可有可无,若 不需要时,在某一行可以不包括此项。故对每一行源 程序来说,只有操作码是必不可少的,其余三部分都 可视情况而定。 汇编程序只处理分号“;”以前的 字符,对于注释部分,计算机在汇编时 不予处理。注释部分便于程序的使用者 更好地理解程序的功能,有助于程序的 交流使用。软件工作者从一开始就要养 成写好注释
13、的良好习惯。 对于有些指令,操作数不止一个, 有两个甚至三个,在输入计算机时,各 操作数之间要用逗号作分割符。 一、标号一、标号 标号由标号由8个或个或8个以下的字母数字构成,第个以下的字母数字构成,第 一个必须是字母。一个必须是字母。另外还允许使用一个下横线 符号“ ”。其它的符号都不允许在标号中使 用。此外,系统中保留使用的字符或字符组不 能用作标号,以免引起混淆。如各种特殊功能 寄存器名、各个位地址记忆符、各种伪指令等 都不能用作标号。 以下是一些合法的标号:A1,LOOP等。 以下的字符串不能用作标号:4G,F-G, DB,EQU(后两种为保留字)。 标号不是每一行都必须要有,而只是在
14、需 要时才使用。 二、操作数二、操作数 对于立即数#data来说,使用时,一般都在 #后面跟一个具体的数。这个数可以是二进制 数,应以字母“B”作为结束,如#10010011B; 也可以是十六进制数,则以字母“H”结尾,如 88H,但若最高位为AF之中的字母,则前面 还要加一个数字“0”,如#0ABH。如果这个0 忘了加上,汇编程序将认为所写的是一个编号。 如果数字的最后没有结束字母,则认为是十进 制数,如#10。 立即数的data也可以用定义过的标号来代 替,这种定义要用到伪指令EQU等。 对于直接地址direct来说,在实际使用时, 也可以有多种选择: 1.二进制数,十进制数或十六进制数,
15、如:MOV A,30H等; 2.标号地址,如:MOV A,SUM等,SUM应该在 程序中某处加以定义; 3.带加减的表达式,如:MOV A,SUM+9,SUM 为已定义的符号地址; 4.特殊功能寄存器名,如:MOV A,SP等。 对于偏移量rel,除了可以采用上面提到的各种数 值、标号地址以及表达式之外,还可以采用一个专门 的符号“$”,它表示相对转移指令所在的地址,例如: LJMP $ 这条指令实际上是一条自身跳转的死循环。在实 际 编 程 时 , 凡 是 指 令 中 用 到 地 址 的 地 方 (rel,addr11,addr16)都用标号地址代替实际地址,而将复 杂的地址运算交给汇编程序
16、完成。 4.2.2伪指令伪指令 每种汇编语言都会定义若干伪指令, 用来对汇编过程进行某种控制,或对符 号、标号赋值。伪指令和指令是完全不 同的。在汇编过程中,由于伪指令并不 执行可执行的目的代码,因而大部分伪 指令甚至不会影响存储器中的内容。对 不同版本的汇编语言,伪指令的符号和 含义可能不同,但基本的用法是相似的。 下面就介绍一些常用的伪指令。 一、一、ORG(汇编起始命令汇编起始命令) 其功能是规定下面的目标程序的起始地址,指令 格式为: 标号:ORG addr16 其中括号内是任选项,可以没有,例如: ORG 1000H LAB:MOV A,#3H 即,规定了标号LAB所在的起始地址为1
17、000H, 第一条指令就从1000H开始存放。 一般在一个汇编语言源程序的开始,都用一条 ORG伪指令来规定程序存放的起始位置,故称 为汇编起始命令。 二、二、END(汇编结束命令)(汇编结束命令) END是汇编语言源程序的结束标志,在END以后 所写的指令,汇编程序都不予处理。一个源程序只能 有一个END命令。在同时包含有主程序和子程序的系 统中,也只能有一个END命令,并存放到所有指令的 最后,否则,就有一部分指令不能被汇编。其格式为: 标号:END 三、三、EQU(等值命令)(等值命令) 其功能是将一个数或者特定的汇编符号赋予规定 的符号名称,其格式为: 字符名称 EQU数或汇编符号 例
18、如: INPEQUP1 MOV A,INP 这里将INP等值为汇编符号P1,在指令中INP就可以代 替P1来使用。 四、四、DATA(数据地址赋值命令)(数据地址赋值命令) 其功能是将数据地址或代码地址赋予规定的字符 名称,其格式为: 字符名称DATA表达式 DATA伪指令的功能和EQU有些相似,使用时要注意 它们的差别: (1)EQU伪指令定义的符号必须先定义后使用,而 DATA伪指令的符号可以先使用后定义; (2)用EQU伪指令可以把一个汇编符号赋给一个字符 名称,而DATA伪指令则不能。 (3)DATA伪指令可将一个表达式的值赋给一个字符 名称,所定义的字符名称也可以出现在表达式中,而
19、用EQU定义的字符则不能这样使用。 (4)DATA伪指令常在程序中用来定义数据地址。 五、五、DB(定义字节指令)(定义字节指令) 其功能是从规定的地址单元开始,定义若干个8位内 存单元的内容,其格式为: 标号:DB8位数据表 这个伪指令是在程序存储器的某一部分存入一组规 定好的8位二进制数,或者是将一个数据表格存入程序 存储器。这个伪指令在汇编后,将影响程序存储器的 内容。例如: TAB1: DB3FH,55,8,C TAB2: DB10100B 设TAB1的对应地址为2000H,则以上伪指令经汇编 以后,将对2000H开始的若干内存单元赋值: (2000H)=3FH(2001H)=37H
20、(2002H)=38H(2003H)=43H (2004H)=14H 六、六、DW(定义字命令)(定义字命令) 其功能是从指定地址开始,定义若干个16位数据, 其格式为: 标号:DW16位数据表 每个16位数据要占ROM的两个单元,在MCS-51系 统中,16位二进制数的高8位先存入低地址字节,低8 位后存入高地址字节。这和MCS-51指令中的16位数据 存放的方式一致。 例如: ORG1000H DW 3964H,6H,20 汇编以后结果为: (1000H)=39H(1001H)=64H(1002H)=00H (1003H)=6H (1004H)=00H(1005H)=14H 七、七、BIT
21、(位地址符号命令)(位地址符号命令) 其功能是将位地址赋予所规定的字符名称, 其格式为: 字符名称 BIT位地址 例如: RECORD BITP2.2 PLAYBITP2.3 这样就把两位位地址分别赋给两个变量 RECORD和PLAY,在编程中它们可当作位地 址来使用。但不是所有的MCS-51汇编程序都 有这条伪指令。当不具备BIT命令时,可以使 用EQU命令来定义位地址变量,但这时所赋的 值应该是具体的位地址,例如P1.0就要具体地 用90H来代替。 4.2.3源程序的编辑和汇编源程序的编辑和汇编 源程序的编辑可以使用任何可编辑和存储文本格 式的文件编辑器,如Windows操作系统提供的写字
22、板 (Wordpad)和笔记本(Notebook)、Word文字处理器和各 种单片机集成开发软件如MEDWIN、MPLAB、WAVE 等。 用文本文件编辑器编辑和汇编单片机程序的过程如 下: (1)用文件编辑器编辑汇编语言源程序,它的扩展 名为.ASM; (2)经检查无明显的语法错误后,再采用单片机汇 编程序ASM51进行汇编,产生扩展名为.LST的列表输 出文件和扩展名为.HEX的目标代码文件; 列表输出文件:包含源程序语句所汇编成的代码,以及有 关的地址、语句和符号表等; 目标代码文件:包含源程序语句所汇编成的代码,不包含 任何符号信息或助记符。 用单片机集成开发软件编辑和汇编单片机程序的
23、过程如下: (1)在集成开发环境中编辑器编辑汇编语言源程序,它的扩 展名为.ASM; (2)在集成开发环境中设置编译所采用的正确汇编程序(一般 为ASM51)后,用鼠标点击编译工具条或菜单可直接进行汇编。若 源程序无语法错误,会产生扩展名为.LST的列表输出文件和扩展 名为.BIN(或.HEX)的目标代码文件;若源程序有语法错误,一般 不会产生列表输出文件和目标代码文件,但会弹出一个信息窗口, 指示出错位置和错误类型。用鼠标点击出错指示信息,会直接跳 到源程序出错语句,修改正确后,再一次编译,则会弹出信息窗 口指示汇编成功,源程序无语法错误,并产生相应的目标代码文 件和列表输出文件。 4.34
24、.3汇编语言程序设计汇编语言程序设计 4.3.14.3.1程序流程图设计及子程序设计程序流程图设计及子程序设计 一、程序流程图一、程序流程图 1 概述概述 编制程序的正确做法是先画程序流程图,再开始 编程,而不是编完程序后再补画程序流程图。程序流 程图在“高级语言程序设计”相关课程中大家已熟悉, 它是一种以框图形式表示程序结构的。画程序流程图 的过程是进行程序的逻辑设计过程,这中间的任何错 误或忽视将会导致程序出错或可靠性下降。可以认为 真正的程序设计过程是流程图设计,而上机编程是将 设计好的程序流程图转换成程序设计语言而已。 2. 程序流程图的画法程序流程图的画法 正确的流程图画法是先粗后细
25、、一步一个脚印, 只考虑逻辑结构和算法,不考虑或少考虑具体指令。 这样画流程图就可以集中精力考虑程序的结构,从根 本上保证程序的合理性和可靠性,剩下来的任务只是 进行指令代换,这时只要消除语法错误,一般就能顺 利编出源程序,并且很少大返工。下面用一个例子来 说明流程图的画法:有一数据采集系统,将采集到的 一批数据存放在片外RAM中,数据类型为双字节十六 进制整数,存放格式为顺序存放,高字节在前(低地 址),低字节在后(高地址),数据块的首址已知, 数据总个数(不超过256)也已知。现要设计一个程序, 计算下列公式的值: 式中,n为数据总个数,Xi为某个数据,为这n个 数据的平均值。要求最后结果
26、以BCD码百分数 表示,并精确到0.1%。 第一步第一步,先进行最原始的规划,画第一张 程序流程图,如图4-2所示。在画第一张程序流 程图时,将总任务分解成若干个子任务,安排 好它们之间的相互关系,暂不管各个子任务如 何完成。这一步看起来简单,但千万不能出错, 这一步错误是属于宏观决策错误,有可能造成 整体推倒重来。 %100)( 1 11 2 1 n i i XX nX V 图4-2 开始 求X 求 求 开平方 求V 结束 n i i XX 1 2 1 1 n 第二步第二步,将第一张流程图的各个子 任务进行细化。决定每个子任务采用哪 种算法,而暂不考虑如何为数据指针、 计数器、中间结果配置存
27、放单元等具体 问题。由于内容比第一张详细,如果全 图画在一起不方便,可以分开画,但要 注意各分图之间的连接关系。第二张流 程图如图4-3所示。 图图4-3 开始 初始化累加和SUM=0; 数据指针i=1;计数器 m=n SUM=SUM+Xi i=i+1 M=m-1 M=0? 初始化SUM=0; i=1;m=n i=i+1;M=m-1 M=0? 调开平方子程序 V=100%P 调用子程序 转换为BCD码 结束 YY NN US i XXi ii i 2 2 i SUMSUM XSP/ nSUMX/ )1/(nSUMX 画出第二张流程图后,还不能马上就进行编程, 这时往往需要画第三张流程图,用它来
28、指导编程。第 三张流程图以资源分配为策划重点,要为每一个参数、 中间结果、各种指针、计数器分配工作单元,定义数 据类型和数据结构。在进行这一步工作时,要注意上 下左右的关系,本模块的入口参数和出口参数的格式 要和全局定义一致,本程序要调用低级子程序时,要 和低级 子程序发生参数传递,必须协调好它们之间的数 据格式。本模块中各个环节之间传递中间结果时,其 格式也要协调好。在定点数系统中,中间结果存放格 式要仔细设计,避免发生溢出,精度损失。一般中间 结果要比原始数据范围大,精度高,才能使最终结果 可靠。 设数据块首址在3EH和3FH,数据总个数 在3DH中。在求平均值的子任务中,用R2、R3、
29、R4存放累加和,用DPTR作数据指针,用R7作 计数器,R5和R6作机动单元。这样规划后,第 三张流程图的求子程序部分就可以画出来,如 图4-4所示。与第二张流程图相比,每一个变量 都使具体的,由此来编程就很容易了。 对于编程经验比较丰富的人员,有时可以 不画第三张程序流程图,在设计好第二张程序 流程图后,再编制一张资源分配表,用这张资 源分配表对照第二张程序流程图就可以开始进 行编程。 图图4.4 开始 初始化R2,R3,R4 =0;DPTR=(3F、3EH )R7=(3DH) 读取Xi并暂存R5,R6=Xi R7=0? (R2,R3,R4)= (R2, R3,R4)+(R5,R6) 调整D
30、PTR,指向下一个数据 R7= R7-1 R7=(3DH) (R3,R4,R5)=(R2,R3,R4)/R7 3.从程序流程图到程序从程序流程图到程序 画好程序流程图后,就可以比较方便地进行编程 了。从流程图到程序的过程发生了两个变化,形式上 从二维图形变成了一维的程序,内容上从功能描述变 成了具体的指令实现。 将功能描述变成具体指令实现的过程,一般不会 有什么问题,因为算法过程和资源分配已经规划好了。 如实现(R2,R3,R4)= (R2, R3,R4)+(R5,R6)的指令串如下: MOV A,R6 ADDA,R4 MOV R4,A MOV A,R5 ADDCA,R3 MOV A,R2 A
31、DDCA,#0 MOV R2,A 二、子程序设计二、子程序设计 1.结构化的程序设计风格结构化的程序设计风格 不仅总体应用程序要设计成模块式结构,子程序 也应按结构化设计成具有模块特性:一个输入口和一 个输出口,且子程序的内部也设计成由若干个小模块 组成。这种模块特性对测试很有利,功能扩展也很方 便,要增加新功能,只要增加新模块就能实现,象搭 积木一样。模块有如下四种基本结构: (1) 顺序结构(DO结构) 模块内各个子过程按先后次序排列和执行。如图4-2所示 流程图即为顺序结构。 (2) 选择(分支)结构(IF结构) 模块内各个子过程是相互排斥的。按某条件进行选择, 被选中的子过程被执行,如
32、图4-6(a)所示。A、B子过 程中可以有一个是空过程,如图4-5(a)中的b选择结构 就有一边是空过程。 IF BA IF A IF CB IF CAB Y N Y N Y N (a) (b) (c) 图图4-6 IF结构结构 选择结构有两种常用变形。如果图4-6(a)中的B执行块本身也 是选择结构,就变为图4-6(b)所示的多级选择结构,常称为分选 (筛选)结构;如果互斥的执行块较多,常用一种“散转”结构, 如图4-6(c)所示,通过对某一索引值进行运算,直接选中某一执行 块。 (3)循环结构(WHILE或FOR结构) WHILE结构 模块内只有一个执行块,但在执行前要先对某条件进行检查,
33、 当条件成立(为真)时执行该模块,如果条件不成立(为假)则 退出该模块。执行后继续检查条件,如果仍然成立,则还要执行, 如图4-7所示。 FOR结构 这种结构和WHILE结构有相似的地方,且可多次执行,但控制 次数方法不同,如图4-8所示。这种结构引入一个循环控制变量I, 在进入模块时,对I进行初始化,赋以初值I0,然后执行其中的实 质程序块(循环体),执行完一遍后控制变量进行调整,增加一 个步长量,例如加1,再和预定终值比较,达到或超过终止值就停 止循环,退出模块,否则继续执行。 N Y N Y N Y 图4-7 WHILE 结构 图4-8 FOR结构 图4-9 REPEAT结构 判断 执行
34、块判断 执行块 IIe 循环体 I=I0 I=I+ (3)重复结构(重复结构(REPEAT结构)结构) 这种结构和WHILE结构类似,模块中也只有一个 执行块和一个条件判断过程,但先后次序不同,如图 4-9所示。这种结构是先执行后判断,如果某条件尚未 成立则反复执行,直到某条件成立为止,故有时又称 这种结构叫“直到”结构。 2.参数的传递参数的传递 子程序在执行过程中,有时要使用一些数据;子 程序运行后,产生的一些数据有时要被主程序使用。 也就是参数在主程序和子程序之间的传递问题。以主 程序传递参数给子程序为例,基本上可分为三种方法: (1)通过存储单元传递。子程序有自己的参数存放 单元,如工
35、作寄存器R0R7,主程序将要传递的参数 复制到工作寄存器指定的单元中,就可以调用该子程 序了。 例例4-1 用这种方法调用双字节十六进制整数转换成双字节 BCD码整数的子程序HTB2,待转换的双字节十六进制 整数在R7R6中,转换后三字节BCD码整数在R5R4R3 中,主程序和子程序如下: MAIN: MOV R7,#12H MOV R6,#34H ACALL HTB2 HTB2:CLR A MOV R3,A MOV R4,A MOV R5,A MOV R2,#10H RLC A MOV R7,A HTB3:MOV A,R7 RET (2)通过指针传递。主程序对指针(例如R0,R1) 进行赋值
36、,使它指向要传递的参数存放的位置,然后 调用子程序。子程序通过指针,用间接寻址的方式来 使用参数。 例例4-2 用这种方法调用将RAM数据区清零子程序SUBBT的主程序和子程 序为: MAIN: MOV R0,#30H;传递RAM数据区的起始地址 MOV R7,#0AH;传递RAM数据区的长度 ACALL SUBBT SUBBT:MOV A,#00H;将片内RAM的一组单元清零子程序 LOOP: MOV R0,A INC R0 DJNZ R7,LOOP RET (3)通过堆栈传递参数 例例4-3 仍以RAM数据区清零为例,假定数据区的起始地址预先存放在70H单 元,被清零单元的个数预先存放在7
37、1H单元,则主程序为: MAIN: PUSH 70H;将起始地址送堆栈 PUSH 71H;将数据区长度送堆栈 ACALL SUBBT;调用清零子程序 为了适应这种方法,子程序SUBBT应作如下变动: SUBBT:POP DPH;将返回地址送到DPTR中暂存 POP DPL POP R7;取出数据区长度 POP R0;取出数据区首址 SUB1: MOV A,#00H LOPP: MOV R0,A INC R0 DJNZ R7,LOOP PUSH DPL;将返回地址送堆栈 PUSH DPH RET (3)通过堆栈传递参数通过堆栈传递参数。通过PUSH,POP指令完成对参数的 交换工作。 例例4-3
38、仍以RAM数据区清零为例,假定数据区的起始地址预先存放在 70H单元,被清零单元的个数预先存放在71H单元,则主程序为: MAIN: PUSH 70H;将起始地址送堆栈 PUSH 71H;将数据区长度送堆栈 ACALL SUBBT;调用清零子程序 为了适应这种方法,子程序SUBBT应作如下变动: SUBBT:POP DPH ;将返回地址送到DPTR中暂存 POP DPL POP R7;取出数据区长度 POP R0;取出数据区首址 SUB1: MOV A,#00H LOPP: MOV R0,A INC R0 DJNZ R7,LOOP PUSH DPL;将返回地址送堆栈 PUSH DPH RET
39、(4)隐含参数传递方式隐含参数传递方式。主程序直接调用子程序, 要使用的参数已隐含在子程序之中了。例如固定延时 子程序和特定操作子程序等。在这种参数传递方法中, 有的是以立即数方式在指令中给出,有的是以绝对地 址方式给出参数存放地址。 3子程序设计其它要求 子程序的设计要求满足:对主程序具有很好的透 明性;各子程序具有相容性,即一个子程序的出口现 场与后续子程序的入口条件互相兼容,主程序不需要 进行协调工作,只要为每个子程序补充新的操作数就 可以了;子程序容错性,即子程序除了能在正常情况 下完成指定功能外,还应能处理异常情况,及时发现 并妥善处理,从而保证系统不出现重大事故。 4.3.2 顺序
40、程序设计顺序程序设计 顺序结构程序是指一种无分支的直接执行程序, 即从第一条指令开始依次执行每一条指令,直到最后 一条,程序就算执行完。这种程序虽然比较简单,但 也能完成一定的功能,并且往往也是构成复杂程序的 基础。 例例4-44-4 将十六进制数表示的ASCII代码转 换成4位二进制数。 我们知道,“字符0”“字符9”的ASCII码值为 “30H”“39H”,它们与30H之差恰好为“00H”“09H”, 结果均0则转移到LOP1 MOV A,#0FFH;X0则Y=-1 SJMP LOP2 LOP1:MOV A,#01H LOP2:MOV DATA2,A 01 00 01 X X X Y ,
41、, , 二、散转程序 散转程序是一种并行分支程序,它能根据某种输 入或运算结果分别转向各个操作程序。在MCS-51中, 提供了散转指令JMP A+DPTR来实现散转。该指令 把累加器A的8位无符号数与16位数据指针的内容相加, 并把相加的结果装入程序计数器PC,控制程序转向目 标地址去执行。 1采用转移指令表的散转程序 在许多场合下,需要根据标志单元的内容是0,1, 2,n分别转向散转操作程序0,1,2,n。这 时,可以先用无条件转移指令AJMP或LJMP按序组成 一个转移表,将标志单元的内容装入累加器A作为变址 值,然后执行指令: JMP A+DPTR 实现转移。 例例4-6 要求根据R7的
42、内容转向各个操作程序。即当 R7=0,转向OP0 R7=1,转向OP1 R7=n,转向OPn 程序清单如下: JMPP1:MOV DPTR,#JPTAB;指向转移表 MOV A,R7 ADD A,R7;修正变址值 JNC NADD;判断有否进位 INC DPH;有进位加到高字节地址 NADD:JMP A+DPTR;转向形成的散转地址 JPTAB:AJMP OP0;转移指令表 AJMP OP1 AJMP OPn 2采用地址偏移量表的散转程序采用地址偏移量表的散转程序 如果散转点较少,而且所有操作程序处在同一页(256B)内, 则可以使用地址偏移量表的方法实现散转。 例例4-7 要求按R7的内容转
43、向5个操作程序。程序清单如下: JMPP2:MOV A,R7 MOV DPTR,#TAB2;指向地址偏移量表 MOVC A,A+DPTR;散转点入口地址在A中 JMP A+DPTR;转向相应的操作程序入 TAB2:DB OP0-TAB2;地址偏移量表 DB OP1-TAB2 DB OP2-TAB2 DB OP3-TAB2 DB OP4-TAB2 OP0: (操作程序0) OP1: (操作程序1) OP2: (操作程序2) OP3: (操作程序3) OP4: (操作程序4) 3采用转向地址表的散转程序采用转向地址表的散转程序 前面讨论的采用地址偏移量表的方法,其转向范围局限于一页之内,在使 用时
44、,受到较大的限制。若需要转向较大的范围,可以建立一个转向地址表,即 将所要转向的二字节地址组成一个表,在散转时,先用查表的方法获得表中的转 向地址,并将该地址装入数据指针DPTR中,然后清除累加器A,执行JMP A+DPTR指令,便能转向到相应的操作程序中去。 例例4-8 要求根据R7的内容转向相应的操作程序中去。设各操作程序的转向地址分别为OP0, OP1,OPn。 程序清单如下: JMPP3:MOV DPTR,#TAB3;指向转向地址表 MOV A,R7 ADD A,R7 JNC NADD INC DPH NADD:MOV R3,A MOVC A,A+DPTR;取转向地址高8位 XCH A
45、,R3 INC A MOVC A,A+DPTR;取转向地址低8位 MOV DPL,A MOV DPH,R3 CLR A JMP A+DPTR TAB3:DW OP0 DW OP1 DW OPn 4.3.44.3.4循环程序设计循环程序设计 前面讲过,循环有WHILE和FOR两种结构, 为了构成循环程序,DJNZ指令是很有用的, 特别是在根据计数器的值决定循环是否结束时 可以直接使用。但也可以根据其它条件来判断 循环结束条件。 例例4-94-9 内存中以STRING开始的区域有若干 个字符和数字,一般称为一个字符串,最末一 个字符为“$”,试统计这些字符数字的数目, 结果存入NUM单元。 本题可
46、采用WHILE结构,用CJNE指令来和关键字 符作比较,比较时要将关键字符用其对应的ASCII码来 表示。符号“$”的ASCII码是24H。 NUMDATA20H STRINGDATA21H CLR A;A作为计数器,先清零 MOV R0,#STRING;首地址送R0 LOP: CJNE R0,#24H,LOP2;与$比较,不等转移 SJMP LOP3;找到$,结束循环 LOP2:INC A;计数器加1 INC R0;修改地址指针 SJMP LOP;循环 LOP3: INC A;再计这个$字符 MOV NUM,A;存结果 4.3.5查表程序设计查表程序设计 如果一元单值函数的解析式比较复杂,那
47、么,基 于这种函数关系,采用查表法往往使得问题得解决要 简单得多。所谓查表法,就是预先将满足一定精度要 求的表示变量x与函数y=f(x)值之间关系的一张表求出, 然后把这张表存于单片机的程序存储器中。这时自变 量值为单元地址,相应的函数值为该地址单元中的内 容。而查表就是根据给定的自变量x,在表格中查找y, 使y=f(x)。 在MCS-51中,查表时的数据表格是存放在程序 ROM而不是数据RAM中。相应地,用于查表的指令有 两条: MOVC A,A+DPTR MOVC A,A+PC 使用DPTR作为基地址查表比较简单,可通过三步 操作来完成: (1)将所查表格的首地址存入DPTR数据指针寄存器
48、; (2)将所查表格的项数(即在表中的位置是第几项)送累加器 A; (3)执行查表指令MOVC A,A+DPTR进行读数,查表结果 送回累加器A。 若使用PC作为基地址查表,则操作有所不同,也可 分为三步: (1)将所查表格的项数送累加器A,在MOVC A,A+PC指令 之前先写上一条ADD A,#data指令,data的值待定; (2)计算从MOVC A,A+PC指令执行后的地址到所查表的首 地址之间的距离(以字节数表示),用这个计算结果取代加法指 令中的data,作为A的调整量; (3)执行查表指令MOVC A,A+PC进行查表,查表结果送回 累加器A。 例例4-10 在一个温度测量装置中
49、,测出的 电压与温度为非线性关系。设测得电压值为x, 用10位二进制数表示(占2B)。现要求采用查 表法实现线性化处理。 这个问题的解决办法是,先通过实验测出 与1024(210)个电压值相对应的温度值,并按 电压由小到大的顺序构造一个表,表中存放温 度值y(一个定字长数,高字节在前),则: 存放温度值y的单元地址=表首址+(x*2) 设测得电压值x已存放在20H,21H单元中(高字 节在20H),查表得到的温度值y存放在22H, 23H(高字节在22H单元)。查表程序如下: STB1:MOV DPTR,#TAB;首址送DPTR MOV A,21H;(20H)(21H)乘2 CLR C RLC
50、 A MOV 21H,A MOV A,20H RLC A MOV 20H,A MOV A,21H;表首址+(x*2) ADD A,DPL MOV DPL,A MOV A,20H ADDC A,DPH MOV DPH,A CLR A MOVC A,A+PC ;查表得温度值高位字节 MOV 22H,A;存放高字节 INC DPTR;指向温度低位字节 CLR A MOVC A,A+PC ;查表得温度值高低字节 MOV 23H,A;存放低字节 RET TAB:DW ;温度值表 4.4综合程序应用编程综合程序应用编程 单片机常用于测控领域,其中智能仪表是最典型的 单片机应用系统。它具有典型的硬件电路和软
51、件结构。 因此,智能仪表系统最有可能实现硬件的标准化和软 件的模块化。本节以智能仪表的应用软件设计为例说 明综合程序应用编程的问题。 4.4.1智能仪表的典型软件结构智能仪表的典型软件结构 智能仪表是一种较完整的单片机应用系统。一般硬 件电路除基本扩展部分外,都配置有采集电路、显示 器、按键、打印机等。相应的软件有采集控制、数据 处理、显示、结果打印等。 图4-10是智能仪表的一种典型软件结构。按其功能 可分为三部分,即初始化监视程序、键功能散转程序 和系统控制程序。 图4-10智能仪表典型软件结构 图4-11初始化监视程序 正常? 系统测试 初始化 提示符显示 键盘扫描 键按下? 初始化 监
52、视程序 上电复位 键功能 散转程序 系统控 制程序 4.5 C51程序设计简介程序设计简介 当单片机用于一般商用和民用场合, 如作为掌上电脑微处理器时,对实时性 要求不高,但对编程的简单和使用的方 便性提出了较高要求,这时采用高级语 言来设计单片机应用程序就显得较合适。 在这里介绍一种目前流行的MCS-51单片 机高级语言C51。 4.5.1 C51程序结构程序结构 C51程序结构与一般C语言没有什么差别。一个C51程序大体上是一个 函数定义的集合,在这个集合中有且仅有一个名为main的函数(主函 数)。主函数是程序的入口,主函数中的所有语句执行完毕,则程序执 行结束。在这里,其它函数称为子函
53、数。下面所示一个C51程序的大体结 构: #include/*头文件(包含库函数)*/ #define uint unsigned int/*数据类型符号定义*/ #define uchar unsigned char unchar bdata FLAG/*变量,数组等定义*/ void inport(uchar state)/*子函数*/ /*相关语句*/ main()/*主函数*/ /*相关语句*/ inport()/*子函数调用*/ 函数定义由类型、函数名、参数表和函数体四部 分组成。函数名是一个标识符,标识符都是大小可区 别的,最长为255个字符。参数表是用圆括号括起来的 若干参数,项
54、项之间用逗号隔开。函数体是用大括号 括起来的若干C语句,语句与语句之间用分号隔开,最 后一个语句一般是return语句(在主函数中可以省略)。 每一个函数都返回一个值,该值由return语句中的表达 式指定(省略时为零)。函数的类型就是返回值的类 型。函数类型(除整型外)均需在函数名前加以指定。 C51函数的一般格式为函数的一般格式为: 类型 函数名(参数表) 参数说明; 数据说明部分; 执行语句部分; 一个函数在程序中可以三种形态出现一个函数在程序中可以三种形态出现:函数定义、 函数调用和函数说明。函数定义相当于汇编中的一般 子程序。函数调用相当于调用子程序的CALL语句,在 C51中,要普
55、遍地规定函数调用可以出现在表达式中。 函数定义和函数调用不分先后,但若调用在定义之前, 那么在调用前必须先进行函数说明。函数说明是一个 没有函数体的函数定义,而函数调用则要求有函数名 和实参数表。 C51中函数分两大类中函数分两大类:一类是库函数,一类是用户 定义函数。库函数是C51在库文件中已定义的函数,其 函数说明在相关的头文件中。这类函数,用户在编程 时只要用include预处理指令将头文件包含在用户文件 中,直接调用即可。用户自己定义、自己调用的一类 函数。从某种意义上来看,C编程实际上是对一系列用 户函数的定义和调用。 C51程序的编程要点总结如下程序的编程要点总结如下: 1C51语
56、言是由函数构成的。一个C51源程序至少包含一个 函数(main),也可以包含一个main函数和其它子函数。因此, 函数是C程序的基本单位。被调用的函数可以是编译器提供的库 函数,也可以是用户根据需要自己编制设计的函数。 2一个函数由两部分组成: (1)函数说明部分。包括函数名、函数类型、函数属性、 函数参考(行参)、形式参数类型。一个函数名后 面必须跟一个圆括号,函数参数可以没有,如main()。 (2)函数体,即函数说明部分下面的大括号内部分。 如果一个函数内有多个大括号,则最外层的一对 为函数体的范围。 函数体一般包括: 变量定义。 执行部分。由若干语句组成。 当然,在某些情况下也可以没有
57、变量定义部分。甚至既无变量 定义也无执行部分。 3一个C51程序总是从main函数开始执行,而不 论main函数在整个程序中的位置如何。 4C51程序书写格式自由,一行内可以写几个语 句,一个语句可以分写在多行上。C51程序无行号。 5每个语句和数据定义的最后必须由一个分号。 分号是C51语句的必要组成部分。分号不可少,即使是 程序中最后一个语句也应包含分号。 6C51语言本身没有输入输出语句。输入和输出 的操作是由库函数scanf和printf等函数来完成的。C51 对输入输出实行“函数化”。 7可以用/*/对C51程序中的任何部分作注释。 一个好的、有使用价值的源程序都应当加上必要的注 释
58、,以增加程序的可读性。 4.5.2 C51程序编译和连接程序编译和连接 C51语言源程序是一个ASCII文件,可 采用任何标准的ASCII文本编辑器编写, 扩展名为.C。源程序需经过编译和连接 转换为机器语言后才能被CPU识别执行。 现以文件名为SAMPLE.C源程序为例说 明编译和连接的过程。 1编译编译 使用命令为: C51 源程序文件名(可选编译控制项) 例如:C51 SAMPLE.C ROM(SMALL),将产生目标文 件SAMPLE.OBJ,ROM选项用于决定程序内存大小, 它影响转移指令的编码。SMALL表示以CALL和JMP 指令作为ACALL和AJMP指令的编码,最大程序空间
59、可达2K字节,整个用户程序必须分布在这2K字节空间 内。 2连接连接 编译得到的目标文件.OBJ中指令地址是浮动的,需通过 连接产生最后可执行指令文件。使用命令为: L51 输入列表TO 输出文件控制列表 输入列表:是一个由逗号分开的文件名表,该表中的文件是 可重定位的程序模块,对于每个文件欲包含的模块可被指定在括 号内。一般格式为: 文件名(模块名),文件名, 文件名必须指出扩展名,目标文件使用扩展名“.OBJ”,库 文件使用扩展名“.LIB”。模块名输入只有当使用库文件时才是有 用的。模块名必须在文件名后括号内指定,并且必须用逗号分开。 例:L51 SAMPLE.OBJ ,PROG1.OBJ,UTILITY.LIB(FPMUL,FPDIV) 输出文件:是将产生的绝对程序模块的名字,如果不给出名 字,则使用输入文件表中第一个文件名(不带扩展名)。必须注 意输出文件名同时也用作映象文件(扩展名.M51)的基本名。 例:L51 SAMPLE.C TO SAMPLE.ABS 控制列表:包含命令行的命令和参数,可能的参数按顺序显 示。控制命令可在输出文件后指定,各控制命令以空格分开。如 果同一
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 饮水机人机课程设计
- 花草世界幼儿园课程设计
- 香港金融分析课程设计
- 飞轮剪机构课程设计
- 阅读课程设计难度
- 液压系统计算课程设计
- 音响课程设计答辩
- GB/T 45193-2024报废机动车回用件通用技术规范
- 二零二五年电梯设备设计与制造合同3篇
- 2024跨国软件开发与许可合同
- 试卷(完整版)python考试复习题库复习知识点试卷试题
- 海外资管机构赴上海投资指南(2024版)
- GB/T 44679-2024叉车禁用与报废技术规范
- 抖音直播带货协议书模板
- 2024义务教育体育与健康课程标准(2022年版)必考题库及答案
- 工业机器人控制器:FANUC R-30iB:机器人实时监控与数据采集技术教程
- 墓地销售计划及方案设计书
- 新加坡留学完整版本
- 劳务服务合作协议书范本
- 优佳学案七年级上册历史
- 中医五脏心完整版本
评论
0/150
提交评论