- 单片机原理与工程应用
- 向敏等
- 2479字
- 2021-04-12 17:18:20
3.3 MCS-51单片机汇编语言程序设计
3.3.1 MCS-51单片机常用伪指令
不同汇编程序允许的伪指令不尽相同。以下介绍的伪指令适用于MCS-51单片机,MCS-51单片机常用的伪指令分为以下三类。
(1)程序起始与结束伪指令:ORG、END。
(2)符号定义伪指令:EQU、DATA、BIT。
(3)数据表格存储格式定义伪指令:DB、DW、DS。
除此之外,还有SET、BYTE、WORD等伪指令,下面介绍一些MCS-51单片机常用的伪指令。
1.ORG
功能:指定其后的程序或程序段的起始地址。
格式:ORG 16位地址
例:
ORG 0000H表示该伪指令下面第一条指令的起始地址是0000H,即“MOV A,#33H”指令的首字节地址为0000H,或标号“START”代表的地址为0000H。
2.END
功能:汇编操作结束标志。
格式:END
在END以后所写的指令,汇编程序不再处理。一个源程序只能有一个END指令,必须放在所有指令的最后。源程序中若没有END语句,汇编时将报错。
3.EQU
功能:将某个特殊数据或某个存储单元赋予一个符号名称。
格式:符号EQU数据或汇编符
EQU将其右边的“数据或汇编符”用左边的符号名称命名,或者说用EQU指令可以给符号名称赋值。符号名称必须先赋值后使用,符号名称被赋值后,在程序中可以作为一个8位或16位的数据、地址或汇编符使用。EQU伪指令要放在源程序的前面。
例如:
上述程序段中,Addr EQU 01FAH将数据01FAH赋予字符名称Addr;RG1 EQU R5将工作寄存器R5赋予字符名称RG1。
4.DATA
功能:将一个8位或16位的数据或地址单元赋予一个符号名称。
格式:符号DATA表达式
DATA的功能与EQU类似,是将其右边表达式的值赋给左边的符号名称。表达式可以是一个8位或16位的数据或地址,也可以是已定义的符号名称,但不可以是一个汇编符号(如Rn等)。
DATA定义的字符名称不必先定义后使用。DATA可以用在源程序的开头或末尾。
例如:InitData DATA 29H;表示用InitData代表29H。
5.DB
功能:从指定的地址单元开始,依次存放若干个8位格式的(字节)数据。
格式:[标号:]DB8位数据表达式
例如:
以上指令经汇编后,将对0200H开始的若干内存单元进行如下赋值:(0200H)=0EH,(0201H)=25H,(0202H)=4DH(M的ASCII码),(0203H)=59H(Y的ASCII码),(0204H)=33H(3的ASCII码)。
6.DW
功能:从指定的地址单元开始,依次存放若干个16位格式的数据(字数据)。16位数据的高8位存入低地址,低8位存入高地址;不足16位的数据,高位用0填充。
格式:[标号:]DW 16位数据表达式
3.3.2 MCS-51单片机汇编语言程序的基本结构
MCS-51单片机汇编语言程序的基本结构有顺序结构、分支结构、循环结构、子程序和中断服务程序。
1.顺序结构
顺序结构程序是一种最简单、最基本的程序。它是一种无分支的线性程序,按照程序编写的顺序依次执行。
【例3.5】 编写程序实现将内部RAM的70H、71H地址中的内容相加,结果送入内部RAM的72H地址和C。
2.分支结构
分支结构程序的特点是改变程序的执行顺序,跳过一些指令,去执行另外一些指令。每一个分支都要单独编写一段程序,每一个分支的开始地址应该赋予一个确定的标号。
在MCS-51单片机中可以直接用来判断分支条件的指令并不多,只有累加器为0(或不为0)、比较条件转移指令CJNE等,MCS-51单片机还提供了位条件转移指令,如JC、JB等。把这些指令结合在一起使用,就可以完成各种各样的条件判断。
【例3.6】 AT89C51内部RAM的63H和64H单元中各有一无符号数,比较其大小,将大数存放于内部RAM的70H单元,小数存放于内部RAM的71H单元,如两数相等,则分别送往这两个单元。
3.循环结构
循环结构程序一般由4部分组成。
(1)置循环初值。即设置循环过程中有关工作单元的初始值,如置循环次数、地址指针及工作单元清0等。
(2)循环体。即循环的工作部分,完成主要的计算或操作任务,是重复执行的程序段。
(3)循环修改。每循环一次,就要修改循环次数、数据及地址指针等。
(4)循环控制。根据循环结束条件判断是否结束循环。
如果循环体中不再包含循环程序,即单重循环程序。如果循环体中包含循环程序,那么这种现象就称为循环嵌套,这样的程序称为二重循环程序、三重或多重循环程序。在多重循环程序中,只允许外重循环嵌套内重循环程序,而不允许循环体互相交叉,也不允许从循环程序的外部跳入循环程序的内部。
【例3.7】 将从首地址(0100H)开始的连续100个外部RAM单元清0。
4.子程序
在用汇编语言编程时,某些任务或功能需要多次使用,且该任务或功能相对较独立,则可以将其编写为一个程序段,需要时通过指令直接调用,这种程序段称为子程序。每个子程序都有唯一的标号,在使用时,有两个指令可以调用子程序:ACALL Addr11和LCALL Addrl6。指令中的地址为子程序的入口地址(即标号)。在执行这两条指令时,单片机将当前的PC值压入堆栈。子程序的最后是返回指令RET,这条指令将堆栈的内容传入PC中,保证程序返回到调用的地方继续运行。
使用子程序还可以减少源程序和目标程序的长度,但从程序的执行来看,每调用一次子程序都需要附加保护断点、进栈和出栈等操作,增加程序的执行时间。在汇编语言源程序中使用子程序时,一般要注意两个问题:参数传递和现场保护。参数传递一般可采用以下方法。
① 传递数据。将数据通过工作寄存器R0~R7或累加器来传送。即主程序和子程序在交接处,上述寄存器和累加器存储的是同一参数。
② 传送地址。数据存放在数据存储器中,参数传递时只通过R0、R1、DPTR传递数据所存放的地址。
③ 通过堆栈传递参数。在调用之前,先把要传送的参数压入堆栈,进入子程序之后,再将压入堆栈的参数弹出到工作寄存器或者其他内存单元。
④ 通过位地址传送参数。在进入汇编子程序时,特别是进入中断服务子程序时还应注意现场保护问题,即对于那些不需要进行传递的参数,包括内存单元的内容、工作寄存器的内容,以及各标志的状态等都不应因调用子程序而改变。方法就是在进入子程序时,将需要保护的数据压入堆栈,而空出这些数据所占用的工作单元,供在子程序中使用。在返回调用程序之前,则将压入堆栈的数据弹出到原有的工作单元,恢复其原来的状态,使调用程序可以继续往下执行。由于堆栈操作是“先入后出”,因此,先压入堆栈的参数应该后弹出,才能保证恢复原来的状态。例如:
5.中断服务程序
中断服务程序是为响应某个中断源请求服务的独立子程序,该子程序独立于主程序之外,不会在主程序中被调用。中断服务程序返回指令为RETI,而普通子程序返回指令为RET。中断服务程序的设计步骤将在第4章讲解。