1、第第4 4章章 汇编语言与仿真系统汇编语言与仿真系统 计算机能够识别的是用二进制表示(书写时大多用十六计算机能够识别的是用二进制表示(书写时大多用十六进制)的指令,称为机器码,用机器码编写的程序称为机器进制)的指令,称为机器码,用机器码编写的程序称为机器语言,如:语言,如:“74H 03H”代表代表“MOV A,#03H”这条指令。机这条指令。机器码在书写、记忆、阅读时非常难,用来编写程序很不方便,器码在书写、记忆、阅读时非常难,用来编写程序很不方便,为了解决这一问题,人们采用一些助记符来代替机器码,用为了解决这一问题,人们采用一些助记符来代替机器码,用助记符书写的程序就是汇编语言。汇编语言的
2、缺点是可读性助记符书写的程序就是汇编语言。汇编语言的缺点是可读性比较差,只有熟悉单片机的指令系统,并具有一定的程序设比较差,只有熟悉单片机的指令系统,并具有一定的程序设计经验,才能设计出功能复杂的应用程序。高级语言计经验,才能设计出功能复杂的应用程序。高级语言(High-Level Language)是在汇编语言的基础上用自然语言)是在汇编语言的基础上用自然语言的语句来编写程序的,例如的语句来编写程序的,例如PL/M-51、Franklin C51、MBASIC 51等,程序可读性强,通用性好,适用于不熟悉单等,程序可读性强,通用性好,适用于不熟悉单片机指令系统的用户。但高级语言编写程序的缺点
3、是实时性片机指令系统的用户。但高级语言编写程序的缺点是实时性不高,结构不紧凑,编译后占用存储空间比较大,这一点在不高,结构不紧凑,编译后占用存储空间比较大,这一点在存储器有限的单片机应用系统中没有优势。存储器有限的单片机应用系统中没有优势。汇编语言的基本格式是:汇编语言的基本格式是:标号标号:操作码助记符操作码助记符源操作数源操作数,目的操作数目的操作数;注释;注释标号用在指令的前边,是用符号表示的地址,其后必须紧跟标号用在指令的前边,是用符号表示的地址,其后必须紧跟“:”,一般在程序中有特定用途的地方加标号,如转移目标,一般在程序中有特定用途的地方加标号,如转移目标执行指令的前面须加标号,用
4、执行指令的前面须加标号,用DB建立的表格的首个单元须建立的表格的首个单元须加标号,其他地方不必加标号;操作码助记符是每条指令都加标号,其他地方不必加标号;操作码助记符是每条指令都必须有的,代表指令的行为属性,不能省略;源操作数和目必须有的,代表指令的行为属性,不能省略;源操作数和目的操作数根据不同的指令有不同的结构,特殊指令两者可以的操作数根据不同的指令有不同的结构,特殊指令两者可以都没有(如都没有(如NOP);注释是对指令或程序功能的一种解释说);注释是对指令或程序功能的一种解释说明,属于用户自己的行为,勤做注释是一种好的习惯,其日明,属于用户自己的行为,勤做注释是一种好的习惯,其日后的回报
5、远远超出注释时的付出,需要注意的是前面必须加后的回报远远超出注释时的付出,需要注意的是前面必须加“;”。4.1 4.1 伪伪 指指 令令 伪指令不是单片机本身的指令,也没有对应的机器码,伪指令不是单片机本身的指令,也没有对应的机器码,不产生目标程序,不影响程序的执行,仅仅是能够帮助进行不产生目标程序,不影响程序的执行,仅仅是能够帮助进行汇编的一些指令,但在程序中加入伪指令后,可以使程序结汇编的一些指令,但在程序中加入伪指令后,可以使程序结构分明,调试时参数修改、地址调整等更加方便。不同版本构分明,调试时参数修改、地址调整等更加方便。不同版本的汇编语言,伪指令的符号和含义可能有所不同,但基本用的
6、汇编语言,伪指令的符号和含义可能有所不同,但基本用法是相似的,下面介绍几种常用的伪指令。法是相似的,下面介绍几种常用的伪指令。(1)汇编起始指令)汇编起始指令 ORG指令格式:指令格式:ORG nn该指令的作用是指明后面程序的起始地址,它总是出现在每该指令的作用是指明后面程序的起始地址,它总是出现在每段源程序的开始。其中段源程序的开始。其中nn为为 16 位地址,汇编时位地址,汇编时nn确定了此确定了此语句后面第一条指令的存放地址,此后的源程序就依次连续语句后面第一条指令的存放地址,此后的源程序就依次连续存放在以后的地址内,直到遇到另一个存放在以后的地址内,直到遇到另一个ORG指令为止。指令为
7、止。【例例4-1】ORG0050HMOVSP,60HMOVR0,2FH上述上述ORG伪指令说明其后面程序的目标代码在存储器中存放伪指令说明其后面程序的目标代码在存储器中存放的起始地址是的起始地址是0050H,即:,即:存储器地址存储器地址 目标程序目标程序0050H75 81 600053H78 2F(2)等值指令)等值指令EQU指令格式:字符名称指令格式:字符名称 EQU 数字或汇编符号数字或汇编符号功能:使指令中的字符名称等价于给定的数字或汇编符号。功能:使指令中的字符名称等价于给定的数字或汇编符号。使用等值指令可给程序的编制、调试、修改带来方便,如果使用等值指令可给程序的编制、调试、修改
8、带来方便,如果在程序中要多次使用某一地址,那么由在程序中要多次使用某一地址,那么由EQU指令将其赋值给指令将其赋值给一个字符名称,一旦需要对其进行变动,就只要改变一个字符名称,一旦需要对其进行变动,就只要改变EQU命命令后面的数字即可,而不需要对程序中涉及该地址的所有指令后面的数字即可,而不需要对程序中涉及该地址的所有指令逐句进行修改(人工逐句进行修改往往还会漏掉该修改的令逐句进行修改(人工逐句进行修改往往还会漏掉该修改的地方,从而引起程序单元使用混乱,产生严重后果)。但要地方,从而引起程序单元使用混乱,产生严重后果)。但要注意,由注意,由EQU等值的字符名称必须先赋值后使用,且在同一等值的字
9、符名称必须先赋值后使用,且在同一个源程序中,同一个标号只能赋值一次。个源程序中,同一个标号只能赋值一次。【例例4-2】8255_PA EQU 8000H即将即将8000H赋值给标号赋值给标号8255_PA,指令中可以这样写:,指令中可以这样写:MOV DPTR,#8255_PA (等同于(等同于 MOV DPTR,#8000H)在读写在读写8255_PA端口时实际上就在读写端口时实际上就在读写8000H端口,如果硬端口,如果硬件线路更改了,件线路更改了,8255_PA 的实际地址变为的实际地址变为6000H了,则只要了,则只要将上述将上述“8255_PA EQU 8000H”中的中的“8000
10、H”改成改成“6000H”即可,程序的其他地方不需调整了,这就是伪指令即可,程序的其他地方不需调整了,这就是伪指令带来的方便之处。带来的方便之处。(3)定义字节指令)定义字节指令 DB指令格式:指令格式:标号标号:DB8位二进制数表位二进制数表功能:把功能:把8位二进制数表依次存入从标号开始的连续的存储位二进制数表依次存入从标号开始的连续的存储单元中,单元中,8位二进制数表是字节常数或用逗号隔开的字节串,位二进制数表是字节常数或用逗号隔开的字节串,也可以是用引号括起来的也可以是用引号括起来的ASCII码字符串(一个码字符串(一个ASCII字符字符相当于一个字节),因此相当于一个字节),因此DB
11、又称建表指令。格式中标号可又称建表指令。格式中标号可有可无,若没有标号,则前面必须用有可无,若没有标号,则前面必须用ORG来定位,否则很难来定位,否则很难查表;有了标号,查表;有了标号,ORG可以省略,可以用标号来查表。可以省略,可以用标号来查表。【例例4-3】ORG1000HTAB:DB56H,45,A,10010101BDB45H,66HORG伪指令指定了标号伪指令指定了标号TAB的地址为的地址为1000H,而,而DB伪指令伪指令是将其后的二进制数表是将其后的二进制数表56H、45、41H、95H依次存放在依次存放在1000H、1001H、1002H、1003H这这4个连续单元之中。个连续
12、单元之中。(4)定义字指令)定义字指令 W指令格式:指令格式:标号标号:DW 16 位数据表位数据表该指令的功能与该指令的功能与DB相似,区别仅在于从指定地址开始存放相似,区别仅在于从指定地址开始存放的是指令中的的是指令中的16位数据,而不是字节串。每个位数据,而不是字节串。每个16位数据要占位数据要占两个存储单元,高两个存储单元,高8位先存,低位先存,低8位后存,这和位后存,这和MCS-51指令指令中的中的16位数据存放顺序是一致的。位数据存放顺序是一致的。(5)位地址定义指令)位地址定义指令 BIT指令格式:字符名称指令格式:字符名称 BIT 位地址位地址该伪指令的功能是将位地址赋予该伪指
13、令的功能是将位地址赋予BIT前面的字符,经赋值后前面的字符,经赋值后可用该字符代替可用该字符代替BIT后面的位地址。例如:后面的位地址。例如:【例例4-4】OUT_1 BIT P1.0OUT_2 BIT P1.1例例4-4定义了两个输出端定义了两个输出端OUT_1和和OUT_2,它们实际对应的,它们实际对应的是是P1.0和和P1.1,在程序中就可以把,在程序中就可以把OUT_1和和OUT_2作为位地作为位地址来使用。上述址来使用。上述“BIT”可以换成可以换成“EQU”。(6)汇编结束指令)汇编结束指令 END指令格式:指令格式:END功能:提供汇编结束标志。汇编程序遇到功能:提供汇编结束标志
14、。汇编程序遇到“END”后就停止后就停止汇编,对汇编,对“END”以后的语句不予处理(以后的语句不予处理(END后的语句视作后的语句视作没有),故没有),故“END”应放在程序的结束处。请切勿把它当作应放在程序的结束处。请切勿把它当作程序运行结束命令!程序运行结束命令!4.2 4.2 汇编语言程序设计汇编语言程序设计 程序设计是学习单片机的重要内容,因为单片机系统都程序设计是学习单片机的重要内容,因为单片机系统都是在软件的控制下完成规定的动作或功能,所以软件是硬件是在软件的控制下完成规定的动作或功能,所以软件是硬件的灵魂。程序设计也是单片机教与学的难点,有些同学因为的灵魂。程序设计也是单片机教
15、与学的难点,有些同学因为不会程序设计而最终无法跨入单片机应用的大门。要学好程不会程序设计而最终无法跨入单片机应用的大门。要学好程序设计,除了应熟悉、掌握常用的指令外,还必须多看(对序设计,除了应熟悉、掌握常用的指令外,还必须多看(对程序设计来说,模仿往往是学习的起步,不但要看程序,更程序设计来说,模仿往往是学习的起步,不但要看程序,更要看流程图)、多练(练习是基本知识的消化、巩固过程和要看流程图)、多练(练习是基本知识的消化、巩固过程和编程技巧的领悟途径)、多总结(如循环程序等很有规律,编程技巧的领悟途径)、多总结(如循环程序等很有规律,总结出规律后,几乎可以一劳永逸地采用)。当然程序也并总结
16、出规律后,几乎可以一劳永逸地采用)。当然程序也并非都由自己亲手编制,现在的网络资源非常丰富,利用网络非都由自己亲手编制,现在的网络资源非常丰富,利用网络可以整合众人的智慧,互相可以整合众人的智慧,互相“借用借用”别人的别人的“劳动成果劳动成果”(比如现成的子程序)也是一种方法或途径。(比如现成的子程序)也是一种方法或途径。4.2.1 4.2.1 简单程序设计简单程序设计 图图4-1 顺序结构顺序结构:简单程序也就是顺序结构的程序,如图简单程序也就是顺序结构的程序,如图4-1所示,其所示,其特点是按指令的排列顺序一条条地执行,直到全部特点是按指令的排列顺序一条条地执行,直到全部指令执行完毕为止。
17、在一个复杂的程序中,总可以指令执行完毕为止。在一个复杂的程序中,总可以分解成若干顺序程序段,所以顺序结构是最简单、分解成若干顺序程序段,所以顺序结构是最简单、最基本的程序结构。本节通过实例介绍几个常用的最基本的程序结构。本节通过实例介绍几个常用的简单程序的设计方法。简单程序的设计方法。【例例4-5】4字节(双字)无符号数加法:将内部字节(双字)无符号数加法:将内部RAM 20H开始的开始的4个单元中存放的个单元中存放的4字节十六进制数字节十六进制数(20H高位,高位,23H低位)和内部低位)和内部RAM 30H单元开始单元开始的的4个单元中存放的个单元中存放的4字节十六进制数相加,结果存字节十
18、六进制数相加,结果存放到放到40H开始的单元中。开始的单元中。首先,根据题意可以画出加法过程的示意图(如图4-2所示)。图图4-2 加法过程示意图加法过程示意图其次,由加法规则可知:23H单元与33H单元相加用指令“ADD”外,其余单元都用“ADDC”。程序如下:说明:说明:(1)若是)若是BCD码加法,在上述的码加法,在上述的“ADD”或或“ADDC”指令指令后紧跟后紧跟“DA A”即可。即可。(2)上述程序中最后的)上述程序中最后的“SJMP$”必须要加,这条指令是让必须要加,这条指令是让程序停止往下执行,相当于程序停止往下执行,相当于“原地踏步原地踏步”,因为,因为“END”并并非程序停
19、止的命令。非程序停止的命令。【例例4-6】数据合并程序:设在数据合并程序:设在20H和和21H单元中各有一个单元中各有一个8位数据位数据(20H)=x7x6x5x4x3x2x1x0(2lH)=y7y6y5y4y3y2y1y0现在要从现在要从20H单元中取出低单元中取出低4位,从位,从21H单元中取出高单元中取出高4位完位完成拼装并送成拼装并送22H单元保存,数据要求如下:单元保存,数据要求如下:(22H)=y3y2y1y0 x3x2x1x0数据的拆、拼常常利用逻辑指令数据的拆、拼常常利用逻辑指令ANL、ORL来完成,来完成,“拆拆”是利用是利用ANL的屏蔽功能的屏蔽功能“与与0得得0,与,与1
20、不变不变”的性质来实现,的性质来实现,“拼拼”是利用是利用“或或0不变不变”的性质来实现,高、低位的交换的性质来实现,高、低位的交换用用SWAP 指令,程序清单如下:指令,程序清单如下:ORG0000HSJMP STARTORG0050HSTART:MOVA,20H;将;将x7x0传送到传送到AANLA,#00001111 B;将高;将高4位屏蔽掉,得到位屏蔽掉,得到0000 x3x2x1x0MOV22H,A;将;将0000 x3x2x1x0暂存到暂存到22HMOVA,21H;将;将y7y6y5y4y3y2y1y0传传送到送到ASWAP A;将高、低;将高、低4位互换,变位互换,变成成y3y2
21、y1y0y7y6y5y4yANLA,#11110000 B;将低;将低4位屏蔽掉,得到位屏蔽掉,得到y3y2y1y0000ORLA,22H;0000 x3x2x1x0 和和y3y2y1y0000 相相或或MOV22H,A;将结果保存到;将结果保存到 22HSJMP$END上面两个程序中的开头用了上面两个程序中的开头用了ORG程序定位指令,尽管在这样程序定位指令,尽管在这样简单的程序中省掉也没什么影响,但对于养成规范的编程习简单的程序中省掉也没什么影响,但对于养成规范的编程习惯是有好处的,否则看到一个具体应用程序时就会无所适从,惯是有好处的,否则看到一个具体应用程序时就会无所适从,同时也与第同时
22、也与第2.3节关于程序存储器的叙述相吻合。节关于程序存储器的叙述相吻合。【例例4-7】双字节数依次左移程序:将双字节数依次左移程序:将20H(高位)、(高位)、21H(低位)组成的双字节数向左移一次。(低位)组成的双字节数向左移一次。根据题意可表示成图根据题意可表示成图4-3,先用,先用RLC指令将指令将21H单元左移(实单元左移(实际必须将际必须将21H单元送到单元送到A 后才能用后才能用RLC指令)一次,此时指令)一次,此时21H单元的最高位进入单元的最高位进入Cy,最低位暂时由原来的,最低位暂时由原来的Cy填入(最填入(最后必须用后必须用20H单元的最高位来补);然后再用单元的最高位来补
23、);然后再用RLC指令将指令将20H单元左移,此时单元左移,此时Cy(原来(原来21H的最高位)进入了的最高位)进入了21H的的最低位,最低位,21H的最高位则进入的最高位则进入Cy,用此,用此Cy“补补”到到20H单元单元最低位即可完成双字节数的移位。最低位即可完成双字节数的移位。图4-3 双字节数依次左移示意图程序如下:程序如下:ORG0000HSJMP STARTORG0050HSTART:MOVA,20H;20H传送到传送到ARLCA;20H带带Cy左移左移MOVA,21H;21H传送到传送到A RLCA;21H带带Cy左移左移MOV20H,C;注意,这里的;注意,这里的20H是是20
24、H单元单元的的D0位地址位地址SJMP$END【例例4-8】将将30H单元中的十六进制数转换为三位单元中的十六进制数转换为三位BCD码,分码,分别存放在别存放在22H、21H、20H中,如中,如(30H)=FFH,则结果,则结果(22H)=02H,(21H)=05H,(20H)=05H,即十六进制的,即十六进制的“FF”等于十进制的等于十进制的“255”。十六进制到十六进制到BCD码的转换,通常是用除法将码的转换,通常是用除法将“百位百位”、“十十位位”、“个位个位”逐一分离,对于位数更多的十六进制转换也逐一分离,对于位数更多的十六进制转换也是如此,由于没有直接的双字节除法指令,所以除法用减法
25、是如此,由于没有直接的双字节除法指令,所以除法用减法来实现,因为涉及判断转移(属于分支程序范畴),这里仅来实现,因为涉及判断转移(属于分支程序范畴),这里仅作说明,用户可以从相关资料或网站中获取。本题程序如下:作说明,用户可以从相关资料或网站中获取。本题程序如下:ORG0000HSJMP STARTORG0030HSTART:MOVA,30H;30H传送到传送到AMOVB,#64H;相;相当于当于100DIVAB;原;原来数据除以来数据除以100MOV22H,A;百位数据送;百位数据送22H单元单元MOVA,B;取回余数;取回余数MOVB,#10DIVAB;除以;除以10MOV21H,A;十位
26、数据送;十位数据送21H单元单元MOV20H,B;余数即为个位数,送;余数即为个位数,送20HSJMP$END4.2.2 4.2.2 分支程序设计分支程序设计在实际系统尤其是自动控制中,需要根据系统所处的不同状在实际系统尤其是自动控制中,需要根据系统所处的不同状态进行分别处理,执行不同的程序,这种结构的程序称为分态进行分别处理,执行不同的程序,这种结构的程序称为分支程序。分支结构有两种基本形式,如图支程序。分支结构有两种基本形式,如图4-4(a)、()、(b)所示。所示。【例例4-9】两个无符号数大小的比较:有两个无符号数分别两个无符号数大小的比较:有两个无符号数分别放在放在30H和和31H单
27、元,若单元,若(30H)(31H),则,则P1.0管脚连接的管脚连接的LED发光(设发光(设P口接有口接有LED,“0”点亮);若点亮);若(30H)(31H),则则P1.1管脚连接的管脚连接的LED发光。发光。在系统自动控制中,一般是两种情况:一种是开关量的判断,在系统自动控制中,一般是两种情况:一种是开关量的判断,并由此作出一种行为抉择;另一种是数据量的大小判断,根并由此作出一种行为抉择;另一种是数据量的大小判断,根据大小、相等来选择相应的动作。本题是属于数据量的判断。据大小、相等来选择相应的动作。本题是属于数据量的判断。数据大小的比较常用以下两种方法:一种是两数相减(放在数据大小的比较常
28、用以下两种方法:一种是两数相减(放在A中的数据将被破坏),然后查看中的数据将被破坏),然后查看Cy,程序流程如图,程序流程如图4-5所示。所示。另外一种是直接用比较转移指令(另外一种是直接用比较转移指令(A中数据不被破坏),然中数据不被破坏),然后查看后查看Cy。图4-4 分支程序图4-5 数据判断流程图程序如下:程序如下:X DATA 30H;地址赋值伪指令;地址赋值伪指令DATAY DATA31HORG0000HSJMPSTORG0030HST:MOVA,X;(X)ACLRC;Cy=0SUBBA,Y;带借位减法,;带借位减法,A-(Y)-CyAJCOUT1;Cy=1,转移到,转移到OUT1
29、CLRP1.0;(30H)(31H),点,点P1.0上上LEDSJMPSTOP;跳转到结束等待;跳转到结束等待OUT1:CLRP1.1;(30H)(31H),点,点P1.1上上LEDSTOP:SJMP$END【例例4-10】已知电路如图已知电路如图4-6所示,要求实现:所示,要求实现:(1)K0单独按下,只有红灯(单独按下,只有红灯(R)亮)亮(2)K1单独按下,只有绿灯(单独按下,只有绿灯(G)亮)亮(3)K0、K1均按下,红、绿、黄灯(均按下,红、绿、黄灯(Y)全亮)全亮(4)其余情况黄灯亮)其余情况黄灯亮123456ABCD654321DCBATitleNumberRevisionSiz
30、eBDate:6-Feb-2006 Sheet of File:D:教材编写图纸.DdbDrawn By:R1R2R3R4R5RGYK0K15V5VP1.0P1.1P1.2P1.3P1.4图4-6 信号灯电路本例为开关量(状态)的判断,流程如图本例为开关量(状态)的判断,流程如图4-7所示。所示。图4-7 信号灯流程图程序如下:程序如下:ORG0000HSJMP STARTORG0030HSTART:MOVP1,#0FFH;设置;设置P1.0、P1.1为输入方式,红、绿、黄灯灭为输入方式,红、绿、黄灯灭LOOP:JNBP1.0,K1;查;查P1.0是否为是否为0 JNBP1.1,GREENCL
31、RP1.4;亮黄灯,灭红、绿灯;亮黄灯,灭红、绿灯SETB P1.2SETB P1.3SJMP LOOPGREEN:CLRP1.3;亮绿灯,灭红、;亮绿灯,灭红、黄灯黄灯SETB P1.2SETB P1.4SJMP LOOPK1:JNBP1.1,ALLRED:CLRP1.2;亮红灯,灭绿、黄灯;亮红灯,灭绿、黄灯SETB P1.3SETB P1.4SJMP LOOPALL:CLRP1.2;红、绿、黄灯全亮;红、绿、黄灯全亮CLRP1.3 CLRP1.4 SJMP LOOP END4.2.3 4.2.3 循环程序设计循环程序设计 在应用系统中,往往需要反复执行某种动作,比如对连在应用系统中,往往
32、需要反复执行某种动作,比如对连续的一批内存单元做同样的初始化,又如将内存中成批数据续的一批内存单元做同样的初始化,又如将内存中成批数据送到外部端口等,这种任务的特点是有送到外部端口等,这种任务的特点是有“批量批量”且动作行为且动作行为“重复重复”,采用循环结构可以解决此类问题,并使程序变得,采用循环结构可以解决此类问题,并使程序变得高效简单。循环结构有两种组织形式,分别如图高效简单。循环结构有两种组织形式,分别如图4-8的(的(a)、)、(b)所示,其中初值一般包括数据区的首地址、循环次数)所示,其中初值一般包括数据区的首地址、循环次数等。循环体是等。循环体是“重复重复”执行的动作描述,一般采
33、用间接寻址。执行的动作描述,一般采用间接寻址。(a)(b)图4-8 循环程序流程【例例4-11】将内部将内部RAM 20H开始的开始的30个数据送到外部个数据送到外部RAM 2000H开始的各单元。开始的各单元。本题是典型的数据批量传送例子,相当于计算机操作中的本题是典型的数据批量传送例子,相当于计算机操作中的“块复制块复制”。程序如下:。程序如下:【例例4-12】试编写统计数据区长度的程序,设数据区从片内试编写统计数据区长度的程序,设数据区从片内RAM 20H单元开始,以数据值为单元开始,以数据值为0为结束,统计结果存入为结束,统计结果存入1FH单元。单元。ORG0000H SJMP STA
34、RT ORG0030HSTART:MOVR0,#20H;内部数据区首地址,用R0或R1 MOV1FH,#0;统计单元初始化0LOOP:MOVA,R0;取源数据,要用间接寻址 JZSTOP;若单元中数据为0,则表示数据结束 INC1FH;统计+1 INCR0;单元地址+1 SJMP LOOPSTOP:SJMP$ENDDELAY:MOVR6,#n1DL1:MOVR5,#n2DL2:NOPNOPDJNZ R5,DL2DJNZ R6,DL1SJMP$【例例4-13】设计时间为设计时间为t的延时程序。的延时程序。循环程序的一个用处就是设计延时程序,在循环程序的一个用处就是设计延时程序,在LED动态扫描和
35、动态扫描和键盘扫描键盘扫描“消抖消抖”中经常要用到,一般的延时用双重循环就中经常要用到,一般的延时用双重循环就可以了。以下是双重循环延时的基本程序:可以了。以下是双重循环延时的基本程序:在上述程序中,在上述程序中,“MOV R6,#n1”运行了运行了1次,次,“MOV R5,#n2”和和“DJNZ R6,DL1”各运行了各运行了n1次,次,“NOP NOP DJNZ R5,DL2”运行了运行了n1n2次(每次时间为次(每次时间为4T),因为每),因为每条指令的运行时间(即指令周期)是已知的,所以上述程序条指令的运行时间(即指令周期)是已知的,所以上述程序运行的时间是能够精确计算出来的。在要求不
36、高的情况下,运行的时间是能够精确计算出来的。在要求不高的情况下,上述时间近似为(上述时间近似为(n2 n1越大,误差越小):越大,误差越小):t 4Tn1n2时间的长短除了与时间的长短除了与n1、n2有关之外,还可以用增加或减少有关之外,还可以用增加或减少“NOP”对时间进行调整。延时程序常常以子程序形式出现,对时间进行调整。延时程序常常以子程序形式出现,只要将末句只要将末句“SJMP$”改为改为“RET”即可。即可。4.2.4 4.2.4 查表程序设计查表程序设计在单片机汇编语言程序设计中,查表程序的应用非常广泛,在在单片机汇编语言程序设计中,查表程序的应用非常广泛,在LED、LCD显示程序
37、设计中经常用到查表程序,另外可以将单显示程序设计中经常用到查表程序,另外可以将单片机无法实现的一些计算(如函数的计算)直接将结果存到内片机无法实现的一些计算(如函数的计算)直接将结果存到内部,需要时一一部,需要时一一“对号对号”读取就可以了。读取就可以了。【例例4-14】在程序中定义一个在程序中定义一个09的平方表,利用查表指令找的平方表,利用查表指令找出累加器出累加器A=05H的平方值。的平方值。ORG0000HMOVDPTR,#TABLE;表首地址;表首地址DPTR(数据指针)(数据指针)MOVA,#05;05AMOVCA,A+DPTR;查表指令,;查表指令,25A,A=19HSJMP$;
38、程序暂停;程序暂停TABLE:DB0,1,4,9,16,25,36,49,64,81;定义;定义09平方表平方表END 有关查表程序的其他应用可以参考其他资料,有关查表程序的其他应用可以参考其他资料,LED显示显示扫描时,从扫描时,从BCD转到字型码的查表程序可以参考第转到字型码的查表程序可以参考第8章,在章,在这里大家要理解查表的原理:查表实际上是人为安排的一种这里大家要理解查表的原理:查表实际上是人为安排的一种巧合,程序本身没有在巧合,程序本身没有在“查查”,“对号入座对号入座”是查表程序设是查表程序设计的基本思想。计的基本思想。4.2.5 4.2.5 散转程序设计散转程序设计 在上面的分
39、支程序中可以看到,它是在两种可能的情况在上面的分支程序中可以看到,它是在两种可能的情况下作出某种选择,非此即彼,而在实际应用中,常常会遇到下作出某种选择,非此即彼,而在实际应用中,常常会遇到需要从两个以上的条件中选择一个,这种程序称为多分支程需要从两个以上的条件中选择一个,这种程序称为多分支程序或散转程序,其结构如图序或散转程序,其结构如图4-9所示。所示。MCS-51单片机指令系单片机指令系统中专门提供了散转指令,利用散转指令可以方便地解决看统中专门提供了散转指令,利用散转指令可以方便地解决看似复杂的问题,请看下面的例子。似复杂的问题,请看下面的例子。图4-9 散转程序结构【例4-15】编写
40、要求根据R1的内容转向各个操作程序的程序。即当:(R1)=0时,转向时,转向GO_0(R1)=1时,转向时,转向GO_1(R1)=n时,转向时,转向GO_n解:程序清单如下:解:程序清单如下:MOV A,R1RLA;分支序号值乘;分支序号值乘2,若下面,若下面转移指令用转移指令用LJMP则要乘则要乘3MOV DPTR,#FIRST;转移指令表首址;转移指令表首址JMPA+DPTR;转向形成的散转地址;转向形成的散转地址FIRST:AJMP GO_0;转移指令表;转移指令表AJMP GO_1AJMP GO_n 有关散转的过程可以参考散转指令有关散转的过程可以参考散转指令“JMP A+DPTR”的
41、说明,散转常用在键盘的程序的功能处理,如键盘号为的说明,散转常用在键盘的程序的功能处理,如键盘号为0时,转向时,转向GO _0,键盘号为,键盘号为1时,转向时,转向GO_1等。等。另外,散转程序也可以连续用另外,散转程序也可以连续用“CJNE”指令来实现,只是程指令来实现,只是程序显得序显得“肥肥”,不够精简。当然散转程序也有约束条件,即,不够精简。当然散转程序也有约束条件,即只能对有规律的数据进行散转。如在例只能对有规律的数据进行散转。如在例4-15中,若将某个数中,若将某个数据改变,散转时就会走错路,而用据改变,散转时就会走错路,而用“CJNE”却不会有这样的却不会有这样的条件约束。从这个
42、角度上来说,指令不必每条都会用,用什条件约束。从这个角度上来说,指令不必每条都会用,用什么样的指令,最后取决于编程者的习惯。当然高效率的程序么样的指令,最后取决于编程者的习惯。当然高效率的程序还是要提倡的。例还是要提倡的。例4-15用用“CJNE”来实现可以表示如下。来实现可以表示如下。MOV A,R1;取出数据;取出数据CJNE A,#00 H,NEXT1;是否为;是否为00H,否,继续,否,继续比较比较AJMP GO_0NEXT1:CJNE A,#01H,NEXT2;是否为;是否为01H,否,继续比较,否,继续比较AJMP GO_1NEXT2:CJNE A,#02H,NEXT3;是否为;是
43、否为02H,否,继续比较,否,继续比较AJMP GO_1NEXTn:CJNE A,#0nH,OTHER;是否为;是否为0nH,否,其他或停止,否,其他或停止AJMP GO_n4.2.6 4.2.6 子程序程序设计子程序程序设计在解决实际问题时,经常会遇到一个程序中多次使用同一个在解决实际问题时,经常会遇到一个程序中多次使用同一个程序段,例如延时程序、查表程序、算术运算程序等功能相程序段,例如延时程序、查表程序、算术运算程序等功能相对独立的程序段。对独立的程序段。在实际的单片机应用系统软件设计中,为了程序结构更加清在实际的单片机应用系统软件设计中,为了程序结构更加清晰,易于设计,易于修改,增强程
44、序可读性,同时便于程序晰,易于设计,易于修改,增强程序可读性,同时便于程序的移植,基本上都要使用子程序结构。子程序作为一个具有的移植,基本上都要使用子程序结构。子程序作为一个具有独立功能的程序段,编程时须遵循以下原则:独立功能的程序段,编程时须遵循以下原则:(1)子程序的第一条指令必须有标号,以明确子程序入口)子程序的第一条指令必须有标号,以明确子程序入口地址。地址。(2)以返回指令)以返回指令“RET”结束子程序。结束子程序。图图4-10是主程序中调用子程序(名为是主程序中调用子程序(名为DELAY)的示意图,图)的示意图,图中数字表示程序执行顺序。子程序举例此处省略。中数字表示程序执行顺序
45、。子程序举例此处省略。图4-10 子程序调用示意图4.3 4.3 汇编语言程序的仿真与调试汇编语言程序的仿真与调试 在学习汇编语言程序设计的过程中,程序是否能实现最在学习汇编语言程序设计的过程中,程序是否能实现最终功能是我们所关心的,也是系统设计必须面对的一个问题。终功能是我们所关心的,也是系统设计必须面对的一个问题。如果不能完成预定的任务,那么是哪一步出错了?如何来检如果不能完成预定的任务,那么是哪一步出错了?如何来检查程序并最终改正程序?这些工作就是程序的调试,对于掌查程序并最终改正程序?这些工作就是程序的调试,对于掌握单片机技术来说,程序的调试是非常重要的,因为我们不握单片机技术来说,程
46、序的调试是非常重要的,因为我们不能保证不犯错误。能保证不犯错误。目前用于目前用于MCS-51调试的软件平台很多,购买仿真设备的时调试的软件平台很多,购买仿真设备的时候都会获得厂方提供的软件平台。这里简单介绍使用较广的候都会获得厂方提供的软件平台。这里简单介绍使用较广的MedWin中文版调试平台,详细功能请参考使用手册。中文版调试平台,详细功能请参考使用手册。(1)启动)启动MedWin。启动后出现如图。启动后出现如图4-11所示的界面。如果所示的界面。如果不需要调试硬件,就单击不需要调试硬件,就单击“模拟仿真模拟仿真”按钮,如果要调试硬按钮,如果要调试硬件,则单击件,则单击“仿真器仿真器”按钮
47、,当然这时需要电脑与仿真器相按钮,当然这时需要电脑与仿真器相连,仿真器和用户系统板连接。连,仿真器和用户系统板连接。图4-11 启动窗口纯软件模拟用仿真器运行(2)单击)单击“模拟仿真模拟仿真”按钮进入按钮进入MedWin的工作环境,如图的工作环境,如图4-12所示。所示。(3)打开或新建一个源文件。这里需要说明的是早先)打开或新建一个源文件。这里需要说明的是早先MedWin版本不支持中文名的文件,如文件名为版本不支持中文名的文件,如文件名为“练练习习.ASM”,则即使程序正确也没法继续调试。后来的,则即使程序正确也没法继续调试。后来的2.39版版本支持中文名。本支持中文名。(4)汇编。在)汇
48、编。在“项目管理项目管理”菜单中单击菜单中单击“编译编译/汇编汇编”命令、命令、按下、用快捷键按下、用快捷键Ctrl+F7或直接单击或直接单击“编译编译/汇编汇编”按钮,对按钮,对程序进行汇编,在生成机器码的同时还能检查程序的基本语程序进行汇编,在生成机器码的同时还能检查程序的基本语法问题,只有这一步通过了,才能继续进入下一步。图法问题,只有这一步通过了,才能继续进入下一步。图4-13是是“汇编汇编”出错后的提示,双击错误信息栏的语句,在源程出错后的提示,双击错误信息栏的语句,在源程序窗口中以红色显示对应的错误语句。序窗口中以红色显示对应的错误语句。图4-12 MedWin界面工作区菜单及按钮
49、错误提示对应错误的指令图4-13 汇编出错后的提示(5)装入代码。在)装入代码。在“项目管理项目管理”菜单中单击菜单中单击“产生代码并产生代码并装入装入”命令、按下快捷键命令、按下快捷键Ctrl+F8或直接单击或直接单击“产生代码并产生代码并装入装入”按钮将程序装入模拟系统,代码装入后,屏幕出现调按钮将程序装入模拟系统,代码装入后,屏幕出现调试的工具(菜单下的调试命令也由灰色变成可用),界面如试的工具(菜单下的调试命令也由灰色变成可用),界面如图图4-14所示。所示。(6)调试。调试是利用仿真平台提供的工具和资源对程序)调试。调试是利用仿真平台提供的工具和资源对程序进行模拟运行,通过对单元结果
50、的查看和现象(结果)的观进行模拟运行,通过对单元结果的查看和现象(结果)的观测,确定程序运行是否正常,对不正常的程序进行故障定位,测,确定程序运行是否正常,对不正常的程序进行故障定位,直到查出问题。下面介绍调试中常用的几个过程或方法。直到查出问题。下面介绍调试中常用的几个过程或方法。运行程序运行程序单步运行:又称指令跟踪,快捷键是单步运行:又称指令跟踪,快捷键是F7,每按一次就执行一,每按一次就执行一条指令,适合于精确定位故障语句的场合,结合下面的过程条指令,适合于精确定位故障语句的场合,结合下面的过程查看就能找出程序的错误所在。查看就能找出程序的错误所在。新出现调试工具观测窗口程序窗口图4-