天学通单片机第3章.ppt
21天学51单片机开发,第三讲:单片机汇编语言,课程安排,单片机汇编语言概述 伪指令 单片机的指令 51系列单片机指令集 单片机汇编语言的程序结构,单片机汇编语言概述,单片机汇编语言就是单片机汇编指令的集合,其采用了助记符的形式来描述指令。优点:程序代码精炼,执行速度快;每条指令的执行时间确定,特别适合于对时序要求比较高的场合;占用内存单元和CPU资源比较少;和硬件结构和资源密切相关,对于理解单片机的运行和组成很有帮助。缺点:指令和具体的硬件密切相关,缺乏通用性;采用助记符描述的指令还是不够清晰,代码比较难懂;使用汇编语言编写程序时,必须熟悉单片机的指令系统、寻址方式、寄存器的设置和使用方法,以及系统的硬件资源等。分散了开发人员用于程序结构和功能上的精力;,伪指令,伪指令,顾名思义,并不是真正的单片机指令。伪指令仅为单片机汇编程序提供某种标记信息,但却是程序中不可缺少的部分。伪指令与单片机指令的区别如下:伪指令不能命令CPU执行某种操作,也没有对应的机器代码。单片机指令能使单片机的CPU执行某种操作,并可以生成对应的机器代码。,起始伪指令ORG,起始伪指令ORG用于标记一个汇编语言程序的开始。这里,16位地址便是汇编程序块或数据块存放的起始地址。如果省略ORG伪指令,则单片机程序代码将默认从0000H单元开始存放。,标号:ORG16位地址,使用格式,结束伪指令END,结束伪指令END用于标记一个汇编语言程序的结束。这里,标号和表达式都可以省略。在汇编语言程序执行时,END之后所写的任何指令都不予以处理。一个程序只能有一个END伪指令。,标号:END表达式,使用格式,等值伪指令EQU,等值伪指令EQU相当于重命名的概念,其采用一个规定的字符名称来代替一个数或特定的汇编符号。使用伪指令EQU时必须先赋值,后使用,而不能先使用后赋值。另外,给字符名称所赋的值可以是8位数,也可以是16位数。用EQU定义的字符名称不能和汇编语言的关键字同名。,字符名称EQU数据或汇编符号或者字符名称=数据或汇编符号,使用格式,地址赋值伪指令DATA,地址赋值伪指令DATA是用指定的字符名称来代替数据地址或代码地址。DATA伪指令在程序中常用来定义数据地址。就功能上来说,伪指令DATA与EQU有些类似。区别如下:EQU伪指令必须先定义后使用,而DATA伪指令则无此限制;EQU伪指令可以把一个汇编符号赋给一个字符名称,而DATA伪指令则不能;DATA伪指令可将一个表达式的值赋给一个字符变量,所定义的字符变量也可以出现在表达式中,而EQU定义的字符则不能这样使用。,字符名称DATA表达式,使用格式,字节保存伪指令DB,字节保存伪指令DB用于在单片机内存中保存数据表,只能对程序存储器进行操作。其中,8位字节数据表可以是一个或多个字节数据、字符串或表达式。在数据表中,各项数据用“,”分隔,一个数据项占一个存储单元。所有的数据项是从标号指定的地址单元开始,将数据表中的字节数据按顺序依次保存。数据项可以采用十进制、二进制或者十六进制表示。,标号:DB8位字节数据表,使用格式,字保存伪指令DW,字保存伪指令DW用于在单片机内存中保存双字节数据表,只能对程序存储器进行操作。其中,16位字数据表可以是一个或多个字节数据、字符串或表达式。在数据表中,各项数据用“,”分隔,一个数据项占一个存储单元。所有的数据项是从标号指定的地址单元开始,将数据表中的字节数据按顺序依次保存。16位数据要占用两个单元的存储器,高8位数据存入低地址字节,低8位数据存入高地址字节。,标号:ORG16位地址,使用格式,空间预留伪指令DS,空间预留伪指令DS用于在单片机内存中划分出一定的存储空间用作备用区域,只能对程序存储器进行操作。这里,表达式表示了从标号指定的地址单元开始,保留存储单元的个数。,标号:DS表达式,使用格式,位变量伪指令BIT,位变量伪指令BIT用于给位地址定义一个字符名称。其中,位地址需要参考单片机中的定义,字符名称就是位变量。,字符名称BIT位地址,使用格式,单片机的指令,51系列单片机一般都遵循8051指令集。对于单片机汇编语言来说,一条指令通常由操作码和操作数两部分组成。单片机的指令按照其对应的机器码的长度,可以分为如下3种:单字节指令,其对应的机器码只有一个字节,在单片机的程序存储器中占用1个字节的存储单元。单字节指令的功能明确专一,操作简单。双字节指令,其对应的机器码为两个字节,第一个字节表示操作码,第二个字节表示操作数。双字节指令在单片机的程序存储器中占用两个字节的存储单元。三字节指令,其对应的机器码为三个字节,第一个字节表示操作码,后二个字节表示操作数。三字节指令在单片机的程序存储器中占用三个字节的存储单元。,单片机指令的寻址方式,指令的执行是需要操作对象的,单片机指令获取操作对象的方式便是指令的寻址方式。单片机指令的寻址方式,可以分为如下7种:立即寻址直接寻址寄存器寻址寄存器间接寻址变址寻址相对寻址位寻址,立即寻址,立即寻址相当于直接给出操作数,此时的操作数称为立即数。立即数的前面采用标识符“#”来表示,是寻址指令中直接出现的数据。立即数可以采用不同的表示方式:十六进制,结尾用字符H来区别;十进制,结尾用字符D来区别,一般可以省略;八进制,结尾用字符O来区别;二进制,结尾用字符B来区别。在单片机中,立即寻址方式的寻址空间是程序存储器,也就是说立即寻址方式所操作的立即数是存储在指令字节中的。,直接寻址,直接寻址方式相当于将操作数存放的地址告诉指令,此时为了和立即寻址相区别,地址前没有标识符“#”。在单片机中,直接寻址方式可寻址如下两类存储空间。片内RAM的低128个字节单元,其地址为00H7FH。这样,在这128位地址的直接寻址方式中,00H代表第0位,01H代表第1位,依次类推;特殊功能寄存器,其直接地址也可以用特殊功能寄存器的符号名称来表示。直接寻址也是访问特殊功能寄存器的唯一方法。,寄存器寻址,寄存器寻址相当于告诉指令操作数所存放的寄存器,此时,寄存器中的内容作为操作数。由于寄存器位于单片机CPU的内部,因此采用寄存器寻址的速度相比其他几种寻址方式要快,程序具有较高的运算处理速度。寄存器寻址可以寻址如下几种:通用寄存器R0R7累加器A寄存器AB数据指针DPTR 在指令的操作数位置上指定寄存器的寻址方式。其中,寄存器的内容作为操作数。采用寄存器寻址方式的指令一般都是一个字节的指令。,寄存器间接寻址,寄存器间接寻址相当于绕了更大的弯,此时数据存放在RAM中,而该RAM的地址放在寄存器中。这样,通过访问寄存器来获得RAM中操作数的寻址方式便是寄存器间接寻址。在单片机中,寄存器间接寻址可以访问如下所述的存储空间。片内RAM的低128个字节单元,此时需要使用R0、R1作为间接寻址的寄存器;外部RAM,如果采用R0、R1作为间接寻址的寄存器,可寻址256个单元;外部RAM,如果采用16位的DPTR作为间接寻址的寄存器,可寻址外部RAM的完整64KB地址空间。在寄存器间接寻址的指令中,寻址的寄存器前需要加“”标识符。这样可以和寄存器寻址相区别。,变址寻址,变址寻址提供了16位地址的寻址能力,其采用基址寄存器加变址寄存器方式来寻址。其中,基址寄存器为DPTR或PC,变址寄存器为累加器A,用于存放地址偏移量。在单片机中,变址寻址方式一般常用于访问程序储存器中的数据表格。变址寻址共有两种形式:MOV A,A+DPTR:其功能是将累加器A的内容与数据指针DPTR的内容相加形成操作数的地址,即程序储存器的16位地址。该指令取此地址中的内容送入累加器A中,指令的操作码为93H,如图3-7所示。MOV A,A+PC:其功能是将累加器A的内容与PC的内容相加形成操作数的地址,即程序储存器的16位地址。该指令取此地址中的内容送入累加器A中,其操作码为83H。,相对寻址,相对寻址是根据指定地址的偏移量,然后从当前PC值跳转到偏移量所指向的地址的方式。这里,地址偏移量为带符号的8位二进制数,其取值范围为-128+127。因此,相对寻址可以寻址当前PC的-128127之间的某段程序存储器。,位寻址,51系列单片机一般都遵循8051指令集。对于单片机汇编语言来说,一条指令通常由操作码和操作数两部分组成。单片机的指令按照其对应的机器码的长度,可以分为如下3种:单字节指令,其对应的机器码只有一个字节,在单片机的程序存储器中占用1个字节的存储单元。单字节指令的功能明确专一,操作简单。双字节指令,其对应的机器码为两个字节,第一个字节表示操作码,第二个字节表示操作数。双字节指令在单片机的程序存储器中占用两个字节的存储单元。三字节指令,其对应的机器码为三个字节,第一个字节表示操作码,后二个字节表示操作数。三字节指令在单片机的程序存储器中占用三个字节的存储单元。,位寻址,位寻址是特别为位操作区域提供的寻址方式,在指令中直接给出位地址即可。51系列单片机中,可以位寻址的区域如下:片内RAM的20H2FH单元,共168=128位。可直接使用位地址来表示,例如,20H单元的07位的位地址为00H07H。也可以使用RAM地址加位序号表示,例如2AH.1表示2AH单元的D1位。可位寻址的特殊功能寄存器相应位,这些位均有特定的名称,因此可以直接采用位名称来表示,也可以采用寄存器符号加位序号表示,例如PSW.3表示PSW寄存器中的D3位。,单片机的指令集,51系列单片机的指令系统提供了111条指令。按照指令所执行的操作可以细分为如下5类:数据传送类,共29条指令;算术运算类,共24条指令;逻辑运算及移位类,共24条指令;控制转移类,共17条指令;位操作类,共17条指令。详细的指令集可以参阅书中列表。,单片机汇编语言的程序结构,程序结构就是程序指令的组织方式。单片机汇编语言程序大致可以分为5种程序结构:顺序结构分支结构循环结构子程序结构查表结构,顺序结构,顺序结构程序是按照指令的书写顺序来执行的程序结构,相当于人们在作事情时,严格按照一个计划表来执行。顺序结构是一种无分支的直线型程序结构,一种最简单、最基本的程序。,01ORG0200H;汇编程序起始指令02MOVA,32H;将单字节数据存入累加器A中03MOVB,#100;分离出百位数04DIVAB05MOVR5,A;百位数送入寄存器R506XCHA,B;余数存入累加器A中07MOVB,#10;分离出十位和个位08DIVAB09SWAPA;十位存入高字节10ADDA,B;低位存入低字节中11MOVR6,A12END;汇编程序结束命令,在该程序中,单字节十六进制数据在0255之间,存放在单片机RAM的32H中。首先将其除100后,商为百位数,余数除以10,商为十位数,余数为个位数。程序转换后,百位数存放于R5中,十位和个位分别存放于R6的高位和低位字节中。,分支结构,分支结构是一种判断形式的程序结构,相当于人们在作事情时,根据判断的结果来觉得后面做那件事。分支结构的程序判断条件的满足与否,产生一个或多个程序分支,以实现不同的程序走向。分支结构按照采用指令的不同而分为两类:双分支结构。这类分支结构主要采用有条件转移指令JC、JB等,比较条件转移指令CJNE等和累加器A判断指令JZ等。当给定的条件成立时,执行分支程序1,否则执行分支程序2。多分支结构。这类结构主要采用散转指令JMP,根据运算的结果指在多个分支中选择一个执行的程序结构。,分支结构示例,在该程序中,16位双字节数存放在通用寄存器R3和R4中。首先,对低字节数取补,然后判断其结果是否为0,如果为0,则对高字节数进行取补,即取反加1,否则直接取反就可以了。程序将求补以后的结果存放于地址21H、22H中。,01ORG0200H;汇编程序起始命令02MOVA,R4;低字节送入累加器A03CPLA;取反04ADDA,#01H;加105MOV22H,A;将结果送入地址22H06JZZERO;如果A的值为零则转向ZERO07MOVA,R3;高字节送入累加器A08CPLA;取反09MOV21H,A;将结果送入地址21H10SJMPFEND;转结束11ZERO:MOVA,R3;高字节送入累加器A12CPLA;取反13INCA;加一14MOV21H,A;将结果送入地址21H15FEND:16END;程序结束,循环结构,循环结构是一种重复执行某段代码的程序结构,相当于人们在作事情时,在一段时间内进行重复性的工作。一个典型的循环程序由4部分组成,即循环初始化部分、循环处理部分、循环控制部分和循环结束部分。初始化部分:主要用于设置循环的次数、有关的工作单元清零、变量设置和地址指针设置等循环初始参数。循环处理部分:也称为循环体,这是循环结构的主要代码段,在程序运行时将重复执行。循环次数控制部分:主要用于控制循环的次数,防止出现死循环。循环次数控制部分一般由两个单元组成,修改控制变量和判断循环结束。循环控制变量可以采用循环递减计数法,即每循环一次,控制变量减1,并判断是否为0,若不为0,则继续执行循环体程序,否则结束循环体的执行;也可以采用条件控制,即判断结束条件是否成立,如果不成立,则继续执行循环体,否则,结束循环。结束部分:当循环处理部分执行完毕后,需要对计算结果进行处理和保存,已供后面的程序使用。,循环转移指令,在51系列单片机的指令系统中,提供了如下两条循环转移指令:DJNZ Rn,LOOP:这里采用工作寄存器Rn为控制寄存器。控制寄存器的计数方式一般都是减1计数,即每循环一次,Rn自动减1计数,同时判断寄存器Rn是否为0,若不为0,继续执行循环;若为0,则结束循环程序的执行。DJNZ Direct,LOOP:这里采用直接寻址单元Direct作为控制寄存器。控制寄存器的计数方式一般都是减1计数,即每循环一次,Direct单元自动减1计数,同时判断Direct单元是否为0,若不为0,继续执行循环;若为0,则结束循环程序的执行。,循环结构示例,在程序中,采用了比较和交换的方法来依次对比各个数据。数据块的首地址为10H,先读取第一个数据与第二个数据,把第一个数据作为基准送入累加器A,进行比较。如果基准数大,则不作交换,再取下一个数进行比较;如果基准数小,则将数值大的取代原来的基准数,即相当于做一次数据交换。然后,再以新的基准数与下一个数进行比较,直至全部比较完毕。这里的基准数始终保持为最大的数值,因此,全部比较完毕后,累加器A中的基准数即是数据块中的最大值。最后将最大值保存在通用寄存器R2中。,01ORG0200H02MOVR0,#10H;数据块首地址送入R003MOVA,R0;取第一个数作为基准数送入累加器A04MOVR1,#0AH;比较次数10=0AH送入R105LOOP1:INCR0;修改地址指针,使其指向下一个地址单元06MOV20H,R0;将要比较的数暂存于20H单元07CJNEA,20H,CHK;两个数进行比较08CHK:JNCLOOP2;如果A大,则转换09MOVA,R0;如果A小,则将较大的数送入A10LOOP2:DJNZR1,LOOP1;R1减1,如果其不为0,则继续循环11MOVR2,A;比较完毕,存结果12END,子程序结构,子程序结构是一种模块化的程序设计思想,其将某些运算和操作设计成可被其他程序调用的子程序段,需要的时候直接调用这些程序段即可。一般来说,调用子程序的程序称为主程序,调用子程序的过程称为子程序调用。子程序执行完后返回主程序的过程称为子程序返回。使用子程序可以使代码的结构清晰,也便于程序的移植和重复使用。51系列单片机指令集中提供了两个指令可以用来调用子程序,其使用格式如下:LCALL ADDR16:这条指令称为长调用指令,指令的操作数ADDR16给出了子程序的16位入口地址。ACALL ADDR11:这条指令称为绝对调用指令,其中的操作数ADDR11提供了子程序的低11位入口地址,这个地址和程序计数器PC的高5位并在一起构成16位的子程序调用地址,即子程序的入口地址。,子程序执行的步骤,子程序在执行时,需要经过如下几步:首先将程序计数器PC中的内容压入堆栈,即断点保护。程序计数器PC中为调用指令下一条指令地址,称为断点地址。然后,将调用地址送入程序计数器PC中,使程序跳转到子程序的入口地址处开始执行。子程序执行完毕后,通过返回指令RET返回。指令RET将堆栈中存放的返回地址(即断点地址)弹出堆栈,送回到程序计数器PC中,使程序返回到主程序的断点处继续向下执行。,子程序结构示例,在子程序中,两个BCD码数据均按照高位字节数存放于低地址单元。运算时,相加运算则从低位字节数开始,R0、R1指针在运算前均指向最高字节数的地址。因此,需要转换成指向最低字节数的地址,然后进行相加运算。相加的结果BCD码和数存入R0指针的内部RAM中,即原被加数单元。,01BCDADD:PUSHPSW;现场保护02PUSHA03MOVPSW,#00H;选择组004MOVA,R0;从低字节开始相加05ADDA,R206MOVR0,A07DECR008MOVA,R1;加数首地址09ADDA,R2;加字节数10MOVR1,A11DECR112CLRC;C清零13ADDA:MOVA,R0;开始两数相加14ADDCA,R115DAA;BCD码调整16MOVR0,A;存和数17DECR118DECR019DJNZR2,ADDA;判断20JNCADDB;若(C)=0则转向ADDB21MOVA,#00H;清A为022ADDCA,#00H;若(C)=1,则最高位进位23MOVR0,A24ADDB:POPA;现场恢复25POPPSW26RET;子程序返回,查表程序结构,查表程序结构是在一个已知的数据表中查找数据的程序,和我们在打电话前需要查阅电话本类似。在查表程序中,一般是把数据按照一定的顺序排列成表格,存放在单片机的程序存储器中,程序中根据被测数据,查出最终所需结果。查表程序结构一般应用于如下几类计算中:在一个无序表格中查找数据,因为是无序的,所以只能逐个查表来寻找。对于一些复杂的运算,用汇编程序难于计算,而且会占用很长的CPU时间,此时可以将常用的运算结果事先存在单片机中。通过查表来获得运算结果。对于一些非线性的运算,用汇编语言几乎无法处理,此时,只能用查表来获得运算结果。,查表程序结构示例,在该程序中,数据表位TAB,待查找的字符存放在寄存器B中。程序中将查处次数11送入通用寄存器B。然后逐个查找表,如果找到则记录地址,否则将通用寄存器R5和R6清零。,01ORG1000H02FZHAO:MOVB,10H;待查找的字送入B03MOVR4,#11;查找次数送入R404MOVDPTR,#TAB05MOVA,#15H;变址调整06LOOP:07PUSHACC;暂存A08MOVCA,A+PC;查表09CJNEA,B,NF;如果没有找到则转NF10MOVR6,DPH;找到并记录地址11MOVR5,DPL12POPACC13DOWN:RET14NF:15POPACC;恢复A16INCA;求下一个地址17INCDPTR;数据表地址加118DJNZR4,LOOP;未完则继续19MOVR6,#00H20MOVR5,#00H;如果没有找到,则R6、R5清零21AJMPDOWN22TAB:DBA;数据表示例23DBB24DBC25DBD26DBE27DBF28DBG29DBH30DBI31DBJ32DBK33END,性格决定命运,专注成就人生,源智天下,