资源预览内容
第1页 / 共37页
第2页 / 共37页
第3页 / 共37页
第4页 / 共37页
第5页 / 共37页
第6页 / 共37页
第7页 / 共37页
第8页 / 共37页
第9页 / 共37页
第10页 / 共37页
亲,该文档总共37页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
高等职业教育高等职业教育计算机类课程规划教材计算机类课程规划教材大连理工大学出版社大连理工大学出版社第第4 4章章 汇编语言程序设计汇编语言程序设计4.1 4.1 概概 述述4.2 4.2 汇编语言伪指令汇编语言伪指令4.3 4.3 简单程序设计简单程序设计4.4 4.4 循环程序设计循环程序设计4.5 4.5 子程序设计子程序设计4.6 4.6 查表及散转程序设计查表及散转程序设计4.7 4.7 实用程序举例实用程序举例l4.1.1 4.1.1 程序设计语言简介程序设计语言简介l 1.1.机器语言机器语言l 当指令和地址采用二进制代码表示时,机器能够直接识别,因此称为机器语言。l 机器指令代码是0和1构成的二进制数信息,与机器的硬件操作一一对应。l 使用机器语言可以充分发挥计算机硬件的功能。l 但是,机器语言难写、难读、难交流,而且机器语言随计算机的型号不同而不同,因此移植困难。然而,无论人们使用什么语言编写程序,最终都必须翻译成机器语言,机器才能执行。4.1 4.1 概概 述述l 2. 2.汇编语言汇编语言l 汇编语言是采用易于人们记忆的助记符表示的程序设计语言,方便人们书写、阅读和检查。一般情况下,汇编语言与机器语言一一对应。l 用汇编语言编写的程序称为汇编语言源程序(源程序)。l 把汇编语言源程序翻译成机器语言程序的过程称为汇编,完成汇编过程的程序称为汇编程序,汇编产生的结果是机器语言程序(目标程序).l 汇编语言源程序从目标代码的长度和程序运行时间上看与机器语言程序是等效的。不同系列的机器有不同的汇编语言,因此汇编语言源程序在不同的机器之间不能通用。l 3. 3.高级语言高级语言l 高级语言是对计算机操作步骤进行描述的一整套标记符号、表达格式、结构及其使用的语法规则。 l 它是一种面向过程的语言,使用一些接近人们书写习惯的英语和数学表达式的语言去编写程序,使用方便,通用性强,不依赖于具体计算机。目前,世界上的高级语言有数百种。l 用高级语言编写的源程序,同样需要翻译成用各种机器语言表示的目标程序,计算机才能解释执行,完成翻译过程的程序称为编译程序或解释程序。高级语言程序所对应的目标代码往往比机器语言要长的多,运行时间也更多。l4.1.2 4.1.2 汇编语言源程序的设计步骤汇编语言源程序的设计步骤 汇编汇编l 1. 1.分析任务分析任务l 当我们要编写某个功能的应用程序时,首先应该详细分析给定的任务。明确哪些是任务所提供的基本条件,哪些是任务要解决的具体问题,哪些是任务所期望的最终目标。l 2. 2.确定算法确定算法 l 任务明确之后,下一步就是确定解决问题的方法。l 将给定的任务转换成计算机处理模式,即通常所说的算法。对于较复杂的任务,需要先用数学方法把问题抽象出来。往往同一个数学表达式可以用多种算法实现,我们应综合考虑寻找出其中的最佳方案,使程序所占内存小,运行时间短。l 3.3.画程序流程图画程序流程图l 画流程图是把所采用的算法转换为汇编语言程序的准备阶段,选择合适的程序结构,把整个任务细化成若干个小的功能,使每个小功能只对应几条语句。l 4.4.分配资源分配资源l 在用汇编语言进行程序设计时,我们直接面向的是计算机的最底层资源。在编写代码之前需要对内存区域进行分配,并确定程序和数据的存放地址。l 5. 5.编写代码编写代码l 在画好流程图并分配了相关资源后,就可以编写程序代码了。l 6.6.程序修改与调试程序修改与调试l 当一个汇编语言程序编好后难免有错误或需要进一步优化的地方,必须进行调试、修改。在源程序的汇编过程中用户很容易发现程序中存在的语法错误,但查找和修改程序中的逻辑错误就不那么简单,我们需要借助开发系统所提供的程序单步操作或设置断点等调试手段予以排除。4.2 4.2 汇编语言伪指令汇编语言伪指令 l 伪指令是用于告诉汇编程序如何进行汇编的指令,它不控制机器的操作也不能被汇编成机器码,只为汇编程序所识别并指导汇编如何进行。l MCS-51MCS-51系列单片机的常用伪指令如下系列单片机的常用伪指令如下: : l 1.ORG1.ORG起始地址定义伪指起始地址定义伪指l 令格式: ORG16位地址l 功能: 规定目标程序在程序存储器中所占空间的起始地址。l 例如: ORG1000H 表示后面的数据或程序存放在从1000H开始的程序存储单元中。l 2.END 2.END汇编程序结束伪指令汇编程序结束伪指令l 格式: ENDl 功能: 标志源程序的结束,即通知汇编程序不再继续向下汇编。l 3.EQU 3.EQU宏代换伪指令宏代换伪指令l 格式: 符号EQU字符串l 功能: 在程序中用EQU后面的字符串去替换EQU前面的符号。l EQU后面的字符串可以是符号、数据地址、代码地址或位地址。l 说明: EQU伪指令所定义的符号必须先定义后使用。l 所以该语句一般放在程序开始。例如:l BUFFER EQU 58H ;BUFFER的值为58Hl MOV A,BUFFER ;表示内部RAM58H单元中数据送给累加器A l 4.DATA4.DATA数值赋值伪指令数值赋值伪指令l 格式: 符号名称DATA表达式l 功能: 将表达式指定的数据地址或代码地址赋予符号名称。l 说明: DATA伪指令功能与EQU伪指令相似,但是DATA所定义的符号可以先使用后定义。该语句一般放在程序开始或结尾。l 例如:l BUFFER DATA58H ;BUFFER的值为58Hl MOV A,BUFFER ;表示内部RAM58H单元中数据送给累加器Al 5.DB5.DB字节存储伪指令字节存储伪指令l 格式:标号:DB8位二进制数据表l 功能: 从指定的地址单元开始,定义若干个字节存储单元的内容。 l 【例4.1】 l ORG 100Hl FIRST:DB 01H,02Hl SECO:DB 011B,A,12l 以上伪指令经汇编后,程序存储器有关单元l如图4-1所示。l 其中伪指令中的011B为二进制数,A为字l符A的ASCII码41H,12为十进制数。l 另外,格式中的标号为可选项。 图图4-1 4-1 例例4.14.1示意图示意图 l 6.DW6.DW字存储伪指令字存储伪指令l 格式:标号:DW16位二进制数据表l 功能: 从指定的地址单元开始,定义若干个字存储单元的内容。l 【例4.2】 l ORG1 00Hl FIRST: DW 01Hl DW 1234H,AB l 以上伪指令经汇编后,程序存储器有关单元l如图4-2所示。l 其中16位数据的高8位存入低地址单元,低8l位存入高地址单元。l 格式中的标号为可选项。图图4-2 4-2 例例4.24.2示意图示意图 l 7.DS7.DS定义空间伪指令定义空间伪指令l 格式:标号:DS表达式l 功能: 从指定的地址单元开始,保留由表达式指定的若干字节空间作为备用空间。l 例如:l ORG 1000Hl DS 0AHl DB 12H,Bl 伪指令汇编后从1000H单元开始,保留10个字节,从100AH开始连续存放12H、42H。l 8.BIT 8.BIT位地址符号伪指令位地址符号伪指令l 格式: 字符名称BIT位地址l 功能: 用规定的字符名称表示位地址。l 例如:l X0 BIT P1.0l X1 BIT 30Hl 经汇编后,P1口的第0位地址赋给X0,位地址30H赋给X1。l 在程序中可以分别用X0、X1代替P1.0和位地址30H。 4.3 4.3 简单程序设计简单程序设计 l4.3.1 4.3.1 顺序程序设计顺序程序设计l 顺序结构的程序,是指程序按指令的排列顺序依次执行直至程序结束。这种结构是程序结构中最简单的一种,用程序流程图表示的顺序结构程序,是一个处理框紧接一个处理框。 l 【例4.3】 【例4.4】 【例4.5】 (见教材P80-81页) l4.3.2 4.3.2 分支程序设计分支程序设计l 分支程序是按照给定的条件进行判断,根据不同的情况使程序发生转移,选择不同的程序入口。l 通常用条件转移指令形成简单分支结构。例如,判断结果是否为0(JZ、JNZ)、是否有进位或借位(JC、JNC)、指定位是否为1(JB、JNB)、比较指令CJNE等都可作为分支依据。l 【例4.6】 【例4.7】 (见教材P82-83页) 4.4 4.4 循环程序设计循环程序设计l4.4.1 4.4.1 循环结构循环结构l 顺序程序中每条指令只执行一次,分支程序则依据条件不同会跳过一些指令,执行另一部分指令。l 这两种程序的特点是每条指令最多只执行一次。l 在处理实际问题时,常常要求某些程序段重复执行,此时应采用循环结构实现。l 典型的循环结构如图4-4所示。l 一般包含程序初始化、循环处理、循环控制和循环结束四部分。l (1 1)初始化部分)初始化部分l 为实现程序循环做准备,如建立循环计数器、设地址指针以及为变量赋初值等。l (2 2)循环处理部分)循环处理部分l 该部分是循环程序的主体,在这里对数据进行实际的处理,是重复执行部分,所以这段程序的设计非常关键,应充分考虑程序的效率。l (3 3)循环控制部分)循环控制部分l 为下一次数据处理而修改计数器和地址指针,并判断循环是否结束。l (4 4)结束部分)结束部分l 分析、处理或存放结果。l4.4.2 4.4.2 单重循环程序设计单重循环程序设计l 1.1.循环次数已知的循环程序循环次数已知的循环程序l 【例4.8】 从60H单元开始的连续单元中有l一个无符号数的数据块,其长度在5FH中,编程l求数据块的最大值,存入5EH单元。l 分析分析: :l 假设累加器A中有最大值00H,然后逐个取出l数据块中的数据与之进行比较。l 如果当前数据大于累加器A的数据,则把数l据块中的数据送给累加器A; 图图4-4 4-4 例例4.84.8程序流程图程序流程图 l 否则累加器A的内容不变,即保证累加器A中存放的是每次比较出的较大数。l 如此循环,直至比较完最后一个数。累加器A中存放的便是所有数据中的最大值。程序流程如图4-4所示。l 源程序源程序: :l ORG 1000Hl CLR Al MOV B,5FHl MOV R0,#60H l LOOP: CLR Cl SUBB A,R0l JC L1l ADD A,R0l SJMP L2l L1: XCH A,R0l L2: INC R0l DJNZ B,LOOPl MOV 5EH,A l SJMP l END l 【例4.9】 编程确定一个数据块中负元素的个数。假设数据块的长度存放在内部RAM51H单元,数据块从内部RAM52H单元开始存放,要求将负元素的个数存放在50H单元中。l 分析分析: : l 判断有符号数值的正负可以通过判断该数值的最高位来完成。l 如果最高位为1,则该数为负;否则该数为正。l另外,统计负数个数,需要在程序初始化时将存l放负元素个数的单元清零,以便在循环中进行个l数累计,流程图如图4-5所示。l 源程序源程序: :l ORG 1000Hl MOV R0,#52H l MOV R2,#00Hl MOV B,51H l LOOP: MOV A,R0l JNB Acc.7,NEXT l INC R2图图4-5 4-5 例例4.94.9程序流程图程序流程图 l NEXT: INC R0l DJNZ B,LOOP l MOV 50H,R2l SJMP l ENDl 2.2.循环次数未知的循环程序循环次数未知的循环程序l 【例4.10】 从 60H单元开始的连续单元中有一个无符号数0FH,编程求该数据的地址并存入5FH单元。l 分析分析: :l 先取出60H单元的数据与立即数0FH比较。l 如果不相等,再取下一个单元数据进行比较;l 如此循环,直到两个数据相等时,记录数据地址,退出循环。 l 判断两数是否相等有多种方法,在此我们选择两数异或指令。如果两数相等,则异或结果为0; 否则结果为1。程序流程图如图4-6所示。l 源程序源程序: :l ORG 1000Hl MOV R0,#5FH l LOOP: INC R0l MOV A,R0l XRL A,#0FH l JZ NEXT l SJMP LOOPl NEXT: MOV 5FH,R0l SJMP l END 图图4-6 4-6 例例4.104.10程序流程图程序流程图 l 【例4.11】 用 80C51单片机的 P1口作输出,经驱动电路接 8只发光二极管,如图4-7所示。l 当输出位是“1”时,发光二极管被点亮; 输出位是“0”时二极管熄灭。l 编制单灯循环亮程序,即按l P1.0P1.1P1.2P1.6P1.7P1.0P1.1顺序,每次只有一只二极管亮。l 分析分析: :l 要使每个灯轮流被点亮,必须在P1口的各l位按指定顺序轮流输出 “1”,其余位输出0,可l以采用循环移位指令完成。l 8个灯一轮的渐次点亮由循环体完成,然l后利用无条件转移指令反复执行循环体。图图4-7 4-7 单灯循环电路图单灯循环电路图 l 程序流程图如图4-8所示。l 源程序源程序: :l ORG 1000Hl MOV A,#01H l LOOP: MOV P1,Al RL A ;累加器A左循环一位l LCALL DELAY ;调用延时子程序l SJMP LOOPl DELAY: MOV R2,#0FAH ;延时子程序l L1: MOV R3,#0FAHl L2: DJNZ R3,L2l DJNZ R2,L1l END 图图4-8 4-8 例例4.114.11程序流程图程序流程图 l4.4.3 4.4.3 多重循环程序设计多重循环程序设计l 多重循环又称为循环嵌套,是指一个循环程序的循环体中包含另一个循环程序。理论上对循环嵌套的层数没有明确的规定,但由于受硬件资源的限制,实际可嵌套层数不能太多。l 需要注意的是循环嵌套只允许一个循环程序完全包含另一个循环程序,不允许两个循环程序之间相互交叉嵌套。l 【例4.12】 编程将内部RAM70H79H中10个无符号数按由大到小的顺序排序。排序后仍存放在70H79H中。l 分析分析: :l 排序方法有多种,本例题采用“冒泡”法完成。l 具体思路是具体思路是: : 从低地址到高地址将相邻两个单元进行比较。l 若低地址的内容大于相邻高地址单元的内容,则保持原状; 若低地址的内容小于相邻高地址单元的内容,则两单元内容互换。 l 图4-9给出设标志位冒泡法排序流程图。l 设标志位冒泡法排序源程序: l ORG 1000Hl LOOP: MOV R0,#70Hl MOV B,#09H l CLR 10Hl LOOP1: MOV A,R0l MOV 20H,A l INC R0l MOV 21H,R0l CJNE A,21H,LOOP2 图图4-9 4-9 冒泡法排序流程图冒泡法排序流程图 l LOOP2: JNC LOOP3l MOV A,R0l MOV R0,20H l DEC R0l MOV R0,A l INC R0l SETB 10Hl LOOP3: DJNZ B,LOOP1l JB 10H,LOOP l SJMP l ENDl 【例4.13】 编写软件延时80ms程序。l 分析分析: : 设单片机的时钟频率为6MHz,则其机器周期为2s。l 由于DJNZ指令需要2个机器周期,因此它的指令周期即指令执行时间为4s。MOV和NOP指令分别为2个机器周期和1个机器周期。 l 为了延时80ms,我们可以通过控制循环次数的方法来解决。l 执行两条 NOP指令和1条 DJNZ指令的时间是 8s,循环250次用时2000s,即程序中第2条到第5条指令完成的功能。l 若想达到延时80ms的目的,只要再使用一个循环40次的DJNZ指令即可。精确计算程序运行时间的公式为:l 2+2+(1+1+2)*250+2*40*2s=80324s l 如果单片机的时钟频率为12MHz,则其机器周期为1s。为了延时80ms,我们只要把循环次数由40修改为80就可以了。l 延时程序:l MOV 20H,#40 ;2机器周期指令l BBB1: MOV 21H,#250 l BBB2: NOP ;1机器周期指令l NOP l DJNZ 21H,BBB2 ;2机器周期指令l DJNZ 20H,BBB1l SJMP 4.5 4.5 子程序设计子程序设计l 在程序设计过程中,经常会遇到在不同的程序中或同一个程序的不同地方执行同一个操作的情况,例如软件延时、代码转换等。l 为了缩短程序设计周期及程序长度,可以将这些程序段从源程序中分离出来单独组成一个程序模块,我们称之为子程序。l 在需要使用这些模块的地方可以 “调用子程序”。 l 那些调用子程序的程序被称为主程序。主程序对子程序的调用是通过ACALL或LCALL指令完成的。一个主程序可以多次调用同一个子程序,也可以调用多个子程序。子程序也可调用其他子程序(称为子程序嵌套). l4.5.1 4.5.1 关于子程序的几点说明关于子程序的几点说明l 1.每个子程序的起始指令前必须定义一个标号,作为该子程序的名称,以便主程序正确的调用它。子程序通常以 RET指令结束,以便正确的返回主程序。l 2.子程序应具有通用性。一般,子程序的操作对象通常采用寄存器或寄存器间接寻址等寻址方式,尽量避免采用立即寻址。l 3.子程序应保证放在存储器的任何空间都能正确运行,即具有浮动性。例如,子程序中应使用相对转移指令,避免使用绝对转移或长转移。l 4.进入子程序时需要把在主程序中使用并在子程序中也要使用的寄存器进行保存,并在返回主程序之前恢复原来状态。l 5.子程序的调用和返回指令,以及保护现场等操作均需用到堆栈,因此在程序初始化时应设置堆栈指针SP,开辟堆栈保护区。l 6.设计子程序时应首先确定子程序名称,确定子程序的入口参数和出口参数,确定子程序需要使用的寄存器和存储单元,确定子程序的算法,再编写源程序。 l4.5.2 4.5.2 子程序的应用举例子程序的应用举例 ( (略略) )l4.5.3 4.5.3 子程序的嵌套调用子程序的嵌套调用l 子程序的嵌套调用是指在一个子程序中又调用另一个子程序。l 对于MCS-51单片机,子程序嵌套次数一般不受限制。l 子程序的嵌套调用过程如图4-10所示。l 当主程序执行到LCALL SB01指令时,它会将断点地址M02压入堆栈,并转去执行SB01子程序。 l 在SB01子程序中执行到LCALL SB02指令时,它会将断点地址SB12压入堆栈,并转去执行SB02子程序。l SB02子程序执行到最后的RET指令时,它会从堆栈中取出断点地址SB12送给指令计数器PC,程序返回SB01子程序。l SB01子程序执行到最后的RET指令时,它会从堆栈中取出断点地址M02送给指令计数器PC,程序返回主程序,继续执行。图图4-10 4-10 子程序嵌套示意图子程序嵌套示意图 l4.6.1 4.6.1 查表程序设计查表程序设计l 查表程序是指适当的组织一些表格,跟控制程序一起事先输入到单片机的程序存储器中。使用查表指令迅速获取结果数据。该类程序主要用于代码转换、算术运算等。l 【例4.16】 【例4.17】 (见教材P91页) l 说明说明: :l 在例4.16和例4.17中分别使用了指令MOVC A,A+PC和指令MOVC A,A+DPTR实现查表。l 第一条指令是以 PC作为基址寄存器,A中存放偏移量(偏移量为当前的PC值到表格首地址之间的距离),两者的和为结果所在程序存储单元的地址。 4.6 4.6 查表及散转程序设计查表及散转程序设计l 该指令执行后PC仍指向下一条指令。l 用用PCPC的内容作为基地址来查表,通常分为三步的内容作为基地址来查表,通常分为三步: :l (1)将所查表格的项数(即在表格中的位置)送入累加器A中;l (2)计算偏移量data,并在MOVC A,A+PC指令前加上指令ADD A,#data。计算公式如下:l 偏移量=表格首地址-(MOVC指令所在的地址+1)l (3)执行查表指令MOVC A,A+PC,结果存入累加器A。l 第二条指令是以 DPTR作为基址寄存器,A与DPTR两者的和为结果所在程序存储单元的地址。l 用用DPTRDPTR内容作为基地址来查表,通常也分为三步内容作为基地址来查表,通常也分为三步: :l (1)将表格的项数(即在表格中的位置)送入累加器A中;l (2)将表格的首地址送入DPTR中;l (3)执行查表指令MOVC A,A+DPTR,结果存入累加器A。 l4.6.2 4.6.2 散转程序设计散转程序设计l 在设计单片机应用程序时,经常遇到根据不同的输入或运算结果决定程序流向的问题。这就是散转程序,实际就是一种多分支程序。l 散转程序也需要一个表,但表中所列的不是普通数据,而是某些功能程序的入口地址、偏移量或转向这些功能程序的转移指令。l 程序的散转功能,主要依靠间接转移指令JMPA+DPTR完成。l 1.1.利用转移指令表进行散转利用转移指令表进行散转l 假设有一个标志单元,它的可能取值为 0,1,2的自然数,每个值对应一个处理程序。我们可以利用转移指令表,使程序根据标志单元的值转向各自的处理程序。l 选择与处理程序相同数目的无条件转移指令,由这些指令组成一张指令表,且第1条转移指令转向 “0” 标志所对应的处理程序,第2条转移指令转向“1”标志所对应的处理程序,依此类推。 l 然后把指令表的起始地址和标志单元的值分别送数据指针DPTR和累加器A中,最后使用散转指令完成。l 【例4.18】 (见教材P93页)l 2. 2.利用转向地址表进行散转利用转向地址表进行散转l 当转向范围比较大时,可直接使用转向地址表法,即把每个处理程序的入口地址直接放到地址表内。l 用查表指令从表中查找与变量值对应的处理程序的入口地址,再通过间接转移指令,使程序转向该地址指向的功能程序。l 【例4.19】 (见教材P93页)l 3. 3.利用利用 “RETRET” 指令进行散转指令进行散转l 此方法与转向地址表法基本相同。l 两者的惟一区别是:l 转向地址表法,将表中取出功能程序的入口地址直接送给数据指针; l 而返回指令法,则把入口地址压入堆栈进行保存,并随后便执行一条RET指令,使程序转向功能程序。l 【例4.20】 (见教材P94页)4.7 4.7 实用程序举例实用程序举例l 设计单片机的应用程序,不仅要掌握几种基本结构程序的设计步骤、设计方法,还要熟悉一些常用子程序的基本功能和使用方法。l4.7.1 4.7.1 代码转换类子程序代码转换类子程序 (略)l4.7.2 4.7.2 运算类子程序运算类子程序 (略)l4.7.3 4.7.3 数据比较类子程序数据比较类子程序 (略)l4.7.4 4.7.4 数据块处理类子程序数据块处理类子程序 (略) 37 以上有不当之处,请大家给与批评指正,以上有不当之处,请大家给与批评指正,谢谢大家!谢谢大家!
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号