1第4章51汇编语言程序设计122第4章目录4.1汇编语言程序设计概述4.1.1单片机编程语言4.1.2汇编语言语句和格式4.1.3伪指令4.2汇编语言源程序的汇编4.2.1手工汇编4.2.2机器汇编34.351汇编语言程序设计举例4.3.1子程序的设计4.3.2查表程序设计4.3.3关键字查找程序设计4.3.4数据极值查找程序设计4.3.5数据排序程序设计4.3.6分支转移程序设计4.3.7循环程序设计4内容概要汇编语言能直接控制单片机硬件的编程语言。因此,要求程序设计者要“软、硬结合”。本章介绍汇编语言程序设计的基本知识,以及一些基本的程序设计。4.1汇编语言程序设计概述程序是指令的有序集合。单片机运行就是执行指令序列的过程。编写这一指令序列的过程称为程序设计。54.1.1单片机编程语言常用的编程语言是汇编语言和高级语言。1.汇编语言用英文字符来代替机器语言,这些英文字符被称为助记符汇编语言:用助记符表示的指令。汇编语言源程序:用汇编语言编写的程序。“汇编”:汇编语言源程序需转换(翻译)成为二进制代码表示的机器语言程序,才能识别和执行。完成“翻译”的程序称为汇编程序。经汇编程序“汇编”得到的以“0”、“1”代码形式表示的机器语言程序称为目标程序。56优点:用汇编语言编写程序效率高,占用存储空间小,运行速度快,能编写出最优化的程序,缺点:可读性差,离不开具体的硬件,是面向“硬件”的语言通用性差。2.高级语言不受具体“硬件”的限制,优点:通用性强,直观、易懂、易学,可读性好。目前多数的51单片机用户使用C语言(C51)来进行程序设计,已公认为高级语言中高效简洁而又贴近51单片机硬件的编程语言。将C语言向单片机上移植,始于20世纪80年代的中后期。67经过十几年努力,C51已成为单片机的实用高级编程语言。尽管目前已有不少设计人员使用C51来进行程序开发,但在对程序的空间和时间要求较高的场合,汇编语言仍必不可少。在这种场合下,可使用C语言和汇编语言混合编程。在很多需要直接控制硬件且对实时性要求较高的场合,则更是非用汇编语言不可。掌握汇编语言并能进行程序设计,是学习和掌握单片机程序设计的基本功之一。4.1.2汇编语言语句和格式两种基本语句:指令语句和伪指令语句。78(1)指令语句每一指令语句在汇编时都产生一个指令代码(机器代码),执行该指令代码对应着机器的一种操作。(2)伪指令语句是控制汇编(翻译)过程的一些控制命令。在汇编时没有机器代码与之对应。下面介绍指令语句格式。伪指令语句将在4.1.3节介绍。9汇编语言语句是符合典型的汇编语言的四分段格式:标号字段和操作码字段之间要有冒号“:”分隔;操作码字段和操作数字段间的分界符是空格;双操作数之间用逗号相隔;操作数字段和注释字段之间的分界符用分号“;”。任何语句都必须有操作码字段,其余各段为任选项。9标号字段(LABLE)操作码字段(OPCODE)操作数字段(OPRAND)注释字段(COMMENT)10【例4-1】下面是一段程序的四分段书写格式。标号字段操作码字段操作数字段注释字段START:MOVA,#00H;0→AMOVR1,#10;10→R1MOVR2,#00000011B;03H→R2LOOP:ADDA,R2;(A)+(R2)→ADJNZR1,LOOP;R1减1不为零,则跳LOOP处NOPHERE:SJMPHERE上述4个字段应该遵守的基本语法规则如下。10111.标号字段语句所在地址的标志符号,如标号“START”和“LOOP”等。有关标号规定如下:(1)标号后必须跟冒号“:”。(2)标号由1~8个ASCII码字符组成,第一个字符必须是字母。(3)同一标号在一个程序中只能定义一次,不能重复定义。(4)不能使用汇编语言已经定义的符号作为标号,如指令助记符、伪指令以及寄存器的符号名称等。(5)标号的有无,取决于本程序中的其他语句是否访问该条语句。如无其他语句访问,则该语句前不需标号。11122.操作码字段操作码字段规定了语句执行的操作,操作码是汇编语言指令中唯一不能空缺的部分。3.操作数字段指令的操作数或操作数地址。在本字段中,操作数的个数因指令的不同而不同。通常有单操作数、双操作数和无操作数三种情况。如果是多操作数,则操作数之间要以逗号隔开。13操作数表示时,几种情况需注意:(1)十六进制、二进制和十进制形式的操作数表示多数情况,操作数或操作数地址是采用十六进制形式来表示的。则需加后缀“H”。在某些特殊场合用二进制表示,需加后缀“B”若操作数采用十进制形式,则需加后缀“D”,也可省略。若十六进制操作数以字符A~F开头,需在它前面加一个“0”,以便汇编时把它和字符A~F区别开。1314(2)工作寄存器和特殊功能寄存器的表示当操作数为工作寄存器或特殊功能寄存器时,允许用工作寄存器和特殊功能寄存器的代号表示。例如,工作寄存器用R7~R0,累加器用A(或Acc)表示。另外,工作寄存器和特殊功能寄存器也可用其地址来表示,如累加器A可用其地址E0H来表示。4.注释字段用于解释指令或程序的含义,对可读性非常有用。使用时须以分号开头,长度不限,一行写不下可换行书写,但注意也要以分号开头。1415汇编时,遇到“;”就停止“翻译”。因此,注释字段不会产生机器代码。4.1.3伪指令在汇编语言源程序中应有向汇编程序发出的指示信息,告诉它如何完成汇编工作,这是通过伪指令来实现。伪指令不属于指令系统中的汇编语言指令,它是程序员发给汇编程序的命令,也称为汇编程序控制命令。只有在汇编前的源程序中才有伪指令。“伪”体现在汇编后,伪指令没有相应的机器代码产生。伪指令具有控制汇编程序的输入/输出、定义数据和符号、条件汇编、分配存储空间等功能。1516常用的伪指令。1.ORG(ORiGin)汇编起始地址命令源程序的开始,用一条ORG伪指令规定程序的起始地址。如果不用ORG,则汇编得到的目标程序将从0000H地址开始。例如:ORG2000HSTART:MOVA,#00H……即规定标号START代表地址为2000H开始。在一源程序中,可多次用ORG指令,规定不同的程序段的起始地址。17地址必须由小到大排列,且不能交叉、重叠。ORG2000H……ORG2500H……ORG3000H……这种顺序是正确的。若按下面顺序的排列则是错误的,因为地址出现了交叉。ORG2500H……ORG2000H……ORG3000H……17182.END(ENDofAssembly)汇编终止命令源程序结束标志,终止源程序的汇编工作。整个源程序中只能有一条END命令,且位于程序的最后。如果END出现在程序中间,其后的源程序,将不进行汇编处理。3.EQU(EQUate)标号赋值命令用于给标号赋值。赋值后,标号值在整个程序有效。例如:TESTEQU2000H表示TEST=2000H,汇编时,凡是遇到TEST时,均以2000H来代替。18194.DB(DefineByte)定义数据字节命令用于从指定的地址开始,在程序存储器连续单元中定义字节数据。例如:ORG2000HSEG1:DB30H,40H,24,C,B汇编后(2000H)=30H(2001H)=40H(2002H)=18H(十进制数24)(2003H)=43H(字符“C”的ASCII码)(2004H)=42H(字符“B”的ASCII码)1920显然,DB功能是从指定单元开始定义(存储)若干字节,十进制数自然转换成十六进制数,字母按ASCII码存储。5.DW(DefineWord)定义数据字命令该命令用于从指定的地址开始,在程序存储器的连续单元中定义16位的数据字。例如:ORG2000HTAB:DW1246H,7BH,10汇编后(2000H)=12H;第1个字(2001H)=46H(2002H)=00H;第2个字21(2003H)=7BH(2004H)=00H;第3个字(2005H)=0AH6.DS(DefineStorage)定义存储区命令从指定地址开始,保留指定数目的字节单元作为存储区,例如:TABEL:DS10表示从TABEL代表的地址开始,保留10个连续的地址单元2122注意:DB、DW和DS命令只能对程序存储器有效,不能对数据存储器使用。7.BIT位定义命令用于给字符名称赋以位地址,位地址可以是绝对位地址,也可是符号地址。例如:QABITP1.6功能是把P1.6的位地址赋给变量QA。4.2汇编语言源程序的汇编“汇编”:汇编可分为手工汇编和机器汇编两类。22234.2.1手工汇编通过查指令的机器代码表(表3-2),逐个把助记符指令“翻译”成机器代码,再进行调试和运行。手工汇编遇到相对转移偏移量的计算时,较麻烦,易出错,只有小程序或受条件限制时才使用。实际中,多采用“汇编程序”来自动完成汇编。23244.2.2机器汇编用微型计算机上的软件(汇编程序)来代替手工汇编。在微机上用编辑软件进行源程序编辑,然后生成一个ASCII码文件,扩展名为“.ASM”。在微机上运行汇编程序,译成机器码。机器码通过微机的串口(或并口)传送到用户样机(或在线仿真器),进行程序的调试和运行。反之,在分析产品的程序的机器代码时,需将机器代码翻译成汇编语言源程序,称为“反汇编”。2425【例4-2】表4-1是一段源程序的汇编结果,可查表3-2,手工汇编,来验证下面的汇编结果是否正确。机器码从1000H单元开始存放。25264.351汇编语言程序设计举例介绍常用的汇编语言程序的设计。4.3.1子程序的设计将那些需多次应用的、完成相同的某种基本运算或操作的程序段从整个程序中独立出来,单独编成一个程序段,需要时进行调用。这样的程序段称为子程序。优点:采用子程序可使程序结构简单,缩短程序的设计时间,减少占用的程序存储空间。26271.子程序的基本结构典型的子程序的基本结构如下:MAIN:……;MAIN为主程序入口标号……QQQ:LCALLSUB;调用子程序SUB,3字节机器代码DISTU:…………子程序SUB:PUSHPSW;现场保护PUSHAccPOPAcc;现场恢复,注意要先进后出POPPSWRET;最后一条指令必须为RET27子程序处理程序段子程序282.子程序的设计原则和调用应注意的问题主程序调用子程序,是通过调用指令来实现。两条子程序调用指令:②长调用指令LCALLaddr16。三字节,addr16为直接调用的目的地址,子程序可放在64KB程序存储器区任意位置。①绝对调用指令ACALLaddr11。双字节,addr11指出了调用的目的地址,PC中16位地址中的高5位不变,被调用的子程序的首地址与绝对调用指令的下一条指令的高5位地址相同,即只能在同一个2KB区内。2829LCALLSUB硬件自动将断点DISTU入栈保存。断点的低位字节先入栈,高位字节后入栈。断点是如何计算的?堆栈指针有何变化?PC=SUB30(1)子程序的入口地址,前必须有标号。(2)子程序入口处,一般用到堆栈指令,进行现场的保护PSW当前内容;子程序中要用到的寄存器,必须在子程序使用前将其当前内容入栈保存(3)子程序最后一条指令必须是RET指令,执行后把堆栈中的断点地址弹出送入PC指针中,从而实现子程序返回后从主程序断点处继续执行主程序。(4)子程序可以嵌套,即主程序可以调用子程序,子程序又可以调用另外的子程序。30314.3.2查表程序设计查表程序是一种常用程序,避免复杂的运算或转换过程,可完成数据补偿、修正、计算、转换等各种功能,具有程序简单、执行速度快等优点。查表是根据自变量x,在表格寻找y,使y=f(x)。单片机中,数据表格存放于程序存储器内。两条查表指令如下:(1)MOVCA,@A+DPTR(2)MOVCA,@A+PC3132MOVCA,@A+DPTR把A中内容与DPTR中的内容相加,结果为某一程序存储单元的地址,然后把该地址单元的内容送到A中。【例4-3】设计一子程序,功能是根据累加器A中的数x(0~9之间)查x的平方表,根据x的值查出相应的平方y。本例中的x和y均为单字节数。33PUSHDPH;保存DPHPUSHDPL;保