1、,第4章 汇编语言程序设计,4. 1 概 述,4. 2 简单程序,4. 3 分支程序,4. 4 循环程序,4. 6 子程序的设计及调用,4. 7 程序设计举例,4. 5 查表程序,下页,4.1 概 述,一、汇编语言和高级语言相比具有下列优点:,上页,下页,回目录,专有特性,MOV P1, A,如: 输出操作,二、汇编语言程序设计的步骤:,三、汇编语言程序的结构,上页,下页,回目录,例1:内部RAM从DATA1单元有一数据块,存放若干无符号数, 第一单元为数据块长度,求这些无符号数之和。,起始地址,程序主体,汇编结束标志,标号,注释,上页,下页,回目录,上页,下页,回目录,四、评价程序质量的标准
2、:, 程序的执行时间, 程序所占用的内存字节数目, 程序的逻辑性、可读性, 程序的兼容性、可扩展性, 程序的可靠性,时 间空 间,4.2.1 顺序程序 例4.1 设三字节无符号数相加,被加数:在内部RAM 20H22H单元(低位在前),加数: 在内部RAM 30H32H单元(低位在前),结果: 存于内部RAM2022H单元,进位位存于23H单元。 利用ADDC指令进行多字节加法运算。,ORG5000H MOVR0,#20H;被加数的低字节地址MOVR1,#30H;加数的低字节地址MOVA, R0ADDA, R1;低字节相加MOVR0,A;存放字节相加结果INCR0INCR1MOV A,R0AD
3、DC A,R1;中间字节带进位相加MOVR0, A;存中间字节相加结果,INCR0INCR1MOV A,R0ADDC A,R1;高字节带进位相加MOV R0,A;存高字节相加结果 INC R0MOV A, #00HADDC A, #00HMOVR0, A;进位位送23HEND,例4.2 将片内RAM 20H单元的内容拆成两段,每段4位。并将它们分别存入21H与22H单元中。 (20H) =0101, 1010=5AH (21H) =0AH (22H) =05H,ORG 5000HSTART:MOV R0,#21H;R021H MOV A,20H;A(20H) ANL A,#0FH;A #0FH
4、(A) MOV R0,A;(R0)(A),保存低4位INC R0;R0 (R0)1 MOV A,20H;A(20H) SWAP A;高低半字节交换 ANL A,0FH ;A 0FH MOV R0,A;(R0)(A)END,4.2 简单程序,简单程序的特点:,既无分支,又无循环,按照顺序执行,例4-2:将一个字节内的两个BCD码拆开并变成ASCII码, 存入两个RAM单元。BCD码放在内RAM的20H, 转换后高半字节放到21H,低字节放22H。,BCDH BCDL,0011,0011,方法1:,BCD码09对应的ASCII码为30H39H转换时,将20H中的BCD码拆开,高四位置为“0011”
5、即可。,BCDH,BCDL,上页,下页,回目录,可完成一定的基本功能,是编写复杂程序的基础,程序:,0011 BCDH,0000 0000,;两个BCD数送A,;BCDL数送22H,;完成转换,;BCDH数送A的低4位,;完成转换,;存数,BCDH BCDL,BCDL,0000,0011,0000,BCDH,0011,上页,下页,回目录,;原地踏步,相当与停机,方法1小结:,以上程序用了8条指令,15个内存字节,执行时间为9个机器周期。,方法2:,采用除10H取余法将两个BCD数拆开,BCDH BCDL,0001 0000,0000 BCDH,0000 BCDL,DIV AB,上页,下页,回目
6、录,0011 BCDH,0011 BCDL,程序:,;取BCD码至A,; 完成转换,;存ASCII码,;完成转换,;存ASCII码,BCDH BCDL,0001 0000,0000 BCDH,0000 BCDL,DIV AB,0011,0011,上页,下页,回目录,方法2小结:,以上程序用了7条指令, 16个内存字节, 执行时间为13个机器周期。,上页,下页,回目录,将内部RAM的20H单元中的8位无符号二进制数,转换为3位BCD码,并将结果存放在FIRST(百位)和SECOND(十位、个位)两个单元中。,例4-4:,解:,可将被转换数除以100,得百位数;余数除以10得十位数;最后余数即为个
7、位数。,编程如下:,例如:255(十进制)除以100,得 2(百位数) 余数除以10,得5(十位数) 最后余数5即为个位数,上页,下页,回目录,5 5 H,程序(设(20H)=0FFH):,; 除100,;百位BCD,;除10,;除数10 B,;十位数送高位,;A为十位、个位BCD,;存十位、个位数,0FFH,6 4H,0 2H,3 7H,0 AH,3 7H,MOV A,B,0 5H,0 5H,5 0H,5 5H,0 2 H,上页,下页,回目录,FIRST,SECOND,4.2.2 分支程序 分支程序的基本结构:单分支和多分支。其特点是:各处理模块是相互排斥的。,13条条件转移指令,分别为:
8、JZ,JNZ: 累加器判零转移指令;CJNE: 比较条件转移指令;DJNZ: 减1条件转移指令; JC, JNC , JB,JNB,JBC: 位控制条件转移指令等四类。,4.3 分支程序,简单分支:,测试标志位,解:,这是一个简单分支程序,可以使两数相减,若CY=1,则被减数小于减数。用JC指令进行判断。,N路分支:,利用散转指令JMP A+DPTR可转向任一处理程序,例4-5 设内RAM 30H,31H存放两个无符号数,试比较 两数的大小,较小的数存入30H单元,较大的数 存入31H单元。,程序的流程图如下:,简单分支程序举例:,上页,下页,回目录,多重分支:,判断程序设置的条件,判断2个以
9、上的条件,被称为复合条件,根据程序运行情况,可以有N种选择,程序:,;做减法比较两数,;若(30H)小,则转移,;交换两数,流程图:,CY=1则转移,若CY1则顺序执行,上页,下页,回目录,例4-6:空调机制冷时,若排出的空气温度比吸入的空气 温度低8则认为工作正常,否则便认为是故障, 并设置故障标志。,解:,为了可靠的监控空调机的工作情况,做两次减法:第一次(40H)-(41H),若CY=1 ,则肯定有故障;第二次两个温度的差值减去8 ,若CY=1 ,则肯定有故障,程序的流程图如下:,上页,下页,回目录,首先定义一些工作单元,低,高,置热?,置冷能力不足?,流程图:,上页,下页,回目录,故
10、障,正常,入 出,故 障,程序:,; A(40H)-(41H),;CY=1,则故障,;是则故障,;温度小于8?,;工作正常标志,;转出口,;设置故障标志,若CY1顺序执行,CY=1转移,CY=1转移,若CY1顺序执行,上页,下页,回目录,;停机,例4.10 假定R0中存放的是采集到的被按键键值,共有128个键值(0127),根据该键值转向不同键的处理程序中去。 跳转方法: 逐个比较,类似CASE。 使用散转指令JMP A+DPTR 。 设(R0) 0 n,对应的处理程序入口地址分别为 PROG0PROGn,且按照一定的规律排列。,多分支程序结构,ORG 2000H MOV DPTR, #TAB
11、 ;设置处理程序入口首地址 MOV A,R0 RL A ;NEXT:JMP A+DPTR ;转向形成的散转地址入口 TAB:AJMP PROG0 ;直接转移地址表 AJMP PROG1 AJMP PROGn,多重分支程序举例,例4-7:设30H单元存放的是一元二次方程ax2+bx+c = 0 根的判别式= b2 4ac的值。,试根据30H单元的值,编写程序,判断方程根的三种情况。在31H中存放“0”代表无实根, 存放“1”代表有相同的实根, 存放“2”代表两个不同的实根。,解:,为有符号数,有三种情况,这是一多重分支程序 即小于零,等于零、大于零。 可以用两个条件转移指令来判断, 首先判断符号
12、位,用指令JNB ACC.7, rel判断, 若ACC.7 = 1,则一定为负数;此时0 若ACC.7 = 0,则0。此时再用指令JNZ rel 判断 若0,则 0,否则= 0,上页,下页,回目录,流程图:,上页,下页,回目录, 0,则无实根,= 0,则 1个实根, 0,则2个实根,P124,程序:,; 0转 TOW,;有两个不同实根,上页,下页,回目录,P124,循环程序设计,循环程序一般由四个主要部分组成: (1) 初始化部分: 为循环程序做准备, 如规定循环次数、 给各变量和地址指针预置初值。 (2) 处理部分: 为反复执行的程序段, 是循环程序的实体, 也是循环程序的主体。 (3) 循
13、环控制部分: 这部分的作用是修改循环变量和控制变量, 并判断循环是否结束, 直到符合结束条件时, 跳出循环为止。 (4) 结束部分: 这部分主要是对循环程序的结果进行分析、 处理和存放。,循环:单重循环 多重循环(二重以上)循环嵌套。 在多重循环程序中,只允许外重循环嵌套内重循环程序,而不允许循环体互相交叉,另外,也不允许从循环程序的外部跳入循环程序的内部。,例4.5 把外部RAM 500050FFH单元的内容清零。ORG 4200HSTART1:MOVR0, #00H;设置循环初始值MOVDPTR, #5000HLOOP1:MOVA, #00HMOVX DPTR, A;外部RAM单元清零IN
14、CDPTR;外部RAM单元加1INCR0;循环次数加1CJNER0, #00H, LOOP1;循环控制END,例4-6 设三字节无符号数相加,被加数:内部RAM 20H22H单元(低位在前),加数: 内部RAM 30H32H单元(低位在前),结果:存于内部RAM 2022H单元,进位位存于23H单元。 利用ADDC指令进行多字节加法运算。,ORG4200H MOV R0,#20H;被加数的低字节地址MOV R1,#30H;加数的低字节地址MOV R2,#03H;循环次数CLRCLOOP: MOV A, R0ADDC A, R1;低字节相加MOV R0,A;存放字节相加结果INC R0INC R
15、1DJNZ R2, LOOP;循环控制MOV A, #00HADDC A,#00HMOV R0, A;进位位送23HEND,循环程序:一些有规可循而又反复处理的问题,利用比较转移指令CJNE、减1不为“0”转移指令DJNZ等实现,例4-13:在内部RAM 30H4FH 连续32个单元中存放了 单字节无符号数,求32个无符号数之和, 并存入内部RAM 51H,50H中。,解:,这是重复相加问题,要设置一些工作单元 设:R0 做加数地址指针,R7 做循环次数计数器,R3 做和数的高字节寄存器。,程序的流程图如下:,上页,下页,回目录,地址指针,循环次数计数器,流程图:,上页,下页,回目录,N,Y,
16、N,Y,(A)+(R0)A,(R3)+1R3,P130,程序:,;取被加数,;R0作加数地址指针,;CY=0,和(B)则恢复A,;未完继续比较,;存最大数,;*若用RET指令结尾则 该程序可作子程序调用,;作减法比较,RET,例4-15:从外部RAM BLOCK单元开始有一数据块, 数据块长度存入LEN单元,,试统计其中正数、负数和零的个数,分别存入PCOUNT、MCOUNT、ZCOUNT单元。,解:这是一个多重分支的单循环问题。数据块中是带符号数,先用JB ACC.7,rel 指令判断符号位。,程序的流程图如下:,若ACC.7=1,则该数一定是负数,MCOUNT单元加1;,若ACC.7=0,
17、则该数可能是正数,也可能是零;,用JNZ rel 判断A是否为零,若A0,则一定是正数,PCOUNT单元加1;,若既不为正也不为负,则一定是零,ZCOUNT单元加1;,上页,下页,回目录,P132请阅读!,阅读!,流程图:,上页,下页,回目录,P132,负数,正数,零,程序:,上页,下页,回目录,上页,下页,回目录,P132,作业 P156: 2、6、13、16,查表程序,上页,下页,回目录,对于复杂参数的计算如:,非线性参数,对数、指数、三角函数,微分、积分等,用汇编编程十分困难,甚至无法建立数学模型,用查表的方法简单便捷,MCS-51指令系统中有两条指令具有极强的查表功能,(1) MOVC
18、 A,A+DPTR,作基址寄存器,作变址寄存器,长查表指令,寻址64KB,(2) MOVC A,A + PC,作基址寄存器,作变址,短查表指令页内查表指令,指向表格首址,指向表格的第 i 项,第i项加变址调整值,查表程序 常用于非线性修正、非线性函数转换以及代码转换等。 专用的查表指令: MOVC A,A+DPTR ;远程查表, 64KB 通过以下三步操作实现查表。 将所查表格的首地址送入DPTR; 将要查找的数据序号,即数据在表中的位置送入累加器A中; 执行查表指令 MOVC A,A+DPTR 进行读数并存结果存 于累加器A。,例4.13 若累加器A中存放的是一位BCD码。通过查表将其转换成
19、为相应的七段显示码,并存入寄存器B中。 七段数码显示管连接方式:共阳极和共阴极两种。 共阳极是低电平为有效输入, 共阴极为高电平为有效输入。 假设数码显示管为共阴极。 09的七段码为 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH。 由于代码没有规律,一般采用查表完成。,3FH,若以DPTR为基址,程序段如下: MOVA, #05H MOV DPTR, #TAB MOVC A, A+DPTR TAB:DB 3FH,06H,5BH,4FH,66H, DB 6DH,7DH,07H,7FH,6FH ,例:用查表法计算平方(一) ORG 0000H MOV DPTR,#
20、TABLE ;表首地址送DPTR MOV A,#05;被查数字05A MOVC A,A+DPTR ;查表求平方 SJMP $ TABLE:DB 0,1,4,9,16,25,36,49,64,81 END,MOVC A,A+PC ;近程查表,-128+127B其实现查表也可通过以下三步操作来完成。 将要查找的数据序号,即数据在表中的位置送入累加器A中; 把从查表指令到表的首地址间的偏移量与A值相加; 执行查表指令 MOVC A,A+PC 进行读数,查表结果送累加器A。,若以PC为基地址,则程序段如下: MOVA, #05HADD A, #01H MOVCA, A+PCNOP TAB:DB 3FH
21、,06H,5BH,4FH,66H, DB 6DH,7DH,07H,7FH,6FH ,例: 用查表法计算平方(二) ORG 0000H0000H MOV A,#05 ;05 A0002H ADD A,#02 ;修正累加器A0004H MOVC A,A+PC ;查表求平方0005H SJMP $ 0007H: DB 0,1,4,9,16,25,36,49,64,81 END,例4-20:一个十六进制数放在HEX单元的低四位, 将其转换成ASCII码,解:,十六进制 09 的ASCII码为 30H39H, AF 的ASCII码为 41H46H,,上页,下页,回目录,ASCII码表格的首址为ASCII
22、TAB,上页,下页,回目录,编程1:,0 1 2 3 4 5 6 7 8 9,A B C D E F,(A)= 3,33H,(A)= 15,46H,编程2:,;2字节,;1字节,#3,上页,下页,回目录,;变址调整,ALU,(PC) = 0207H,01H,04H,31H,查十六进制数“01H”的ASCII码(PC做基址),上页,下页,回目录,ALU,01H,31H,查十六进制数“01H”的ASCII码(DPTR做基址),020BH,上页,下页,回目录,4.2.4 子程序设计 子程序与一般程序的主要区别是在子程序的末尾有一条子程序返回指令(RET),其功能是执行完子程序后通过将堆栈内的断点地址
23、弹出到PC而返回到主程序中。 在编写子程序时应注意以下几点: (1) 要给每个子程序赋一个名字。 实际上是一个入口地址的代号。 (2) 要能正确地传递参数。 首先要有入口条件,说明进入子程序时它所要处理的数据如何得到,另外,要有出口条件,即处理的结果是如何存放的。,(3) 注意保护现场和恢复现场。 注意保存主程序和子程序共同涉及的,但值不同的累加器、寄存器和单元的内容。 保护现场: PUSH 恢复现场:POP(4) 注意子程序的通用性。主程序调用子程序的指令: “LCALL”,“ACALL”。 子程序返回指令:RET。子程序可以嵌套,嵌套次数从理论上说是无限的,但实际上由于受堆栈深度的影响,嵌
24、套次数是有限的。,例4.11 设有a,b,c三个数(09),存于内部RAM的 DATAA、DATAB、和DATAC三个单元。 编程实现: c = a2 + b2。 设DATAA、DATAB、DATAC分别对应内部RAM的40H、41H和42H单元。,ORG5000HDATAAEQU40HDATABEQU41H DATACEQU42HSTART:MOV A,DATAA;取第一操作数ACALL SQR;调用查表程序MOV R1,A;a2暂存R1MOV A,DATAB;取第二操作数 ACALL SQR;调用查表程序ADD A,R1;Aa2b2MOV DATAC,A,子程序:SQR: INC A ;偏
25、移量调整MOVC A,A+PC ;查平方表RETTAB:DB 0, 1, 4, 9, 16, 25, 36, 49, 64, 81END,4.6 子程序的设计及调用,一、子程序的概念,把能完成某种基本操作,并具有相同操作的程序段,单独 编成子程序。如:函数、 运算、代码转换、数据采集、延时等,利用调用子程序指令(ACALL或LCALL)和从子程序返回指令RET,使用子程序的优点, 不必重复书写同样的程序,提高编程效率, 程序的逻辑结构简单,便于阅读, 缩短了源程序和目标程序的长度,节省了存储器空间, 使程序模块化、通用化、便于交流共享资源, 便于按某种功能调试,上页,下页,回目录,二、调用子程
26、序的要点, 子程序开头的标号段必须有一个标志,该标志既是 子程序的名字又是其入口地址,以便主程序调用。,在主程序中利用指令ACALL或LCALL可转入子程序。 该指令具有保护断点的功能,例如:调用延时子程序,LCALL(ACALL) DELY, 子程序结尾必须使用一条从子程序返回指令RET, 它具有恢复断点的功能,主程序,CALL断点,子程序,RET,1、子程序的结构,上页,下页,回目录,2、参数传递,子程序入口条件:,在调用一个子程序时,主程序应先把有关参数放到某些约定的位置,子程序运行时,可以从约定的位置得到有关参数。,子程序出口条件:,子程序结束前,也应把处理结果送到约定位置,参数传递的
27、方法:, 子程序无须传递参数,这类子程序中所需要的参数是子程序赋予,不需要主程序给出,上页,下页,回目录,主程序:,子程序:,不需主程序提供入口参数,从子程序开始到子程序返回,大约为20ms,例4-23 调用延时子程序DELY,子程序开始的标号,子程序返回指令,调用子程序,上页,下页,回目录,982=196s,1s,1s,设:主频为12MHZ,2s,(196+2+2) 100,+3,=20003s = 20.003ms,2s,1s,+3,意味着每个机器周期为1s, 用累加器和工作寄存器传递参数,入口参数:,放在累加器A和工作寄存器中R0 R7中,出口参数:,放在累加器A和工作寄存器中R0 R7
28、中,例4-24 双字节求补子程序CPLD,解:采用“变反加1”的方法,十六位数变反加1, 不仅低字节要加1,高字节要加低字节的进位。 故采用ADD指令,不采用INC指令。 INC指令不影响CY位,上页,下页,回目录,入口参数:(R7R6)=16位数,出口参数:(R7R6)=求补后的16位数,上页,下页,回目录,Cy,+ Cy,R7R6,R7R6, 通过操作数地址传递参数,入口参数:(R0)=求补数低字节指针,(R7)=n-1,出口参数:(R0)=求补后高字节指针,例4-25 n字节求补子程序CPLN,上页,下页,回目录,地址, 通过堆栈传递参数,解: 由于要进行两次转换,故可调用查表子程序完成
29、,主程序,*PCH,*PCL,HEX,栈底,断点地址,上页,下页,回目录,子程序,上页,下页,回目录,HEX,Result,Result,PC,HEX,HEX,*PCL,*PCH,断点,ASC,主程序,子程序,上页,下页,回目录,3、现场保护,现场保护: 如果子程序使用的寄存器与主程序使用的寄存器 有冲突,在转入子程序前,特别是进行中断服务 子程序时,要进行现场保护。,保护内容: 主程序使用的内部 RAM 内容,各工作寄存器内容, 累加器 A 和 DPTR 以及 PSW 等寄存器内容。,保护方式: 将要保护的单元压入堆栈。,上页,下页,回目录,中断保护时:还可以用 RS1 RS0 来选择其他通
30、用寄存器组, 以便保护主程序现场。,R0 R7,冲突,例如:十翻二子程序的现场保护,推入与弹出应按照“先进后出”,或“后进先出”的顺序,上页,下页,回目录,三、子程序的调用及嵌套,1、子程序的调用,上页,下页,回目录,请阅读P144,使用 LCALL 或 ACALL 指令,主程序:,上页,下页,回目录,请阅读P144,子程序:,A37 A30,0,0,A37,A36,A36 0,A26 A37,A16 A27,A06 A17,上页,下页,回目录,2、子程序的嵌套,子程序的嵌套: 子程序中可调用其他子程序,上页,下页,回目录,子程序与主程序的概念是相对的,在一个子程序中又可调用其它子程序,这就是
31、子程序的多重嵌套。,多重嵌套的过程,*PC0L,*PC0H,*PC1L,*PC1H,*PC2H,*PC2L,主程序,LCALL SUB1,继续主程序,*PC0,断点入栈,LCALL SUB2,*PC1,断点入栈,LCALL SUB3,*PC2,断点入栈,RET,弹出断点,RET,弹出断点,RET,弹出断点,上页,下页,回目录,栈 底,堆栈的设置是十分重要的,请阅读P146,4.7 程序设计举例,例4-29 多字节无符号数减法子程序NSUB,功能:n字节无符号数减法,出口:(R0)=差数高字节地址指针,上页,下页,回目录,请阅读P147148,流程图:,程序:,上页,下页,回目录,请阅读P147
32、148,例4-30 双字节无符号数快速乘法子程序MULD,功能: 双字节无符号数乘法,积为32位,出口: (R0)= 乘积的高字节地址指针,上页,下页,回目录,编程思路与手乘法相似:,被乘数,乘数,上页,下页,回目录,bdH,bdL,adH,adL,bcL,bcH,acL,acH,bdL,adH,相乘过程,上页,下页,回目录,按位权对齐,位权,位权,请阅读P148 149,程序,上页,下页,回目录,请阅读P149,上页,下页,回目录,请阅读P149,例4-33 多字节十进制加法子程序BCDADD,功能:n字节十进制加法,出口:(R0)= 和数高字节地址指针,上页,下页,回目录,请阅读P152,程序:,上页,回目录,过 “9” 补 “6”,CY,AC,BCDH,BCDL,请阅读P152,