MCS-51单片机程序设计_第1页
MCS-51单片机程序设计_第2页
MCS-51单片机程序设计_第3页
MCS-51单片机程序设计_第4页
MCS-51单片机程序设计_第5页
已阅读5页,还剩82页未读 继续免费阅读

下载本文档

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

文档简介

MCS-51单片机程序设计单片机原理与应用MCS-51单片机程序设计全文共87页,当前为第1页。MCS-51单片机程序设计1.1汇编语言概述1.3常用程序设计1.2程序设计MCS-51单片机程序设计全文共87页,当前为第2页。

机器语言是计算机能够直接识别和执行的语言,但其指令代码的编写、调试和阅读都相当困难。基于机器语言存在的问题,人类发明了更接近于人类语言特征的指令—汇编语言来编写程序。汇编语言是计算机系统提供给用户的最快、最有效的语言,也是能对硬件直接编程的语言。因此,对空间和时间要求很高的程序,或需要直接控制硬件的程序,一般都使用汇编语言进行程序设计。用汇编语言编写的程序称为汇编语言源程序。MCS-51单片机程序设计全文共87页,当前为第3页。1.1.1汇编语言的特点

汇编语言是用助记符来表示机器语言的指令代码的。汇编语言具有如下特点:①助记符指令和机器指令一一对应。用汇编语言编写的程序效率高,占用存储空间小,运行速度快,且能编写出最优化的程序。②汇编语言与计算机硬件设备密切相关。汇编语言程序能直接管理和控制硬件设备,直接访问存储器及接口电路,也能处理中断。③汇编语言编程比高级语言程序的编写和调试要困难。汇编语言是面向计算机的,汇编语言的程序设计人员必须对计算机硬件有相当深入的了解。④汇编语言缺乏通用性,程序不易移植。各种计算机都有自己的汇编语言,不同计算机的汇编语言之间不能通用。MCS-51单片机程序设计全文共87页,当前为第4页。1.1.2汇编语言的语句格式

汇编语言源程序中的语句格式表示如下:

[标号:] 操作码 [操作数] [;注释]

(Lable)(Opcode)(Operand)(Comment)一条汇编语句由标号、操作码、操作数和注释四个部分所组成,其中方括号括起来的是可选择部分,根据需要而定。1.

标号标号是语句地址的标志符号,汇编语言程序的语句通过标号才能访问到该语句。对于标号的使用有以下规定:

①标号由1~8个ASCII码字符组成,第一个字符必须是字母,其余字符可以是字母、数字和一些特定字符。

②不能使用汇编语言中已经定义的符号作为标号,如指令助记符、伪指令、专用寄存器的符号名称等均不能用作标号。

③标号后必须紧跟一个冒号。MCS-51单片机程序设计全文共87页,当前为第5页。④同一个标号在一个程序中只能定义一次,不能重复定义。⑤一条语句可以有标号,也可以没有标号,标号的有无取决于本程序中的其他语句是否需要访问这条语句。下面给出一些常见的正确标号和错误标号,以加深理解。正确的标号 错误的标号

LOOP: 1BT:(以数字开头)

TABLE:LST+2:(“+”号不能在标号中出现)

THLS2:BEGIN(无冒号)

LT-1: MOV:(指令助记符)MCS-51单片机程序设计全文共87页,当前为第6页。2.操作码操作码用于规定语句执行的操作,它是指令助记符或伪指令。操作码是汇编语言语句中惟一不可空缺的部分。3.操作数操作数是给指令的操作提供数据或地址,它与操作码之间用空格分隔。在一条指令中,操作数根据指令的不同,可以是空白或一至三个,若有两个以上操作数,各操作数之间用逗号分隔。MCS-51单片机程序设计全文共87页,当前为第7页。4.注释注释不属于语句的功能部分,它只是对语句的功能和性质进行解释说明,因此注释可有可无,不是必须的。注释用分号“;”开头,以下为注释内容。注释的长度不限,一行不够时可以换行接着书写,但换行时应注意在开头使用“;”号。使用注释可以使程序结构清楚,可读性强,方便软件的维护、修改和扩充功能,因而一个完整的汇编语言程序应附有必要的注释。MCS-51单片机程序设计全文共87页,当前为第8页。1.1.3汇编语言的伪指令

伪指令是指令系统之外的,是程序源发给汇编程序的指令。汇编程序在这些指令的指导下将汇编语言程序汇编,生成机器码。伪指令对程序本身的算法和流图控制没有作用,因此伪指令没有对应的机器语言代码。下面介绍MCS-51汇编语言程序中常用的伪指令。1.ORG汇编起始地址命令其功能是规定生成的机器语言程序代码的起始地址。命令格式:

[标号:]ORG地址其中标号是任选项,可以没有。地址项为16位二进制绝对地址。MCS-51单片机程序设计全文共87页,当前为第9页。例如:

ORG 1000HSTART: MOV A,#00H

规定了这个程序的START标号所在的地址为1000H,机器码程序从1000H地址开始存放。2.END汇编终止命令其功能是终止源程序的汇编工作,在END之后的指令,汇编程序都不予处理。END是汇编语言程序的结束标志,一个程序只能有一个END命令。命令格式:

[标号:]END[表达式]MCS-51单片机程序设计全文共87页,当前为第10页。只有主程序模块才具有表达式项,且表达式的值等于该程序模块的入口地址。其他程序模块没有表达式项。其中标号也是可选项,当源程序为主程序时,END伪指令可带标号,这个标号应是主程序第一条指令的符号地址。若源程序为子程序,则END伪指令不应带标号。例如:

ORG 1000HSTART: MOV A,#00H

… END STARTMCS-51单片机程序设计全文共87页,当前为第11页。3.EQU赋值命令其功能是将一个特定值赋给一个标号。赋值以后,标号值在整个程序中有效。命令格式:字符名称EQU表达式这里的字符名称不同于标号,因此不加冒号。表达式可以是常数、地址、标号或表达式。其值为8位或16位二进制数。赋值以后的字符名称既可以作地址使用,也可以作立即数使用。例如:

YH EQU 7FH

把7FH的值赋给字符YH,在其后的编程中YH就代表7FH。MCS-51单片机程序设计全文共87页,当前为第12页。4.DB定义字节命令功能是从指定的地址单元开始,定义若干个字节的数据。命令格式:

[标号:]DB数据表

其中的标号是可选项,数据表是一字节数据或用逗号分隔开的一组字节数据,或用引号括起来的字符串。例如:

CONST: DB 30H TBL: DB 0C0H,0F9H,0A4H DB 0B0H,99H,92HMCS-51单片机程序设计全文共87页,当前为第13页。

第二条伪指令定义了一个常数表,该表的起始地址为TBL,表中数据按伪指令中数据的顺序排列。又例如:

DB “howoldareyou?”,“A”,“#”

把引号中的字符按ASCII码存于连续的ROM中。MCS-51单片机程序设计全文共87页,当前为第14页。5.DW定义字命令

其功能是从指定的地址单元开始,定义若干个16位的数据字。命令格式:

[标号:]DW字数据表

一个数据字占两个字节。存放时,高8位在前(低地址),低8位在后(高地址)。例如:

WTBL: DW 1234H,279H,20H

按顺序存入12H,34H,02H,79H,00H,20H。MCS-51单片机程序设计全文共87页,当前为第15页。6.DS定义存储区命令其功能为从指定地址开始保留若干个字节的存储单元。命令格式:

[标号:]DS表达式

表达式的值决定了保留多少字节的存储单元。例如:

BASE:

DS 100

该语句将从BASE标号地址开始保留100个连续的存储单元。又例如:

ORG 8100 DS 08H

表示从8100H地址开始,保留8个连续的存储单元。MCS-51单片机程序设计全文共87页,当前为第16页。7.BIT位定义命令其功能是给字符名称赋以位地址。命令格式:

字符名称BIT位地址

其中位地址可以是绝对地址,也可以是符号地址即位符号名称。例如:

AQ BIT P1.7把P1.7的位地址赋给变量AQ,在其后的编程中AQ就可以作为P1.7使用。MCS-51单片机程序设计全文共87页,当前为第17页。1.2.1顺序程序设计

顺序程序的执行没有流程转移,全部按照程序语句的先后次序执行。顺序程序是最基本的程序结构之一,也是最简单的结构。例1.1两个三字节无符号数相减,设被减数放在片内RAM30H开始的单元中,减数放在40H开始的单元中,低字节在低地址单元中,高字节在高地址单元中,求两数之差并存入40H开始的单元中,借位存放在位寻址区的00H位中。

MOV R0,#30H ;被加数的低字节地址

MOV R1,#40H ;加数的低字节地址

CLR C MOV A,@R0 SUBB A,@R1 ;低字节相减

MOV @R1,A ;存低字节相减结果MCS-51单片机程序设计全文共87页,当前为第18页。

INC R0 INC R1 MOV A,@R0 SUBB A,@R1 ;中间字节带进位相减

MOV @R1,A ;存中间字节相减结果

INC R0 INC R1 MOV A,@R0 SUBB A,@R1 ;高字节带进位相减

MOV @R1,A ;存高字节相减结果

MOV 00H,C ;借位送00H保存MCS-51单片机程序设计全文共87页,当前为第19页。例1.2将R5、R4中双字节二进制数取补,结果仍放在R5、R4中。

DBCPL:MOV A,R5 ;取低字节

CPL A ;取反

ADD A,#1 ;加1 MOV R5,A ;存结果

MOV A,R4 ;取高字节

CPL A ;取反

ADDC A,#00H ;加进位

MOV R4,A ;存结果MCS-51单片机程序设计全文共87页,当前为第20页。1.2.2分支程序设计

程序的分支是通过条件转移指令实现的。根据条件对程序中的状态进行判断,满足条件则进行程序转移,否则按顺序执行。在MCS-51指令系统中,有多种条件转移指令,包括JZ、JNZ、CJNE、DJNZ以及位状态条件转移指令JC、JNC、JB、JNB、JBC等,使用这些指令,可以完成各种条件下的程序分支转移。分支程序可分为单分支程序和多分支程序。1.单分支程序单分支程序是只使用一次条件转移指令的分支程序。例1.3将一位十六进制数转换为ASCII码。设十六进制数在累加器A中,转换结果仍存在于A中。MCS-51单片机程序设计全文共87页,当前为第21页。转换算法:十六进制数的0至9,加30H即可转换为ASCII码,而0AH至0FH加37H才能转换为ASCII码。

ORG 1000H CJNE A,#0AH,NOEQ ;A的内容与0AH比较NOEQ: JC LP1 ;(C)=1即(A)<0AH转移

ADD A,#37H ;(A)≥0AH,加37H AJMPHERELP1: ADD A,#30H ;(A)<0AH,加30HHERE: SJMP HEREMCS-51单片机程序设计全文共87页,当前为第22页。例4.4已知X、Y均为8位二进制数,分别存在R0、R1中,试编制能实现下列符12.使用循环转移指令编写延时20ms、1s、1min的延时子程序。设单片机的晶振频率为6MHz。

+1 ,当X>0Y=0 ,当X=0

-1 ,当X<0程序流程框图如图1.1所示。MCS-51单片机程序设计全文共87页,当前为第23页。程序如下:

ORG 1000H MOV A,R0 CJNE A,#00H,MP1 ;若(R0)≠0跳转

MOV R1,#00H ;若(R0)=0,则0→R1 AJMP HERE ;MP1: JB ACC.7MP2 ;最高位为1,表明(R0)<0,跳转

MOV R1,#01H ;否则1→R1 LJMP HEREMP2: MOV R1,#0FFH ;(R0)<0,则-1→R1,-1的补码为FFHHERE: SJMP HERE MCS-51单片机程序设计全文共87页,当前为第24页。2.多分支程序在多分支程序中,因为可能的分支会有N个,若采用多条CJNE指令逐次比较,程序的执行效率会降低很多,特别是分支较多时。这时,一般采用跳转表的方法,通过两次转移来实现。假定分支序号的最大值是n,则分支转移结构如图1.2所示。MCS-51单片机程序设计全文共87页,当前为第25页。例4.5设内部RAM的30H单元有一个数,根据该数值的不同转移到不同的程序段进行处理,设数值的范围为0~10的无符号数。程序如下:

MOV A,30H ;取数

RL A ;乘以2以适应跳转表

MOV DPTR,#JMPTAB ;跳转表的首地址

JMP @A+DPTR ;转向跳转表JMPTAB: AJMP PROC00 ;转分支0 AJMP PROC01 ;转分支1

AJMP PROC10 ;转分支10PROC00:

…PROC10:MCS-51单片机程序设计全文共87页,当前为第26页。

使用跳转表最多可实现128路分支。由于AJMP指令的转移范围是2KB,因此分支处理程序的位置受到限制。若把跳转表中的AJMP指令改为LJMP指令,则分支程序可分布在整个64KB范围内,但要对分支数值进行乘3处理(LJMP是一个三字节指令,而AJMP是双字节指令)。相应程序如下:

MOV A,30H ;取数

RL A ;乘2 ADD A,30H ;再加一次,实现乘3 MOV DPTR,#JMPTAB ;跳转表的首地址

JMP @A+DPTR ;转向跳转表JMPTAB: LJMP PROC00 ;转分支0 LJMP PROC01 ;转分支1

LJMP PROC10 ;转分支10MCS-51单片机程序设计全文共87页,当前为第27页。

上面的例子还可采用查表法来实现。与跳转表不同,这个表的内容不是跳转指令,而是地址的偏移量,即各分支处理程序的入口地址与表的基地址的差值,因此也称为差值表。其程序如下:

MOV A,30H ;取数

MOV DPTR,#BRTAB ;差值表的首地址

MOVC A,@A+DPTR ;查表

JMP @A+DPTR ;转向跳转表BRTAB: DB BR0-BRTAB ;差值表

DB BR1-BRTAB

… DB BR10-BRTAB BR0:

BR10:

MCS-51单片机程序设计全文共87页,当前为第28页。

这种方法的技巧性较强,但由于表内的差值只限于8位,使分支程序的入口地址的分布范围受到限制,并且只能实现少于255个分支。例4.6假定有三个分支程序段,各分支程序段的功能依次是从内部RAM取数,从外部RAM低256B范围取数,从外部RAM64KB范围取数。并假定R0中存低8位地址,R1中存高8位地址,R3中存放分支序号值0~2。

MOV A,R3 ;分支序号值送A RL A ;乘以2以适应跳转表

MOV DPTR,#JMPTAB ;跳转表的首地址

JMP @A+DPTR ;转向跳转表MCS-51单片机程序设计全文共87页,当前为第29页。JMPTAB: AJMP PROC0 ;转分支0 AJMP PROC1 ;转分支1 AJMP PROC2 ;转分支2PROC0: MOV A,@R0 ;从内部RAM取数

SJMP PROCEPROC1: MOVX A,@R0 ;从外部RAM低256B范围取数

SJMP PROCEPROC2: MOV DPL,R0 MOV DPH,R1 MOVX A,@DPTR ;从外部RAM64KB范围取数PROCE: SJMP $MCS-51单片机程序设计全文共87页,当前为第30页。1.2.3循环程序设计

循环是为了重复执行一个程序段。与高级语言不同,汇编语言中没有专用的循环指令,但可以使用条件转移指令通过判断来控制循环是继续还是结束。通常循环结构的程序包含四个组成部分:①循环准备:设置循环次数、起始地址及结果初值等参数。②循环体:循环程序的主体,是要求重复执行的部分。③循环修改:修改循环次数及有关变量参数等。④循环控制部分:根据循环结束条件来判断是否结束循环。MCS-51单片机程序设计全文共87页,当前为第31页。例4.7将内部RAM的30H地址开始的80个数据,传送到外部RAM的2000H单元开始的区域。

ORG 2000HSTART:MOV R0,#30H ;源数据区首地址

MOV DPTR,#2000H ;目的数据区首地址

MOV R7,#80 ;循环次数LOOP: MOV A,@R0 ;取数据

MOVX @DPTR,A ;数据传送

INC R0 ;源地址加1 INC DPTR ;目的地址加1 DJNZ R7,LOOP ;循环控制

SJMP $ ;结束 MCS-51单片机程序设计全文共87页,当前为第32页。例4.8

外部RAM之间的数据传送程序。把外部RAM2000H开始单元中的数据传送到外部RAM3000H开始的单元中,数据个数在内部RAM的35H单元中。

ORG 1000H START: MOV DPTR,#2000H ;源数据区首地址

PUSH DPL ;源首址暂存堆栈

PUSH DPH MOV DPTR,#3000H ;目的数据区首地址

MOV R2,DPL ;目的首址暂存寄存器

MOV R3,DPHMCS-51单片机程序设计全文共87页,当前为第33页。LOOP: POP DPH ;取回源地址

POP DPL MOVX A,@DPTR ;取出数据

INC DPTR ;源地址加1 PUSH DPL ;源地址暂存堆栈

PUSH DPH MOV DPL,R2 ;取回目的地址

MOV DPH,R3 MOVX @DPTR,A ;目的地址加1 MOV R2,DPL ;目的地址暂存寄存器

MOV R3,DPH DJNZ 35H,LOOP ;没完,继续循环

SJMP $MCS-51单片机程序设计全文共87页,当前为第34页。

此例中,由于访问外部RAM只有一对以DPTR寄存器作为间址方式的指令,完成累加器与外部RAM之间的数据传送,源地址指针和目的地址指针都必须使用DPTR,所以程序中将源地址和目的地址分别保护,分时占用DPTR来传送数据。例4.9已知在内部RAM中,有一长度不超过32B的字符串,首地址为data,该字符串以回车符“CR”作为结束标志。要求统计此字符串的长度并将其结果存入内部RAM的length单元中。程序流程框图如图1.3所示。MCS-51单片机程序设计全文共87页,当前为第35页。MCS-51单片机程序设计全文共87页,当前为第36页。

因回车符“CR”的ASCII值为0DH,假设data为20H,length为1FH,则程序如下:

CR EQU 0DH data EQU 20H length EQU 1FH ORG 1000H MOV R0,#data-1 ;字符串首地址减1 MOV R7,#0FFH ;长度初值为-1CRLOP: INC R0 ;字符串地址加1 INC R7 ;长度加1MOV A,@R0 ;取字符

CJNE A,#CR,CRLOP ;与“CR”比较相等时结束

MOV length,R7 ;存字符长度

SJMP $MCS-51单片机程序设计全文共87页,当前为第37页。1.2.4子程序设计

子程序结构是汇编语言中一种重要的程序结构。在一个程序中经常会碰到反复执行某程序段的情况,如果重新书写这个程序段,会使程序变得冗长而杂乱。对此,可以采用子程序结构,即把重复的程序段编写为一个子程序,通过主程序调用它。这样不但可以提高编制和调试程序的效率,而且可以缩短程序长度,从而节省程序存储空间,但并不节省程序运行的时间。调用子程序的程序称为主程序,主程序和子程序之间的调用关系如图4.4所示。MCS-51单片机程序设计全文共87页,当前为第38页。

在MCS-51中,完成子程序调用的指令为ACALL和LCALL,完成子程序返回的指令为RET。在子程序调用时需要注意的两个问题:1.参数传递在子程序结构中,参数的传递要靠程序设计者自己安排数据的存放和选择工作单元。子程序参数的传递一般可采用下面的方法。(1)传递数据将数据通过工作寄存器R0~R7或者累加器A来传送。其具体过程是:在调用子程序前把数据送入寄存器中,子程序就对这些寄存器中的数据进行操作,子程序执行后,结果仍由寄存器送回。MCS-51单片机程序设计全文共87页,当前为第39页。(2)传递地址数据存放在数据存储器中,参数传递时只通过R0、R1、DPTR传递数据所存放的地址。调用结束时,结果就存放在数据存储器中,传送返回的也是寄存器中的地址。(3)通过堆栈传递参数在调用前,先把要传送的参数压入堆栈,进入子程序后,再将堆栈中的参数弹出到工作寄存器或其他内部RAM单元。在弹出参数时,应注意栈顶的两个字节数据是断点地址,不应误认为传递的参数。在子程序返回之前,应保证该两个字节数据仍处在栈顶位置,以便正确返回主程序。MCS-51单片机程序设计全文共87页,当前为第40页。2.现场保护进入子程序后,应注意除了要处理的参数数据和要传递回主程序的参数之外,有关的内部RAM单元和工作寄存器的内容,以及各标志的状态都不应因调用子程序而改变,这就存在现场保护问题。现场保护的方法是:在调用子程序前或一进入子程序,就将子程序中所使用的或会被改变内容的工作单元的内容压入堆栈;在子程序完成处理,将要返回前或一返回主程序后,就把堆栈中的数据弹出到原来的工作单元,恢复原来状态。对于所使用的工作寄存器的保护可用改变工作寄存器组的方法。MCS-51单片机程序设计全文共87页,当前为第41页。例1.10用子程序实现多字节BCD码的加法运算。设BCD十进制的两个加数分别放在内部RAM的30H单元、50H单元开始的区域,要求将和存放在30H开始的区域,数据长度均为8个字节。子程序:

MULTADD: CLR C ;清CYLOOP: MOV A,@R0 ;取被加数一个字节

ADDC A,@R1 ;与加数的一个字节相加

DA A ;十进制调整

MOV @R0,A ;暂存中间结果

INC R0 ;地址增1 INC R1 ;地址增1 DJNZ R2,LOOP ;次数减1,不为0转移

CLR AMCS-51单片机程序设计全文共87页,当前为第42页。

ADDC A,#00H ;处理最高位进位

MOV @R0,A ;存进位

RET ;子程序返回主程序:

ORG 2000HSTART: MOV R0,#30H ;被加数首地址

MOV R1,#50H ;加数首地址

MOV R2,#08H ;字节数

ACALL MULTADD ;调用子程序

SJMP $

此例中,通过R0、R1传递数据所存放的地址和通过R2传递数据来实现参数传递。汇编语言子程序的设计,在很多情况下还会出现通过堆栈传递参数和现场保护问题,这里不再一一举例。MCS-51单片机程序设计全文共87页,当前为第43页。1.3.1数制转换程序

在实际应用中,经常会遇到各种码制数据之间的相互转换问题。在单片机系统的输入、输出中,人们常常习惯使用十进制数;而在单片机内部数据存储和计算时,通常采用二进制数。因此经常需要作这两种进制数的转换程序。以下介绍二、十进制数之间的相互转换程序。例1.118位二进制数转换为3位BCD数。把累加器A中的8位无符号二进制整数(0~255)变换成3位BCD数字(双字节),百位数置于21H中,十位数和个位数合并置于20H中。MCS-51单片机程序设计全文共87页,当前为第44页。 MOV B,#100 ;除数100,用以提取百为数

DIV AB MOV 21H,A MOV A,#10 ;除数10,用以提取十位数

XCH A,B DIV AB SWAP A ADD A,B ;压缩BCD数字

MOV 20H,AMCS-51单片机程序设计全文共87页,当前为第45页。例1.1216位二进制数转换为5位BCD数。二进制数转换为BCD数除了采用例1.11的除法来实现外,还可以采用下面的方法。一个m位二进制数可以展开为多项式:B=bm-1×2m-1+bm-2×2m-2+……+b1×2+b0其中:bm-1、bm-2……b1、b0是二进制的各位值

B为该二进制数转换的十进制数即压缩BCD数 初值:B=0,i=m-1

循环体:B=B×2+bii=i-1

结束循环条件:i=0

该方法的转换算法如图4.5所示。MCS-51单片机程序设计全文共87页,当前为第46页。MCS-51单片机程序设计全文共87页,当前为第47页。

下面是使用这种方法实现的16位二进制数转换为5位BCD数的程序,该程序将BINDR地址开始的双字节二进制数转换为三字节压缩BCD数,存入BCDDR地址开始的单元中(低字节在前)。

BIN2BCD3: MOV R2,#16

;计数器初值设置为二进制数位数

MOV R3,#3 ;BCD数单元长度

MOV R0,#BCDDR ;BCD数单元首地址

CLR AB0: MOV @R0,A ;BCD数单元清零

INC R0 DJNZ R3,B0MCS-51单片机程序设计全文共87页,当前为第48页。B1: MOV R3,#2 ;二进制数单元长度

MOV R0,#BINDR;二进制数单元首地址

CLR AB3: MOV A,@R0 RLC A ;二进制数左移一位,最高位送CY MOV @R0,A INC R0 ;修改地址指针

DJNZ R3,B3 MOV R3,#3 MOV R0,#BCDDRB4: MOV A,@R0 ;BCD单元内容乘2加CY ADDC A,@R0 MCS-51单片机程序设计全文共87页,当前为第49页。

DA A MOV @R0,A INC R0 DJNZ R3,B4 DJNZ R2,B2 RETMCS-51单片机程序设计全文共87页,当前为第50页。1.3.2多字节无符号数的加减法运算

在MCS-51单片机指令系统中,设有单字节无符号数的加减指令:ADD、ADDC和SUBB。而在实际应用系统,时常需要进行多字节的算术运算。以下我们介绍多字节无符号数的加减法程序设计。例1.13编写四字节无符号数加法子程序,设被加数存放在内部RAM的33H、32H、31H、30H单元,加数放在43H、42H、41H、40H单元,结果将和存放在33H、32H、31H、30H单元中,最高位进位存放在34H单元中。数据高位存高地址。解题分析:根据题意要求列出算式如下:(33H)(32H)(31H)(30H)+(43H)(42H)(41H)(40H)(34H)(33H)(32H)(31H)(30H)MCS-51单片机程序设计全文共87页,当前为第51页。

由此算式可知,只要将各对应字节逐一相加即可。我们用循环结构程序解上述问题。

DADD: MOV R0,#30H ;被加数低位地址

MOV R1,#40H ;加数低位地址

MOV R7,#04H ;加法次数

CLR CLOOP: MOV A,@R0 ADDC A,@R1 MOV @R0,A INC R0 INC R1 DJNZ R7,LOOP

MCS-51单片机程序设计全文共87页,当前为第52页。 CLR A ADDC A,#00H ;A←0+(CY)+0 MOV @R0,A RETDADD子程序完成2个四字节无符号数加法程序设计。首先,最低位的相加,只要使用不含进位的加法指令ADD即可,为避免入口时CY位状态对本程序的影响,在进行最低位加法运算前要先清CY位;其次,最高位进位通过“ADDC A,#00H”指令获得,在ADDC指令执行前,先使A的内容为0,从而获得CY位的值。MCS-51单片机程序设计全文共87页,当前为第53页。例1.14编写N字节无符号数减法子程序。设被减数存放在内部RAM30H单元开始的连续地址,减数放在以40H单元开始的连续地址,结果将差存放在30H单元开始的连续地址,借位存放在00H位地址中。数据高位存地址。该题与上一题非常类似,除运算类型不同外,主要差别还表现在借位不是存放在一个字节单元内,而是一个位地址。

DSUB: MOV R0,#30H ;被减数低位地址

MOV R1,#40H ;减数低位地址

MOV R7,#N ;减法次数

CLR CLOOP: MOV A,@R0 SUBB A,@R1 MCS-51单片机程序设计全文共87页,当前为第54页。

MOV @R0,A INC R0 INC R1 DJNZ R7,LOOP MOV 00H,C ;借位存放

RETMCS-51单片机程序设计全文共87页,当前为第55页。1.3.3双字节的乘法运算MCS-51内部设有单字节的乘法指令(MLUAB),对于单字节的乘法运算,只要通过一条指令即可完成,而对于多字节数的乘法,必须通过程序实现。例1.15编两个双字节无符号数的乘法运算程序,被乘数和乘数分别存放于内部RAM的R2、R3单元和R6、R7单元(其中R2、R6为高位字节),将积存放于R4、R5、R6、R7单元中。根据题意可知:R4R5R6R7=R2R3×R6R7由于乘数和被乘数都是双字节数,所以必须进行4次乘法运算,得到4个部分积,假定部分积的高字节以“H”表示,部分积的低字节以“L”表示,双字节无符号数的乘法运算过程如图4.6所示。MCS-51单片机程序设计全文共87页,当前为第56页。MCS-51单片机程序设计全文共87页,当前为第57页。乘法程序如下:

DBMUL: MOV A,R3 MOV B,R7 MUL AB ;(R3)×(R7)(得第一次部分积)

XCH A,R7 ;R7←(R3R7L),A←(R7)

MOV R5,B ;R5←(R3R7H)

MOV B,R2 MUL AB ;(R2)×(R7)(得第二次部分积)

ADD A,R5 MOV R4,A ;R4←(R2R7L)+(R3R7H)

CLR A ADDC A,B MOV R5,A ;R5←(R2R7H)+(R2R7L

;+R3R7H时产生的进位) MCS-51单片机程序设计全文共87页,当前为第58页。

MOV A,R6 MOV B,R3 MUL AB ADD A,R4 XCH A,R6 ;R6←(R3R6L),A←(R6)

XCH A,B ;B←(R6),A←(R3R6H)

ADDC A,R5 MOV R5,A ;R5←(R3R6H)+(R3R6L+R4时 ;产生的进位)

MOV F0,C MOV A,R2 MUL AB ADD A,R5 MCS-51单片机程序设计全文共87页,当前为第59页。

MOV R5,A ;R5←(R2R6L)+(R5)

CLR A MOV ACC.0,C MOV C,F0 ADDC A,B MOV R4,A ;R4←(R2R6H)+(F0)+

;(R2R6L+R5时产生的进位)

RET

上面程序完成两个双字节无符号数的乘法运算。特别要注意的是,在运算过程中不能忘记对部分积相加产生进位时的处理。由于MCS-51单片机的除法指令也是单字节的,多字节的除法运算也必须以程序实现,这里不再举例。MCS-51单片机程序设计全文共87页,当前为第60页。1.3.4软件定时程序

在单片机的应用系统中,常有定时进行某些处理的需要,如定时检测、定时扫描等。定时功能除利用可编程定时器定时外,当定时时间较短或系统实时性要求不高的情况下,可利用一些“哑指令”,通过执行这些哑指令的固有延时来实现软件定时的目的。

所谓“哑指令”,是指对单片机内部状态无影响的指令,不影响存储单元的内容,也不影响标志位的状态,只是起到调节机器周期的作用,如NOP指令。下面就使用NOP指令说明软件定时程序的设计。1.单循环软件定时MCS-51单片机程序设计全文共87页,当前为第61页。例如: DELAY: MOV R7,#TIMELOOP: NOP NOP DJNZ R7,LOOP RETMCS-51单片机程序设计全文共87页,当前为第62页。

以上程序就是一个最简单的单循环程序。

NOP指令的机器周期为1;DJNZ指令的机器周期为2;

MOV指令的机器周期为1;RET指令的机器周期为1。因此执行这些指令总的机器周期数为:1+4×TIME+1,TIME为装入R7的一个立即数,取值范围由0~255变化。当TIME=0时,由于DJNZ指令是先减1再判零的操作,因此,LOOP循环体执行了256次,总执行机器周期数为:1+4×256+1=1026;当TIME=1时,LOOP循环体执行1次,总执行机器周期数为:1+4×1+1=6。所以,当单片机使用6MHz的晶体振荡器时,上面程序最大延时为:1026×2=2052(µs),最小延时为6×2=12(µs)。改变TIME的不同取值,可实现不同时间的软件定时。MCS-51单片机程序设计全文共87页,当前为第63页。2.多循环软件定时为了得到更长的软件定时,可以使用多个循环嵌套的方法。下面程序使用双重循环实现更长的定时时间。总执行机器周期:1+[(1+4×TIME1)+2]×TIME2+1当使用6MHz晶体振荡器时,最长定时时间为:{1+[(1+4×256)+2]×256+1}×2=(1+127×256+1)×2=65028(µs)

DELAY: MOV R6,#TIME2LOOP2: MOV R7,#TIME1LOOP1: NOP NOP DJNZ R7,LOOP1 DJNZ R6,LOOP2 RETMCS-51单片机程序设计全文共87页,当前为第64页。3.调整定时时间

上面两程序中除改变循环体执行次数,即改变TIME、TIME1、TIME2的值,可改变定时时间外,通过增减循环体内指令的数目也可改变定时时间。如在单循环定时程序循环体中,增加一条哑指令NOP,总执行机器周期数为:1+5×TIME。另外,还可以通过改变调用一个基本延时程序的次数,来实现不同定时时间的要求。例如,利用调用一个5ms的软件定时程序DELAY,来实现10ms、30ms等时间的延时。

MOV R5,#02HLOP1: LCALL DELAY DJNZ R5,LOP1 MOV R5,#06HLOP2: LCALL DELAY DJNZ R5,LOP2MCS-51单片机程序设计全文共87页,当前为第65页。

软件定时,只适合应用在短时间或实时性要求不高的场合。对于那些时间长的、实时性要求高的系统,需要采用可编程定时器定时的方式。详见第5章介绍。MCS-51单片机程序设计全文共87页,当前为第66页。1.3.5查表程序

预先将数据以表格的形式存放在存储器中,然后使用程序将其读出来,这种程序称为查表程序。查表程序是单片机系统一种常用的程序,它可以完成数据补偿、计算、转换等功能。在MCS-51系统中使用“MOVC A,@A+DPTR”和“MOVCA,@A+PC”两条指令实现查表功能。当表格长度不超过256字节时,可以利用

“MOVCA,@A+PC”指令。当表格长度>256时,必须使用“MOVCA,@A+DPTR”指令。当数据表格存放于外部RAM中时,就必须使用MOVX指令访问。例1.16表TAB1中存放一组ASCII码,试使用查表方法,将R2的内容(范围为0~0FH)转换为与其对应的ASCII码,并从P1口输出。按照查表的思路,程序如下:MCS-51单片机程序设计全文共87页,当前为第67页。TB1: MOV A,R2 ADD A,#3 ;加MOVC指令到TAB1表之间的偏移量

MOVC A,@A+PC MOV P1,A RETTAB1: DB 30H,31H,32H,33H DB 34H,35H,36H,37H DB 38H,39H,41H,42H DB 43H,44H,45H,46H

上面这个查表程序所查表的范围局限于表格长度不超过256个字节。如果表格长度范围超过255个字节,则必须使用“MOVCA,@A+DPTR”指令,并且应对DPH、DPL通过表首地址的运算求得。MCS-51单片机程序设计全文共87页,当前为第68页。

例1.17

在一个单片机控制系统中,其输入值x与对应的输出值y的关系为y=f(x),假设对应于x的y值已经存在表中,x的取值范围为(0~255)。设x在R2中,查询结果y值存放于R2R3中,请编程查表程序。解题分析:在本例中,对应于每个x,输出结果占用两个字节,所以必须先将x乘2,对查表地址进行修正。程序如下:LTB2: MOV DPTR,#TAB2MOV A,R2 CLR C RLC A ADD A,DPL MCS-51单片机程序设计全文共87页,当前为第69页。

MOV DPL,A CLR A

ADDC A,DPH MOV DPH,A ;DPTR←(R2)×2+(DPTR)

CLR A MOVC A,@A+DPTR ;查第一字节

MOV R2,A CLR A INC DPTR MOVC A,@A+DPTR ;查第二字节MCS-51单片机程序设计全文共87页,当前为第70页。

MOV R3,A RETTAB2: DW 01A0H,5679H,81B0H ;y值表

… DW AC23H,C600H,E456H

表TAB2可以放于64K程序存储器空间的任何地方。MCS-51单片机程序设计全文共87页,当前为第71页。1.3.6极值查找

极值查找就是在给定的数据区中找出最大值或最小值例1.18在MCS-51单片机内部RAM20H~27H单元中存放8个无符号数,编制一段程序找出其中的最大值并存入28H单元中。解题分析:先把20H单元的内容给A,然后将21H单元的内容与A的内容进行比较,如果(21H)>(A),则将21H的内容送给A,然后和下一个数进行比较,依次类推,最后A中的内容必定是最大值。程序流程如图4.7所示。MCS-51单片机程序设计全文共87页,当前为第72页。MCS-51单片机程序设计全文共87页,当前为第73页。程序如下:

MOV R0,#20H ;置数据存储区首单元地址

MOV R7,#07H ;置比较次数

MOV A,@R0 ;将20H单元的内容送ALOOP: INC R0 MOV B,@R0 ;取下一个数

CJNE A,B,NEXT NEXT: JNC NEXT1 ;若(A)<(B),则A←(B)

MOV A,BNEXT1: DJNZ R7,LOOP MOV 28H,A SJMP $MCS-51单片机程序设计全文共87页,当前为第74页。1.3.7数据检索

数据检索是在数据区中查找关键字的操作。将关键字与数据区中数据逐一进行比较,从而判断两者是否相等。例1.19在MCS-51单片机内部RAM20H~2FH地址的16个单元中,存放一批数据。试检索是否有与30H单元内容相等的数据,若检索成功,则将序号存入31H单元;否则将FFH存入31H单元。解题分析:检索开始时将31H单元初始化为FFH,若检索成功,则将序号存入31H。程序运行结束后,若31H内容为FFH,则表示未检索到;否则即表示已检索到,且31H的内容即为序号。程序设计如下:

MCS-51单片机程序设计全文共87页,当前为第75页。 MOV R0,#20H ;取数据区首地址

MOV R7,#10H ;取数据长度

MOV 31H,#0FFH ;31H初始化为FFH MOV R2,#00H ;序号初始化为00HLOOP2: MOV A,@R0 ;取数据区数据

CJNE A,30H,LOOP1 ;判断与关键字是否相等;不等转LOOP1 MOV 31H,R2 ;相等,则将R2中序号传送到 ;31H保存

SJMP $ ;完成等待LOOP1: INC R0 ;不等,数据区地址加1 INC R2 ;序号加1 DJNZ R7,LOOP2 ;检索未完成转LOOP2 SJMP $ ;检索完成等待

MCS-51单片机程序设计全文共87页,当前为第76页。1.3.8数据排序

数据排序的算法很多,常用的有插入排序法、冒泡法、快速排序法、选择排序法等。现以冒泡法为例,说明数据升序排序算法及编程实现。例1.20编制一段程序,采用冒泡排序法,将8051的片内RAM50H~57H的内容,以无符号数的形式从小到大进行排序,即程序运行后,50H单元的内容为最小,57H的内容为最大。冒泡排序法是一种相邻数互换的排序方法,因其过程类似水中的气泡上浮,故称冒泡法。执行时从前向后进行相邻数的比较,若数据的大小次序与要求的顺序不符(也就是逆序),就将这两个数交换,否则为正序不互换。假设是升序排列,则通过这种相邻数互换的排序方法,使小的数向前移,大的数向后移,如此从前向后进行一次冒泡,就会把最大的数换到最后,再进行一次冒泡,就会把次大的数排到倒数第二的位置上。如此下去,直到排序完成。MCS-51单片机程序设计全文共87页,当前为第77页。假设原始数据有顺序为:50、38、7、13、59、44、78、22。第一次冒泡的过程是:50.38.7.13.59.44.78.22(逆序、互换)38.50.7.13.59.44.78.22(逆序、互换)38.7.50.13.59.44.78.12(逆序、互换)38.7.13.50.59.44.78.22(正序、不互换)38.7.13.50.59.44.78.22(逆序、互换)38.7.13.50.44.59.78.22(正序、不互换)38.7.13.50.44.59.78.22(逆序、互换)38.7.13.50.44.59.22.78(第一次冒泡结束)MCS-51单片机程序设计全文共87页,当前为第78页。如此进行,各次冒泡的结果是:第一次冒泡:38.7.13.50.44.59.22.78第二次冒泡:7.13.38.44.50.22.59.78第三次冒抱:7.13.38.41.22.50.59.78第四次冒泡:7.13.38.22.44.50.59.78第五次冒泡:7.13.22.38.44.50.59.78第六次冒泡:7.13.22.38.44.50.59.78第七次冒泡:7.13.22.38.44.50.59.78

可以看出,冒泡排序到第五次已实际完成。针对上述冒泡排序过程,有两个问题需要说明:MCS-51单片

温馨提示

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

评论

0/150

提交评论