第4章 单片机的程序设计与调试.ppt_第1页
第4章 单片机的程序设计与调试.ppt_第2页
第4章 单片机的程序设计与调试.ppt_第3页
第4章 单片机的程序设计与调试.ppt_第4页
第4章 单片机的程序设计与调试.ppt_第5页
已阅读5页,还剩136页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、1,第4章 单片机的程序设计与调试,【本章内容】 本章主要介绍伪指令、源程序汇编以及常用程序的设计方法。 【项目驱动的学习要点】 应用项目中各段程序功能分析。 应用项目中的程序流程图分析。 应用项目中各段程序设计方法分析。,2,第4章 单片机的程序设计与调试,4.1 源程序的设计与汇编 4.2单片机开发系统与源程序的调试 4.3 顺序和分支程序设计 4.4 循环和查表程序设计 4.5 子程序和中断程序设计 练习题,END,3,4.1 源程序的设计与汇编,4.1.0 几个概念 4.1.1 伪指令 4.1.2 源程序的设计 4.1.3 源程序的汇编,4,二进制形式的机器指令称为机器语言,采用机器语

2、言编写的程序能直接被计算机识别和执行。 由于机器语言不容易理解和记忆,所以人们通常用符号指令来编写源程序。 采用符号指令编写的程序必须通过编译软件(也叫汇编程序)或手工翻译(汇编)成机器指令的形式才能被计算机执行。前者称为机器汇编,后者称为手工汇编。,4.1.0 几个概念,5,用符号指令的计算机语言称汇编语言。 符号指令也称为汇编语言指令; 采用汇编语言指令编写的程序叫做汇编语言源程序。 汇编的反过程称为反汇编。,几个概念,6,图4-1 源程序的汇编与反汇编,源程序的汇编与反汇编,7,4.1.1 伪指令,为了使编译软件能按设计者的要求汇编源程序,编写汇编语言源程序时,还要用到伪指令。 伪指令是

3、供汇编程序识别和执行并对汇编过程进行某种控制的指令性语句。它不是真正的单片机指令,无对应的机器码。所以汇编后产生的目标程序中不会出现伪指令。,8,指令格式:ORG 表达式 指令功能:用于向汇编程序说明下面紧接的程序段或数据段存放从表达指定的起始地址开始存放。表达式通常为十六位地址或自定义的标号地址。 通常每一个汇编语言源程序的开始,都要设置一条ORG伪指令来指定该程序在ROM中存放的起始位置。可以在源程序中使用多条ORG伪指令来规定不同程序段或数据段存放的起始地址,但要求地址值由小到大顺序排列,不允许空间重叠。,1起始汇编伪指令,9,1ORG0000H 2LJMPMAIN ; 转主程序 3 O

4、RG 0003H 4LJMP BREAK0 ; 转 中断 5 ORG 000BH 6LJMP CLOCK ; 转定时器T0中断 7ORG 0013H 8LJMP BREAKl ; 转 中断 ; 主程序: 9ORG0050H 10 MAIN:MOVA, #03H; 8155初始化 ; 控制字码表: 137ORG1010H 138DB0FEH, 06H, 20H, 00H, 0FFH, 06H, 20H, 15H ,【项目应用】以下是应用项目中使用的ORG伪指令,请分析各条ORG指令的作用。,10,解:,(1)第一条ORG伪指令用于说明整个程序的起始地址为0000H,其后的LJMP MAIN指令的

5、机器码便从ROM的0000H单元开始存放。这是单片机开机或复位时的PC初值,所以单片机在开机或复位时总是从这个地址开始读出程序。 (2)第二至第四条ORG指令中的地址分别对应系统规定的3个中断入口地址,用于使其后的中断服务程序能存放在正确的位置(详见第5章)。 (3)第五条ORG伪指令用于说明从标号为MAIN的指令往后的程序存放在0050H开始的ROM单元中。于是应用项目中的主程序,便由0000H单元通过无条件长转移指令LJMP MAIN转移到0050H往后的ROM单元,从而防止系统设定的中断入口地址被占用。 (4)第六条ORG伪指令用于指定作为控制字码表的一个数据区的起始地址为1010H。从

6、应用项目的反汇编源程序可以看出,ORG伪指令指定的地址没有发生重叠。,11,指令格式:END 指令功能:结束汇编。放置于汇编源程序的末尾,当汇编程序遇到END伪指令时,即结束汇编。处于END之后的程序,汇编程序不会进行处理。,2结束汇编伪指令,12,指令格式:符号名 EQU 表达式 指令功能:将表达式的值赋给指定的符号名。表达式通常是8位或16位的地址、数据或汇编符,如果是位地址,则必须采用位的物理地址。 符号的命名与标号的命名规定相同:可以由18个ASCII字符组成。首字符必须是字母,其余字符可以是字母、数字或其他特定字符,不能使用汇编语言已经定义了的符号,如指令助记符、寄存器符号名称等。

7、“符号名” 一旦被赋值,就可以在源程序的任意地方使用,汇编时,汇编程序自动用表达式的值进行代真。使用EQU伪指令有两个优点,一是当源程序中有多处引用“符号名”的地方要修改时,只要修改为“符号名”赋值的指令即可;二是当“符号名”具有见字明义的名称时,可增加程序的可读性。,3通用赋值伪指令,13,符号的命名与标号的命名规定相同:可以由18个ASCII字符组成。第一个字符必须是字母,其余字符可以是字母、数字或其他特定字符,不能使用汇编语言已经定义了的符号,如指令助记符、寄存器符号名称等。 “符号名”必须先赋值后使用,一旦“符号名”被赋值,它就可以在源程序的任意地方使用,汇编时,汇编程序自动用表达式的

8、值进行代真。 使用EQU伪指令有两个优点,一是当源程序中有多处引用“符号名”的地方要修改时,只要修改为“符号名”赋值的指令即可;二是当“符号名”具有见字明义的名称时,可增加程序的可读性。,说明:,14,ORG 0100H; 起始汇编 LEN EQU 10 ; LEN=“10” UM EQU 20H ; SUM=“20H” BLOCK EQU 30H ; BLOCK=“30H” START: CLR A ; A清0 MOV R2, LEN ; 计数初值送R2 MOV R0, BLOCK; 指针初值送R0 LOOP: ADD A, R0; 累加 INC R0 ; 指针加1 DJNZ R2, LOO

9、P ; 未完继续 MOV SUM, A ; 保存结果 HERE: SJMP $; 动态停机 END; 结束汇编,【例4-1】如下一段程序的功能是将BLOCK单元开始存放的10个无符号数进行求和,并将结果存入SUM单元中(假设结果小于255)。,15,可见,若要改变BLOCK单元、SUM单元或累加数据个数,则只要改变相应的EQU指令便可。 细心的读者可以发现,程序中每条指令都加了注释,而且注释的不是单纯的指令功能,而是指令的程序功能,旨在给读者一个示范,希望读者从本章开始,逐步学习单片机的程序设计并学会注释指令的程序功能。,说明:,16,指令格式:符号名 BIT 位地址 指令功能:用于将位地址赋

10、给指定的符号名。其中,位地址可用位名、物理位地址、“字节地址位序号”、“寄存器名位序号”等形式表示(详见3.2.7位寻址)。 例如:MARK BIT F0 其中的位地址是PSW中的用户标志位F0,它也可以用0D5H、0D0H5、PSW5等形式表示。,4位地址赋值伪指令,17,指令格式:标号: DB 单字节数据表 指令功能:用于从标号(即汇编程序为该指令分配的首地址)对应的地址单元开始,将“单字节数据表”中的数据按从左到右的顺序依次存入ROM中,一个数据占一个存储单元。单字节数据表可以是一个或多个单字节数据、字符串或表达式(其值为单字节),表项之间用逗号分隔。项数多于一行时,可使用多条DB伪指令

11、。,5单字节定义伪指令,18,(详见3.1.1指令格式)。 十六进制数:加上后缀H表示,以字母AF开头时,在它的前面加一个前导“0”。 二进制数:加上后缀B表示。 十进制数:加上后缀D表示,也可以省略后缀。 ASCII码:用“单引号”括起来表示,如A,ABC,1,123。,数据的表示方法,19, 134 DONE2: RET ; 字形码表: 135 SEGTAB: DBFH, 06H, 5BH, 4FH, 66H, 6DH, 7DH 136 DB07H, 7FH, 6FH ; 控制字码表: 137 CODE: ORG1010H 138 DB0FEH, 06H, 20H, 00H, 0FFH,

12、06H, 20H, 15H 139 DB0EFH, 06H, 25H, 00H, 0FFH, 06H, 40H, 00H ,【项目应用】以下是应用项目中使用的DB伪指令,20,编号为135的DB伪指令的功能是指示汇编程序从上一条指令(RET)存放完成后的下一个ROM单元开始,依次存入10个字形码。该条伪指令一行写不下,所以分成两条DB伪指令来书写; 编号为138的DB伪指令的功能则是从它上一条ORG伪指令指定的1010H单元开始,依次存入数据表中的控制码。表项较多,所以用多条DB伪指令来书写。,说明:,21,指令格式:标号: DW 双字节数据表 指令功能:与DB伪指令类似,只是指令中数据表的表

13、项应为双字节,即16位二进制数。存入ROM中时,高8位存放在低地址单元中,低8位存放在高地址单元中,对于不足16位的表项数据,存放时在前面补0。例如: ORG0759H DATA: DW3295H, 2800H, 0BDH, 汇编后,在ROM中的数据为:(0759H)=32H,(075AH)=95H,(075BH)=28H,(075CH)=00H,(075DH)=00H,(075EH)=BDH。,6双字节定义伪指令,22,指令格式:标号: DS 表达式 指令功能:用于从标号对应的地址单元开始,在程序存储器中预留出一段存储单元作为备用空间,预留单元数量由表达式确定。 例如: ORG0800H S

14、PARE: DS20H 汇编后,从ROM中地址为0800H的单元开始,预留32个空的存储单元作为备用单元。,7空间定义伪指令,23,4.1.2 源程序的设计,1源程序设计的步骤 2源程序设计的基本要求 3源程序设计注意事项,24,1源程序设计的步骤,(1)明确设计任务 (2)选择适当的算法 (3)确定系统规划 (4)确定程序结构 (5)绘制程序流程图 (6)编写源程序 (7)汇编和调试,25,(1)明确设计任务,在开始源程序设计前,首先要对所要设计的单片机应用系统进行深入地分析,明确应用系统所要实现的功能和技术要求,综合考虑应用系统的可行性、先进性、可靠性、可维护性、成本及经济效益等。选择合适

15、的器件,设计出合理的硬件电路。因为单片机的程序设计与硬件电路的结构是紧密联系在一起的,面板的开关、按键、显示、输入/输出引脚的定义等也与程序设计密切相关,所以要事先作好准备。,26,算法是解决具体问题的方法。明确设计任务后,设计者应把应用系统所要实现的功能和技术要求利用严密的数学方法或数学模型来描述,从而把一个实际问题转化成由计算机进行处理的问题。同一个问题的算法可能有多种,实现方案也可能不尽相同,所以应对各种算法进行分析、比较,合理优化,从中找出一种切合实际的最佳算法。,(2)选择适当的算法,27,系统规划包括合理地选择和分配内存工作区及有关端口地址,规划好寄存器和存储器的使用;确定数据和工

16、作单元,分配存储单元;对数据暂存区、堆栈区、显示缓冲区、标志单元等作好统一安排;根据程序区、数据区、字形表等预计所占字节的多少,对程序存储器ROM做出空间规划,合理分配并确定每个区域的首地址,以及系统主程序、子程序的入口地址,中断服务程序的存放地址等。,(3)确定系统规划,28,程序结构的设计是把算法转化为程序的准备阶段。如果算法比较简单,这一步可以省略,直接按算法编写程序。如果算法比较复杂,则需要进行程序结构的设计。程序的基本结构通常有顺序结构、分支结构、循环结构、子程序及中断服务程序等5类。 程序结构的设计一般通过绘制程序流程图来实现。,(4)确定程序结构,29,(5)绘制程序流程图,程序

17、流程图是用规定的图形符号配以文字说明来表示算法或处理问题的步骤,它具有直观、易懂的特点,是程序结构设计的有力工具。,30,常用的程序流程图符号如图4-2所示。,图4-2 常用的程序流程图符号,程序流程图符号,31, 端点框:表示程序的起止。在端点框中可输入开始、结束、程序名、起始地址等相应的文字。 处理框:表示一种处理功能或者过程,处理框中的文字简要说明一段程序的功能或处理过程。 判断框:表示一个判定点,从该点产生分支,在判断框内应注明测试条件,而测试结果则在各分支流程线上注明。 连接框:表示流程中止而并非流程结束,通常用来连接同一页的流程,以避免流程线的交叉,也可以用来连接不同页上的流程,以

18、避免流程线的跨页中断。绘图时,表示连在一起的连接框内的标识符要相同 流程线:表示程序执行的流向。,程序流程图符号说明:,32,源程序的编写是根据绘制好的程序流程图,运用单片机指令集中的合法指令和伪指令编写出能实现流程图规定功能的程序。所编写的源程序要力求简单明了、层次清晰、可靠、高效。,(6)编写源程序,33,汇编是将源程序翻译成能被单片机识别和执行的目的程序。 调试则是检验所编写的程序是否正确,能否正常运行。如果这两步不能通过,则需要重复以上步骤,对程序进行反复修改,直到获得正确的结果为止。,(7)汇编和调试,34,(1)正确性:要求严格按指令格式书写指令,不能臆造非法指令。 (2)可靠性:

19、由于单片机主要用于控制,所以程序的可靠性很重要。 (3)可读性:为了增加程序的可读性,可在程序段前或每条指令后添加注释。 (4)有效性:要求程序占用存储空间尽量小,执行时间尽可能短。,2源程序设计的基本要求,35,(1)采用模块化的程序设计方法 (2)尽量采用循环结构和子程序 (3)合理分配内存单元 (4)正确使用转移指令,3源程序设计注意事项,36,模块化的程序设计方法具有如下优点: 单个模块的程序功能单一,结构层次一目了然,易于编写、调试和修改。 便于分工,从而可使多个程序员同时进行程序的编写和调试工作,加快软件研制进度。 程序可读性好,便于程序的优化、扩充和版本升级。 对程序可进行局部修

20、改,其他部分可以保持不变。 对于使用频繁的子程序可以建立子程序库,便于多个模块调用。,(1)采用模块化的程序设计方法,37,采用循环结构和子程序可以使程序所占用的存储空间大大减少,节省了存储空间单元,提高程序的运行效率。对于循环程序尤其是多重循环程序,要注意循环初值的设置和循环结束条件的判断,避免出现程序无休止循环的“死循环”现象。 对于通用的子程序,考虑到其通用性,除了用于存放子程序入口参数的寄存器外,程序中用到的其他寄存器的内容应压入堆栈,即保护现场。但要特别注意恢复现场的出栈顺序要与入栈顺序相反,符合堆栈的操作规则。对于中断处理子程序也要注意类似的问题。,(2)尽量采用循环结构和子程序,

21、38, 工作寄存器R0和R1具有地址指针功能,应充分发挥其作用,避免用作其他寄存器。 20H2FH单元具有位寻址功能,通常用来存放各种软件标志、逻辑变量、状态信息等。 30H7FH单元作为一般寄存器区域,通常用来存放各种参数、指针、中间结果或作为数据缓冲区。 如果程序中需要使用08H单元以后的工作寄存器组,通常把堆栈设置在内部RAM的高端处,即30H7FH单元。,(3)合理分配内存单元,39,(4)正确使用转移指令,尽量少用无条件转移指令。这样可以使程序的条理更加清楚,从而减少错误。子程序内部的转移最好使用相对转移指令,使所编写的子程序可以放在64KB程序存储器ROM的任何地方,增加子程序的通

22、用性,便于主程序调用。,40,4.1.3 源程序的汇编,1手工汇编 2机器汇编,41,1手工汇编,是指程序设计者通过手工方式,对照指令代码表(见附录B)将汇编语言源程序中的每一条符号指令转换成对应机器码的过程。 对于无分支源程序可以一次性完成汇编;对于包含转移指令和标号在内的源程序,通常需要进行两次汇编才能完成整个汇编过程:第一次汇编完成指令码的“代真”,第二次汇编完成地址偏移量的“代真”。 举例说明如下。,42,ORG0100H; 起始汇编 LENEQU10 ; LEN=10 SUMEQU20H ; SUM=20H BLOCK EQU 30H ; BLOCK=30H START:CLR A

23、; A清0 MOV R2, LEN ; 计数初值送R2 MOV R0, BLOCK ; 指令初值送R0 LOOP:ADDA, R0 ; 累加 INCR0 ; 指针加1 DJNZ R2, LOOP ; 未完继续 MOV SUM, A ; 保存结果 HERE:SJMP $ ; 动态停机 END ; 结束汇编,【例4-2】请对例4-1的源程序进行手工汇编。该源程序的功能是将BLOCK单元开始存放的10个无符号数进行求和,并将结果存入SUM单元中(假设结果小于255)。,43,根据起始汇编伪指令,确定源程序的起始地址,对照指令表(见附录B),依次找出每条指令的机器码,并确定它们的起始地址,对于无法确认

24、的标号和地址偏移量,把它们按原样抄录在指令码的相应位置上。第一次手工汇编的结果如表4-1所列。,解:(1)第一次汇编,44,表41第一次手工汇编结果:,45,确定指令码中的标号或地址偏移量,即需要计算出表4-1中的有关标号LOOP、$(HERE)的实际值,结果为负数时用补码表示,计算公式为: 地址偏移量=目标地址(转移指令始址 + 转移指令字节数) 求得为: LOOP=0105H(0107H+2)=4补码为:FCH $(HERE)=010BH(010BH+2)=2 补码为:FEH 用计算结果置换表4-1中的地址偏移量,结果如表4-2所列,从而完成汇编。,(2)第二次汇编,46,表42第二次手工

25、汇编结果:,47,机器汇编是指在微机上利用编辑软件编写好单片机的汇编语言源程序后,再通过运行于微机中的汇编程序(编译软件)对源程序进行汇编,把汇编语言源程序翻译成目标程序。最后经调试、仿真成功后,通过编程器(或称为烧写器)将目标代码写入ROM中,提供给单片机执行。,2机器汇编,48,4.2 单片机开发系统 与源程序的调试,4.2.1 开发系统的组成 4.2.2 开发系统的功能 4.2.3 源程序的调试,49,4.2.1 开发系统的组成,单片机开发系统通常由PC机、仿真机、编程器、擦除器等组成,如图4-3所示。,图4-3 单片机开发系统,50,用于运行由产品制造商提供的包括编辑程序、汇编程序、调

26、试程序等在内的单片机开发系统集成操作软件,构成一个集成的开发平台,使开发系统具有各种所需的单片机开发功能,或者用于运行编程器支持软件,使编程器可以将汇编好的目标代码下载(写入)到程序存储器ROM中。,1PC机,51,仿真机本身也是一个已开发好的单片机系统,它具有模拟目标系统中的单片机、ROM、RAM和I/O端口的功能,而且基本上不占用目标系统单片机的任何资源。有些仿真机上还提供部分独立的单元电路或扩展单元,通过适当的连接就可以在仿真机上构成与目标系统相同的硬件电路,使仿真目标系统的运行环境与实际运行环境完全“逼真”。并且通过开发系统的监控软件使开发者能对仿真过程实施监控。,2仿真机,52,3仿

27、真头,仿真头实际上是一个引脚数量与单片机引脚数量相同的插头。用于将仿真机上的单片机信号延伸到目标系统上,代替目标系统上的单片机。,53,目标系统就是需要开发的单片机应用系统。,4目标系统,54,编程器也称为烧写器或固化器,通过并行接口、串行接口或USB接口与PC机相连,用于把保存在PC机中的已调试好的目标代码写入EPROM或E2PROM中。大部分编程器还具有从ROM中读出未加密的代码,或擦除E2PROM中的代码的功能。,5编程器,55,擦除器一般为紫外线擦除器,用于擦除靠紫外线擦除信息的EPROM中的代码,以便重新写入新的代码。,6擦除器,56,4.2.2 开发系统的功能,不同的单片机开发系统

28、,功能各异,但一般都具有如下一些基本的功能。,57,1源程序编辑功能,大多数单片机开发系统都自带一个文本编辑器,具有录入、编辑源程序的功能。,58,2源程序的编译功能,单片机开发系统能对源程序进行编译,从而生成目标代码。,59,使用单片机开发系统对源程序进行编译的过程中,如果发现错误,单片机开发系统能给出错误提示信息,以便用户进行修改。,3排错功能,60,通过通信电缆将在PC机中生成的目标代码装载到仿真机中。,4目标代码装载功能,61,单片机开发系统能有效监控目标程序的运行,以检查运行结果,对硬件故障和软件错误进行定位,其运行方式可设置为连续运行、单步运行或带断点运行等。,5运行监控功能,62

29、,单片机开发系统可读出或修改仿真机中的仿真ROM、RAM、工作寄存器、特殊功能寄存器等,以便对目标程序或运行参数、状态等进行修改,满足源程序调试的需要。,6读出/修改功能,63,通过仿真机上的仿真头,将仿真机上的单片机出借给目标系统,当在开发系统上通过仿真头调试目标系统时,就像使用目标系统中真实的单片机一样,这就是在线仿真。仿真调试成功后,拔掉仿真头,并把开发调试好的程序固化到单片机中的EPROM或片外EPROM芯片中,再把单片机(或连同程序存储器)装回目标系统,目标系统就可以独立运行了。,7仿真功能,64,4.2.3 源程序的调试,源程序的调试大致可分为如下步骤,根据所使用的单片机开发系统的

30、不同以及调试过程的具体情况,有些步骤是必须的,有些步骤是选做的,可以使用开发系统用户界面中的菜单或功能键进行选择。,65,(1)编辑,利用开发系统自带文本编辑器录入、编辑源程序。当然,开发者也可以利用任何一种文本编辑软件编辑源程序,但要注意汇编指令和伪指令的书写格式,不能使用全角的标点符号或其他非法字符。编辑好的源程序一般是以“ASM”为扩展名存盘,以便汇编程序识别。,66,对编辑好的源程序进行汇编,但通常需要先对源程序中的单条指令进行翻译。,(2)汇编,67,对上一步骤已汇编好的单条指令进行代真、链接,形成真正的可供单片机执行的目标代码。,(3)链接,68,将汇编好的目标代码,通过通信电缆从

31、PC机下载到仿真机中。,(4)装载,69,是装载的反过程,将下载到仿真机中的目标代码反过来读到PC机中,再反过来由目标代码翻译为符号指令,目的是供开发者通过对比反汇编的程序与原来的源程序,验证是否汇编、装载成功。如有错误,则需重复上述步骤进行修改。,(5)反汇编,70,(6)运行:通过开发系统提供的运行控制命令,对下载到仿真机的目标代码进行试运行,运行方式通常有连续运行或单步运行,这时可以根据开发系统程序调试界面上显示的工作寄存器、特殊功能寄存器等的状态,或查看有关的RAM中的数据以及硬件电路设置的输出指示等,判断源程序是否正确。必要时还可以使用开发系统的控制命令在程序中设置断点,通过带断点运

32、行,进一步对目标程序实施监控、跟踪。如有错误,重复以上步骤,直到完成源程序的最终调试。 (7)固化程序:把经过上述步骤调试好的目标代码通过编程器写入单片机的EPROM或片外EPROM中,从而完成单片机的整个程序设计与固化的工作。,(5)反汇编,71,通过开发系统提供的运行控制命令,对下载到仿真机的目标代码进行试运行,运行方式通常有连续运行或单步运行,这时可以根据开发系统程序调试界面上显示的工作寄存器、特殊功能寄存器等的状态,或查看有关的RAM中的数据以及硬件电路设置的输出指示等,判断源程序是否正确。必要时还可以使用开发系统的控制命令在程序中设置断点,通过带断点运行,进一步对目标程序实施监控、跟

33、踪。如有错误,重复以上步骤,直到完成源程序的最终调试。,(6)运行,72,4.3 顺序和分支程序设计,4.3.1 顺序程序设计 4.3.2 分支程序设计,73,4.3.1 顺序程序设计,顺序程序又称为简单程序,是一种顺序执行的程序。 该类程序没有分支、循环或子程序。顺序程序虽然简单,但也能完成一定的功能,是构成复杂程序的基础。,74,应用项目中的主程序除去最后两条指令,余下的指令所构成的程序为顺序程序结构,其对应的程序流程图如图4-4所示。,【项目应用】,图4-4 应用项目主程序中的顺序程序流程图,75,; 主程序: 9 ORG0050H 10 MAIN:MOV A, #03H; 8155初始

34、化命令字 11 MOV DPTR, #8000H; 8155命令口地址 12 MOVX DPTR, A; 向8155写入命令字 13 MOV SP, #5AH ; 栈底移至5AH 14 MOV 2BH, #60H ; 秒计数基制 15 MOV 2CH, #60H ; 分计数基制 16 MOV 2DH, #24H ; 时计数基制 17 MOV TMOD, #01H ; 定时器工作方式1 18 MOV TH0, #3CH ; 置T0初值 19 MOV TL0, #0B0H 20 MOV IE, #87H ; 允许中断 21 SETB TR0 ; 启动定时器T0 ,【项目应用】源程序,76,4.3.

35、2 分支程序设计,1单分支程序 2双分支程序 3多分支程序,77,1单分支程序,单分支程序的特点是,若判断条件满足,则执行程序段B,然后继续执行程序段A;若条件不满足,则不执行程序段B,直接执行程序段A,如图4-5(a)所示。 根据实际也可以采用如图4-5(b)的结构,图中的“Y”,“N”也可以互换。,78,在应用项目中的中断服务程序中就包含了单分支程序结构,它的程序流程图如图4-6所示。 下面以中断服务程序的源程序为例进行分析,【项目应用】,79,; 中断服务程序: 24 BREAK0:CLR EX0; 关闭 中断 25 JNB P3.2, $ ; 消除按键抖动, 等待按键释放 26 INC

36、 28H ; 分单元加1 27 MOV A, 28H; 十进制调整 28 ADD A, #00H 29 DA A 30 MOV 28H, A 31 SUBB A, #60H; 不等于计数基制转NEXT1 32 JC NEXT1 33 MOV 28H, #00H; 相等, 分单元清0 34 NEXT1:LCALL DISP ; 调用显示子程序 SETB EX0 ; 开放 中断 36 RETI; 中断返回,【项目应用】源程序,80,(1)该程序的功能是对自动打铃机的时钟分值进行调校,以保证时钟与标准时间一致。 (2)调校的方法是,通过按下接在单片机P3.2引脚(外部中断外脚)上的按钮来进行。当按下

37、按钮时会在P3.2引脚上出现低电平,于是引起中断,CPU响应中断后,会自动调用这个中断服务程序。考虑到按键时会出现抖动,所以使用JNB P3.2,$ 指令,起到消除按键抖动,等待按键释放的作用,只有释放了按键后,程序才往下执行。,说明:,81,(3)每按下并释放一次按钮,便视为是要增加1分钟的时间,于是程序控制分计时单元28H加1,并对加1后的数据进行十进制调整。因为放在计时单元中的数据要求是BCD码表示的十进制数,而十进制调整指令DA A 必须在加法指令之后执行才能获得正确结果,所以这里加进了一条ADD A,#00H 指令,否则,单看这条指令是没有意义的。,说明:,82,(4)进行十进制调整

38、后的时间分值被送入分计时单元保存,同时,这个数据还要和分计时基制进行比较,判断是否等于60分,若等于60分,则要对分计时单元清0。 (5)完成上述工作后,该程序调用显示子程序对调整后的时间进行显示,子程序返回后,该程序的任务才算完成。最后再次开放中断,并通过中断返回指令RETI回到原来的断点。,说明:,83,双分支程序的结构如图4-7所示,它的特点是,若判断条件满足,则执行程序段A;若条件不满足,则执行程序段B。,图4-7 双分支程序,2双分支程序,84,图4-8 应用项目T0中断服务程序流程图,【项目应用】,应用项目中的T0中断服务程序中就包含有类似的双分支程序结构,它的程序流程图如图4-8

39、所示。,85,; T0中断服务程序: 85CLOCK: PUSH PSW; 保护现场 86 PUSH ACC 87 SETB RS0; 选择工作寄存器组1 88 MOV TH0, #3CH; 重装定时器T0初值 89 MOV TL0, #0BDH 90 INC 26H; 0.1s单元加1 91 MOV A, 26H ; 取0.1s单元内容 92 CJNE A, #0AH, DONE1 ; 不等于10, 转DONE1 93 MOV 26H, #00H ; 等于10, 则清0,【项目应用】源程序,86,; T0中断服务程序: 94MOV R0, #27H ; 指向秒计数单元 95MOVRl, #2

40、BH ; 指向秒计数基制单元 96MOV R3, #03H ; 循环3次(秒、分、时) 97CLOCK1:MOV A, R0; 取计时单元的值 98ADD A, #01H; 计时单元加1 99DA A; 十进制调整 100MOV R0, A; 送回计时单元 101MOV 3BH, Rl; 取计时基制 102CJNE A, 3BH, NEXT3 ; 不等于计时基制, 转出,【项目应用】源程序(续),87,103 MOV R0, #00H; 相等, 则计时单元清0 104 INC R0; 计时单元指针加1 105 INC R1; 时间基制单元指针加1 106 DJNZ R3, CLOCK1 ; 秒

41、、分、时共3次循环 107 NEXT3: ACALL CTRL ; 调用控制子程序 108 DONE1: POP ACC ; 恢复现场 109 POP PSW 110 RETI ; 中断返回,【项目应用】源程序(续),88,多分支程序的结构如图4-9所示,它是根据散转条件的结果来决定转向的,所以也称为散转分支程序。 使用指令: JMP A+DPTR,图4-9 多分支程序,3多分支程序,89,解:程序如下。 MOV DPTR, #TAB ; 指向转移指令表首地址 MOV A, R2 ; 取转移序号 ADD A, R2 ; 序号值乘2 JNC NEXT ; 乘积小于256, 转 INC DPH ;

42、 大于等于256, DPTR高8位加1 NEXT:JMP A+DPTR ; 散转 TAB:AJMP PROG0 ; 转移指令表 AJMP PROG1 AJMP PROGn,【例4-3】,请根据R2中存放的转移序号,编写出转向相应处理分支的程序。 R2=0, 转PROG0; R2=1,转PROG1;R2=n, 转PROGn。,90,由于在该程序的转移指令表中,使用的是AJMP指令,这条指令的字节长度为2,各条转移指令的地址依次相差2个字节,所以编程时要进行地址修正。 在执行散转指令前,需将R2中的序号乘以2。当R2中的转移序号大于等于128时,乘积产生进位,应将此进位加到DPTR的高8位。 本例

43、中的处理程序入口地址必须和相应的AJMP指令对应的PC当前值处在同一个2KB区内,也就是说,散转范围不能超出2KB。否则,可用LJMP指令代替AJMP指令,但此时,R2中的序号要乘以3,因为LJMP指令的长度为3个字节。,说明:,91,4.4 循环和查表程序设计,4.4.1 循环程序设计 4.4.2 查表程序设计,92,4.4.1 循环程序设计,循环程序是指当循环条件满足时,能够重复执行某一段程序的程序结构。采用循环程序可以减少指令数量,缩短程序长度,节省存储单元,同时使程序的结构紧凑和可读性好。循环程序一般由以下4部分组成。,93,循环程序组成,(1)循环初始化:用于做循环前的准备工作。例如

44、,给循环计数器、工作寄存器、地址指针等设置初值。 (2)循环体:当循环条件满足时,需要反复循环执行的程序段,是循环程序的主体。 (3)循环控制:用于控制循环程序的循环和结束。在重复执行循环体的过程中,不断修改循环变量,并根据循环变量对结束条件进行判断,直到满足结束条件,才结束循环程序的执行 (4)循环结束:用于对循环程序执行的结果进行分析、处理和保存。,94,图4-10 循环程序结构,循环程序结构,95,如图4-10(a)所示。程序流程是,一进入循环程序,先执行循环体,然后根据循环结束条件判断是否结束循环。若不满足结束条件,则继续执行循环体;若满足结束条件,则进行结束处理,退出循环。其特点是循

45、环体至少被执行一次。,1先执行后判断,96,如图4-10(b)。程序流程是将循环程序的控制部分放在循环的入口处,先根据循环结束条件判断是否结束循环。若满足结束条件,则直接进行结束处理,退出循环;若不满足结束条件,则反复执行循环体,其特点是:若一开始就满足循环结束条件,则一次也不执行循环体,即循环次数有可能为0。 实际编程时,应根据具体情况选择合适的循环结构。循环程序中还可以包含循环程序,形成多重循环,即循环可以嵌套,但应避免从外循环跳入内循环。,2先判断后处理,97,4.4.2 查表程序设计,查表程序设计方法是预先通过伪指令DB或DW在ROM中构建一个常数表格,然后根据程序执行过程中得到的“表

46、项序号”,通过运用查表指令进行查表,而获得对应表项的内容。 MCS-51共有两条查表指令,使用方法如下。,98,(1)将待查表格首地址送入数据指针DPTR。 (2)将需要找查的“表项序号”送入累加器A。 (3)执行查表指令MOVC A,A + DPTR,即在A中得到查表结果。,1使用MOVC A,A + DPTR查表,99,(1)将需要找查的“表项序号”送入累加器A。 (2)进行地址偏移量调整,即在MOVC A,A+PC指令前插入一条ADD A,#data指令。#data的值等于取出MOVC A, A+PC指令后的PC当前值(即该指令的下一条指令首地址)到待查表格首地址之间的距离(以字节数表示

47、)。 (3)执行查表指令MOVC A,A+PC,便可在A中得到查表结果。 采用MOVC A,A+PC指令查表的好处是,不需要占用DPTR,使DPTR可以另作他用,但所查的表格只能存放在MOVC A,A+PC指令后的256字节之内。,2使用MOVC A,A+PC查表,100,应用项目中的显示子程序就包含了循环程序和查表程序,其程序流程图如图4-11所示。,【项目应用】,101,70 MOV R3, #00H ; 计数延时初值 71 DISP2:DJNZ R3, DISP2 ; 延时一段时间(1ms) 由于71号指令被执行了255次,执行该指令所需的时间为2个机器周期,已知应用项目中应用的时钟频率

48、为6MHz,所以机器周期是2s,于是以上程序实现的时间延时为: 25522=1020(s)1ms,(1)实现“延时1ms” 的循环程序:,102,; 显示子程序: 50DISP:MOVR0, #4FH; 准备向缓冲区放数 57 MOVR0, #4AH; 指向缓冲区首地址 58 MOVR2, #0DFH ; 字位显示控制码 59DISPl:; 以下是显示一位数的程序 72 INCR0; 修改显示缓冲区指针 73 RRA; 为显示下一位做准备 74 MOVR2, A; 存字位码 75 JBACC.7, DISPl; 不到最后一位, 则继续 76 RET; 显示完6位, 返回 ,(2)控制6个LED

49、数码显示器依次显示时、分、秒时间值的循环程序(只要求理解程序结构即可):,103, 4A4F为显示缓冲区,分别放置时、分、秒的时间数值。显示子程序需要将这些值逐个读出转换为字形码,并在LED上逐个显示出来。 应用项目中共用6条字位控制线,字位码中为0的位表示被选中。当字位码为DFH,即1101 1111B时,表示最左边的一条字位线被选中,所以只要将字位码进行右移就可以控制字符逐位显示。当循环右移到最高位为0时,便表示已显示了一遍。,说明:,104,57 MOVR0, #4AH; 指向显示缓冲区首地址 62 MOVA, R0 ; 取显示缓冲区中的数 63 MOVDPTR, #SEGTAB ; 指

50、向字形码表首 64 MOVC A, A+DPTR; 查表, 找字形码 ; 字形码表: 135 SEGTAB: DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH 136 DB 07H, 7FH, 6FH,(3)显示子程序中的查表程序:,将显示缓冲区4A4F中放置的时、分、秒的时间数值逐个读出并转换为字形码(字形码也就是控制LED进行8段显示的段码,将在第8章中介绍)。,105,4.5 子程序和中断程序设计,4.5.1 子程序设计 4.5.2 中断程序设计,106,4.5.1 子程序设计,1子程序的编写 2子程序的调用与返回 3现场的保护和恢复 4子程序调用时的参数传递,1

51、07,1子程序的编写,(1)子程序第一条指令的首地址称为子程序的入口地址。该指令前必须要用标号,此标号也就是该子程序的名称。最好以子程序的功能来命名,以达到顾名思义,一目了然的目的。 (2)子程序的最后一定指令通常要设置为一条子程序返回指令RET,以便使子程序能正确返回主程序断点处,继续执行主程序。,108,子程序的调用通过使用子程序调用指令来实现。执行子程序调用指令时,CPU会自动把指向调用指令的下一条指令首地址的PC值(即断点地址)压入堆栈,把断点地址保护起来。如果是在同一个2KB区内调用,可以使用ACALL指令,使用LCALL指令则可以在64KB范围内调用。 子程序的返回通过子程序返回指

52、令RET实现。执行子程序返回指令时,CPU会自动把调用子程序时,压入堆栈的断点地址从堆栈弹出到PC中,从而使子程序能正确返回主程序。,2子程序的调用与返回,109,主程序在调用子程序时,仅仅对断点做了自动保护,对主程序正在使用的累加器A、工作寄存器R0R7、数据指针DPTR、程序状态字PSW以及有关的内存单元等都进行保护。如果这些单元中的内容在调用子程序结束后,主程序仍需使用,或子程序也要用到这些单元时,就会破坏这些单元在主程序中所存储的数据。 因此,对于在主程序和子程序中都要用到的单元,在调用子程序时,需要进行保护,这个过程称之为保护现场。在执行完子程序,返回主程序前再恢复其原来的内容,这个

53、过程称为恢复现场。,3现场的保护和恢复,110,现以保护累加器A、程序状态字PSW和工作寄存器组的内容为例,加以说明。 (这里假定在主程序中,PSW中的工作寄存器选择位RS1、RS0为00,选择的工作寄存器组为第0组)。,现场保护和现场恢复方法,111,程序如下。 PUSHACC; 保护现场 PUSHPSW SETBRS0; 当前工作寄存器组换为第1组 LCALLaddr16; 调用子程序 POPPSW; 恢复现场 POPACC ,(1)在主程序中实现现场的保护和恢复。,112, 将ACC、PSW压入堆栈,相当于把它们的内容暂时保存起来,这样,在子程序中使用它们时,就不会影响到其在主程序中存放

54、的数据。 调用子程序前,通过“SETS RS0”指令使PSW中的工作寄存器组选择位RS0由0变为1(RS1不变仍为0),目的是将工作寄存器组由原来的第0组换为第1组。这样,在主程序中使用到的R0R7与在子程序中使用到的R0R7,虽然同名,但它们的物理地址却不同,前者的地址是00H07H,后者是08H0FH。通过这样的工作寄存器组更换,便达到了保护主程序所用工作寄存器中的内容的目的。,说明:,113, 将ACC、PSW压入堆栈,相当于把它们的内容暂时保存起来,这样,在子程序中使用它们时,就不会影响到其在主程序中存放的数据。 调用子程序前,通过“SETS RS0”指令使PSW中的工作寄存器组选择位

55、RS0由0变为1(RS1不变仍为0),目的是将工作寄存器组由原来的第0组换为第1组。这样,在主程序中使用到的R0R7与在子程序中使用到的R0R7,虽然同名,但它们的物理地址却不同,前者的地址是00H07H,后者是08H0FH。通过这样的工作寄存器组更换,便达到了保护主程序所用工作寄存器中的内容的目的。,说明:,114, 恢复现场时,将PSW从堆栈弹出,相当于重新恢复PSW原来在主程序中的内容,PSW中的工作寄存器组选择位RS1、RS0由转入子程序后的01又变回原来的00状态,于是,当前工作寄存器又更换成了原来的第0组,主程序中使用的R0R7仍保存原来的数据。ACC从堆栈中弹出后,也恢复为原来的

56、内容。,说明:,115,程序如下。 SUBPRG:PUSHACC; 保护现场 PUSHPSW SETBRS0; 当前工作寄存器组换为第1组 POPPSW; 恢复现场 POPACC RET ; 子程序返回,(2)在子程序中实现现场的保护和恢复。,116,从以上程序可知,这两种实现现场的保护和恢复的方法基本相同。 由于堆栈的操作规则是“先进后出”或“后进先出”,所以恢复现场的出栈顺序应与保护现场时的入栈顺序相反。,说明:,117,子程序调用时的参数传递包括入口参数和出口参数的传递。入口参数是指子程序中用到的主程序参数;出口参数是子程序需要回送给主程序的参数。传递子程序参数的方法通常有以下几种。,4

57、子程序调用时的参数传递,118,当需要传递的参数不是很多,而且这些参数就存放在累加器A或工作寄存器R0R7中时,通常直接利用存放参数的累加器和工作寄存器进行传递,方便快捷。,(1)利用累加器或工作寄存器传递,119,使用这种方法时,要事先在存储器中建立一个参数表,用指针指明参数在表中的位置,传递的是参数的地址,程序通过间接寻址获得实际的参数值。当数据表建立在片内RAM时,可用R0、R1作为指针;建立在片外RAM时,可用R0、R1或DPTR作为指针;建在ROM的数据表,只能用来传递入口参数,可用DPTR作为指针。,(2)利用数据表传递,120,利用堆栈传递的具体方法是,在调用子程序前,主程序用

58、PUSH 指令将需传递给子程序的入口参数压入堆栈。执行子程序时,再用 POP指令从堆栈中将数据弹出。,(3)利用堆栈传递,121,如果需要传递的参数为逻辑参数,也可以通过位地址进行传递。,(4)利用位地址传递,122,应用项目中的控制子程序是一个包含了分支程序、循环程序和查表程序的综合子程序,下面对该子程序进行分析。,【项目应用】,123,首先在应用项目中设计一个实时时钟,并把实时时间(时、分、秒)分别存放在29H、28H、27H中(实现方法在后续章节中介绍)。,(1)实时时间(时、分、秒)存放单元,124,根据控制时间(即作息时间)建立一个数据区作为控制字码表。控制字的格式如下。,(启动装置时间) (关闭装置时间) 控制字由4个字节组成,第一个字节是控制码,第二至第四个字节分别是控制时间时、分、秒。控制码是FEH时,表示开启电铃,为EFH时表示开启广播,为FFH时表示关闭电铃或广播。 例如,“620起床打铃15秒”所对应的控制字如下。,(打铃) (熄铃) 控制字存放在ROM中的情况如图4-12所示。,(2)时间控制字,125,图4-12 控制字码表结构及查表方法,控制字存放在ROM中的情况及查表方法,126,在应用项目中,为了实现按设定的时间自动打铃、熄铃及启、停广播控制,程序设计成在自动打铃机的实时时钟每计时

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论