资源描述
2020/10/4,1,第4章 80C51的汇编语言程序设计,程序编制的方法和技巧,4.1,源程序的编辑和汇编,4.2,基本程序结构,4.3,子程序及其调用,4.4,简单I/O设备的并口直接驱动示例,4.5,2020/10/4,2,单片机应用系统由硬件系统和应用程序构成,汇编语言 高级语言,应用程序设计方法,汇编语言,生成的目标程序占内存空间少、运行速度快,具有效率高、实时性强。,高级语言,对系统的功能描述与实现简单,程序阅读、修改和移植方便,适合于编写复杂的程序。,2020/10/4,3,4.1 程序编制的方法和技巧,4.1.1 程序编制的步骤,明确任务:功能要求、技术指标 运行环境调研,任务分析,将实际问题转化为计算机处理的程序算法 算法比较与优化(内存需求与运行速度),算法设计,2020/10/4,4,流程描述,流程图符号,“超级循环”框架,2020/10/4,5,强化模块观念,使程序占用空间减少、结构清晰 循环初值和结束条件,避免“死机”现象 子程序的现场保护(注意栈平衡、寄存器内容),程序模块(主程序模块、各种子程序模块) 模块化优点:分块设计、便于阅读、调试方便,4.1.2 程序编制的方法和技巧,采用循环和子程序,对中断子程序还有注意保护PSW的内容,2020/10/4,6,4.1.3 汇编语言的语句格式,非数字字符开头,后跟字母、数字、“-”、“?”等 不能用已定义的保留字(指令助记符、伪指令等) 后跟英文冒号“:”,Keil的汇编器A51可以识别的语句形式为:,标号(即符号地址),标号: 指令助记符 操作数1, 操作数2, 操作数3, ;注释,指令助记符,是指令功能的英文缩写。,2020/10/4,7,数据:二进制(B) 十进制(D或省略D) 十六进制(H),注意AF开头时要加“0” ASCII码,如 A,1245 符号:符号名、标号或“$”(PC的当前值) 表达式:由运算符和数据构成(见表4.1),操作数,注释,英文分号“;”开头,2020/10/4,8,表4.1,2020/10/4,9,4.2 源程序的编辑和汇编,目标程序的产生过程如下图:,2020/10/4,10,源程序的汇编,汇编源程序转为目标程序的过程叫汇编 汇编通常在Windows下的集成开发环境完成 用A51.EXE汇编生成.OBJ、.LIB及.LST,目标程序的连接,.OBJ、.LIB经BL51.EXE生成无扩展名的绝对地址目标文件 绝对地址目标文件可以用于仿真器调试 调试无误的目标文件用OH51.EXE转换为.HEX文件 .HEX文件经编程器写入单片机存储器,2020/10/4,11,4.2.1 源程序的编辑和汇编,源程序的编辑,ORG 0000H LJMP MAIN ORG 0003H LJMP INT0 ORG 0030H MAIN:MOV SP,#60H Mlop:. SJMP MLOP INT0:.;中断服务程序 RETI SUBP1: ;子程序 ret END,依据汇编语言规则 用好伪指令 符号不用中文 SJMP $ 用于调试 以 .ASM存盘,2020/10/4,12,上页,下页,回目录,评价程序质量的标准:, 程序的执行时间, 程序所占用的内存字节数目, 程序的逻辑性、可读性, 程序的兼容性、可扩展性, 程序的可靠性,时 间 空 间,2020/10/4,13,4.2.2 伪指令,伪指令,也叫汇编命令。仅对汇编过程进行指示 伪指令无对应的单片机可执行代码,起始地址设定伪指令ORG,ORG 表达式,表达式通常为十六进制地址,例:,ORG 8000H START:MOV A,#30H ,ORG可多次使用,但地址值的顺序要由小到大,结束汇编伪指令END,END,该伪指令位于源程序的最后一行。,2020/10/4,14,定义字节数据表伪指令DB,定义字数据表伪指令DW,1000H,标号: DB 字节数据表,如: ORG 1000H DB -2,-4,-6,8,10,18,1001H,标号: DW 字数据表,ORG 1400H DATA1:DW 324AH,3CH ,1400H,1401H,1402H,1403H,大端模式,2020/10/4,15,定义常值为符号名伪指令EQU,符号名 EQU 常值表达式,LEN EQU 10 SUM EQU 21H BLOCK EQU 22H CLR A MOV R7,LEN MOV R0,BLOCK LOOP:ADD A,R0 INC R0 DJNZ R7,LOOP MOV SUM,A,符号名为: 地址 常数 段名 字符串 寄存器名 位名,比较:标号只能是地址,2020/10/4,16,定义位地址为符号名伪指令BIT,符号名 BIT 位地址表达式,如: ST BIT P1.0 ;将P1.0的位地址赋给符号名ST CF BIT 0D7H ;将位地址为D7H的位定义为符号名,用BIT定义的“符号名”一经定义便不能重新定义和改变 其它一些伪指令参见教材表4.2,2020/10/4,17,ORG 0040H START:MOV A,21H ;取十位ASCII码 ANL A,#0FH ;保留低半字节 SWAP A ;移至高半字节 MOV 20H,A ;存于20H单元 MOV A,22H ;取个位ASCII码 ANL A,#0FH ;保留低半字节 ORL 20H,A ;合并到结果单元 SJMP $ END,【例4-1】片内RAM的21H单元存放一个十进制数据十位的ASCII码,22H单元存放该数据个位的ASCII码。编写程序将该数据转换成压缩BCD码存放在20H单元。,4.3.1 顺序程序,(无分支、无循环),基本程序结构,4.3,2020/10/4,18,4.3.2 分支程序,(单分支、双分支、多分支),【例4-2】设变量x以补码的形式存放在片内RAM的30H单元,变量y与x的关系是:当x大于0时,y=x;当x=0时,y=20H;当x小于0时,y=x+5。编制程序,根据x的大小求y并送回原单元。,ORG 0040H START:MOV A,30H ;取x至累加器 JZ NEXT ;x = 0,转NEXT ANL A,#80H ;否,保留符号位 JZ DONE ;x 0,转结束 MOV A,#05H ;x 0处理 ADD A,30H MOV 30H,A ;X+05H送Y SJMP DONE NEXT:MOV 30H,#20H ;x = 0,20H送Y DONE:SJMP DONE END,JNB ACC.7,DONE,ADD A,#5,2020/10/4,19,【例4-3】根据R7的内容x(转移序号)转向相应的处理程序。 设R7内容为04,对应的处理程序入口地址分别为PP0PP4。,2020/10/4,20,START:MOV R7,#3 ;以转移序号3为例 ACALL JPNUM AJMP START,【例4-3】根据R7的内容x(转移序号)转向相应的处理程序。 设R7内容为04,对应的处理程序入口地址分别为PP0PP4。,JPNUM:MOV DPTR,#TAB MOV A,R7 ADD A,R7 MOV R3,A MOVC A,A+DPTR XCH A,R3 INC A MOVC A,A+DPTR MOV DPL,A MOV DPH,R3 CLR A JMP A+DPTR TAB:DW PP0 DW PP1 DW PPN,PUSH ACC MOV A,R3 PUSH ACC RET,PP0:. RET PP1: RET PP2:. RET PP3: RET PP4: RET,2020/10/4,21,JPNUM:MOV DPTR,TAB MOV A,R7 ADD A,R7 JNC NOAD INC DPH NOAD: JMP A+DPTR TAB: AJMP PP0 AJMP PP1 AJMP PPN,PP0:. RET PP1: RET PP2:. RET PP3: RET PPN: RET,2020/10/4,22,4.3.3 循环程序,(2种:先执行,后判断;先判断,后执行),【例4-4】将内部RAM的30H至3FH单元初始化为00H。,MAIN:MOV R0,#30H ;置初值 MOV A,#00H ; MOV R7,#16 ; LOOP:MOV R0,A ;循环处理 INC R0 ; DJNZ R7,LOOP ;循环修改,判结束 SJMP $ ;结束处理,2020/10/4,23,【例4-5】将内部RAM起始地址为60H的数据串传送到外部RAM中起始地址为1000H的存储区域,直到发现$ 字符停止传送。,MAIN:MOV R0,#60H ;置初值 MOV DPTR,#1000H LOOP0:MOV A,R0 ;取数据 CJNE A,#24H,LOOP1 ;循环结束? SJMP DONE ;是 LOOP1:MOVX DPTR,A ;循环处理 INC R0 ;循环修改 INC DPTR SJMP LOOP0 ;继续循环 DONE:SJMP DONE ;结束处理,2020/10/4,24,例:50ms延时程序。fosc=12MHz.Tc=1s,DEL2:DJNZ R6,DEL2,;2s,DEL1:MOV R6,#123,(2123)=246s,;1s,DJNZ R7,DEL1,;1s,NOP,;1s,246s+1+1+2,DEL:MOV R7,#200,(246s+1+1+2)200,(246s+1+1+2)200+1+2=500003s,;1s,;2s,RET,P110有其他的延时子程序,2020/10/4,25,4.4 子程序及其调用,完成通用功能、反复使用的程序设计成子程序。使应用程序结构清晰紧凑,便于阅读和调试,执行要由其它程序来调用,执行完后要返回到调用程序,结构上仍然采用一般程序的3种结构,调用时注意: 一是现场的保护和恢复; 二是主程序与子程序间的参数传递。,2020/10/4,26,4.4.1 现场保护与恢复,在主程序中实现(结构灵活),PUSH PSW ;保护现场( 含当前工作寄存器组号) PUSH ACC ; PUSH B ; MOV PSW,#10H ;切换当前工作寄存器组 LCALL addr16 ;子程序调用, POP B ;恢复现场 POP ACC ; POP PSW ;含当前工作寄存器组切换,2020/10/4,27,在子程序中实现(程序规范、清晰),SUB1:PUSH PSW ;保护现场( 含当前工作寄存器组号) PUSH ACC ; PUSH B ; MOV PSW,#10H ;切换当前工作寄存器组 POP B ;恢复现场 POP ACC ; POP PSW ;内含当前工作寄存器组切换 RET,2020/10/4,28,4.4.2 参数传递,利用累加器或寄存器(简单、快速,但参数个数不多),【例4-6】实现两个8位的十六进制无符号数求和的子程序。,SADD:MOV A,R3 ;取加数(在R3中) CLR C ADD A,R4 ;被加数(在R4中)加A JC PP1 MOV R3,#00H ;结果小于255时,高字节R3内容为00H SJMP PP2 PP1:MOV R3,#01H ;结果大于255时,高字节R3内容为01H PP2:MOV R4,A ;结果的低字节在R4中 RET,入口:(R3)=加数; (R4)=被加数。,出口:(R3)=和的高字节; (R4)=和的低字节。,2020/10/4,29,利用存储器(个数多,用R0或R1及DPTR为参数表指针),【例4-7】将内部RAM 中两个4字节无符号整数相加,和的高字节由R0指向。数据采用大端模式存储。,入口:(R0)=加数低字节地址; (R1)=被加数低字节地址。,出口:(R0)=和的高字节起始地址。,NADD:MOV R7,#4 ;字节数4送计数器 CLR C ; NADD1:MOV A,R0 ;利用指针,取加数低字节 ADDC A,R1 ;利用指针,被加数低字节加A MOV R0,A ; DEC R0 DEC R1 DJNZ R7,NADD1 INC R0 ;调整指针,指向出口 RET,2020/10/4,30, 通过堆栈传递参数,解: 由于要进行两次转换,故可调用查表子程序完成,主程序,*PCH,*PCL,HEX,栈底,断点地址,上页,下页,回目录,2020/10/4,31,子程序,上页,下页,回目录,HEX,Result,Result,PC,2020/10/4,32,HEX,HEX,*PCL,*PCH,断点,ASC,主程序,子程序,上页,下页,回目录,2020/10/4,33,利用堆栈,【例4-8】 将内部RAM中20H单元中的1个字节十六进制数转换为2位ASCII码,存放在R0指示的两个单元中。,入口:预转换数据(低半字节)在栈顶,出口:转换结果(ASCII码)在栈顶,HEASC:MOV R1,SP ;借用R1为堆栈指针 DEC R1 DEC R1 ;R1指向被转换数据 XCH A,R1 ;取被转换数据 ANL A,#0FH ;取一位十六进制数 ADD A,#2 ;偏移调整,所加值为MOVC与DB间总字节数 MOVC A,A+PC ;查表 XCH A,R1 ;1字节指令,存结果于堆栈中 RET ;1字节指令 ASCTAB:DB 30H,31H,32H,33H,34H,35H,36H,37H DB 38H,39H,41H,42H,43H,44H,45H,46H,2020/10/4,34,验证程序段,MAIN:MOV A,20H ; SWAP A PUSH ACC ;预转换的数据(在低半字节)入栈 ACALL HEASC POP ACC ;弹出栈顶结果于ACC中 MOV R0,A ;存转换结果高字节 INC R0 ;修改指针 PUSH 20H ;预转换的数据(在低半字节)入栈 ACALL HEASC POP ACC ;弹出栈顶结果于ACC中 MOV R0,A ;存转换结果低字节 SJMP $,2020/10/4,35,4.4.3 常用子程序示例,一算术运算程序 例:多字节数 的加、减运算,;入口参数(R0)=被减数低字节地址 ; (R1)=减数低字节地址 ; (R7)=字节数 ;出口参数(R1)=差的高字节地址(起始地址),NSUBCLR C NSUB1:MOV A,R0 SUBB A,R1 MOV R1,A DEC R0 DEC R1 DJNZ R7, LOOP INC R1 RET,MOV R7,#16 MOV R0,#3FH MOV R1,#4FH ACALL NUSB ,2020/10/4,36,例4-10 双字节无符号数快速乘法子程序MULD,功能: 双字节无符号数乘法,积为32位,编程思路与手乘法相似:,bdH,bdL,adH,adL,bcL,bcH,acL,acH,bdL,adH,出口:(R0)= 积的高字节地址,2020/10/4,37,BMUL:MOV A,R3 ; MOV B,R5 ; MUL AB ;低位乘 ACALL RADD; MOV A,R3; MOV B,R4; MUL AB ;交叉乘 DEC R0 ; ACALL RADD; MOV A,R8; MOV B,R5; MUL AB ;交叉乘 DEC R0 ; DEC R0 ; ACALL RADD; MOV A,R2; MOV B,R4; MUL AB ;高字节乘 DEC R0 ; ACALL RADD; DEC R0 RET,ADD A,R0 MOV R0,A MOV A,B INC R0 ADDC A,R0 MOV R0,A INC R0 MOV A,R0 ADDC A,#00H MOV R0,A RET,RADD:,2020/10/4,38,例:16位8位无符号数除法。被除数存放在R6、R5(R6高8位,R5低8位)中,除数存放在R2中,商存放在R5中,余数存放在R6中。,商 数 除 数被除数 -除数;试做减法,够减商上1 余数 - 除数 不够减,商上0,并恢复减法前的余数 余数 - 除数 ;再做减法 ,2020/10/4,39,(2);程序名:DDIV ;功能:16位8位无符号数除法 ;入口参数:被除数R6、R5,除数在R2中 ;出口参数:商R5,余数R6 ;占用资源:F0作为标志位暂存单元,DDIV:PUSHPSW MOVR7,#08H;R7次数 DDIV1:CLRC;清CY MOVA,R5;余数左移1位(第1次为被除数) RLCA;CYR5R60 MOVR5,A MOVA,R6 RLCA MOVF0,C; CLRC SUBBA,R2;高位余数-除数 JBF0,NEXT;若标志位为1,则够减 JNCNEXT;没有借位,也说明够减 ADDA,R2;否则,不够减,恢复余数 SJMPNEXT1 NEXT:INCR5;够减,商上1 NEXT1:MOVR6,A;保存余数 DJNZR7,DDIV1 POPPSW RET,2020/10/4,40,例4-11利用子程序c=a2+b2,;入口参数(A)=预平方数 ;出口参数(A)=平方值 SQR:MOV DPTR,#TAB MOVC A,A+DPTR RET TAB:DB 1,4,9,16,25,36,49,64,81,09H,2020/10/4,41,;入口参数(A)=预平方数 ;出口参数(A)=平方值 SQR:MOV DPTR,#TAB MOVC A,A+DPTR RET TAB:DB 1,4,9,16,25,36,49,64,81,MAIN:MOV 30H,#4 MOV 31H,#5 MOV A,30H ACALL SQR MOV R1,A MOV A,31H ACALL SQR ADD A,R1 MOV 32H,A SJMP $,例4-11利用子程序(32H)=(30H)2+(31H)2,2020/10/4,42,三、码型转换,1、十六进制数与ASCII码间的转换,HASC:MOV A,R0;取4位二进制数 ANL A,#0FH;屏蔽掉高4位 PUSH ACC;4位二进制数入栈 CLR C ;清进(借)位位 SUBB A,#0AH POP ACC ;弹出原4位二进制数 JC LOOP ;借位位为1,跳转至LOOP ADD A,#07H;借位位为0,该数在AF之间,加37H LOOP:ADD A,#30H;该数在09之间,加30H MOV R2,A;ASCII码存于R2 RET,入口参数(R0)=16进制 出口参数(R2)=ASCII,MAIN:MOV R0,#0BH ACALL HASC SJMP $,2020/10/4,43,2、二进制数与十进制转换,将某8位二进制数转换为BCD码。,HTBCD:MOV A,R2 MOV B,#100 DIV AB;除100 MOV R2,A XCH A,B MOV B,#10 DIV AB;除10 MOV R3,A MOV R4,B RET,入口参数:R2 出口参数:R2R3R4,253=2*100+5*10+3,2020/10/4,44,将某8位二进制数 转换为BCD码。,DCDTH:CLR A ; MOV R2,A ;R4清0 MOV R3,A ;R5清0 MOV R7,#8;计数初值 LOOP: CLR C ; MOV A,R2; RLC A ; MOV R2,A;R2左移一位并送回 MOV A,R4; ADDC A,R4; DA A ; MOV R4,A;R3乘2并调整后送回 MOV A,R3; ADDC A,R3; DA A ; MOV R3,A;R4乘2并调整后送回 DJNZ R7,LOOP ; RET,入口参数:R2 出口参数:R3R4,B727B626B525B424B323B222B121B020 =(B72B6)26B525B424B323B222B121B020,(02+B7)2B6)2B5)2B4)2B3)2B2)2B1)2B0,(02+B7),(02+B7)2B6,(02+B7)2B6)2B5,(02+B7)2B6)2B5)2B4,(02+B7)2B6)2B5)2B4)2B3,(02+B7)2B6)2B5)2B4)2B3)2B2,(02+B7)2B6)2B5)2B4)2B3)2B2)2B1,=,2020/10/4,45,4.5 简单I/O设备的并口直接驱动示例,4.5.1 独立式键盘与LED显示示例,【例4-17】数据端与P0口正序连接。编写程序,分别实现功能:上电后数码管显示“P”,按下任何键后,显示从“0”开始每隔1秒加1,加至“F”后,数码管显示“P”,进入等待按键状态。,2020/10/4,46,TEMP EQU 30H ORG 0000H JMP START ORG 0100H START:MOV SP,#5FH MOV P0,#8CH ;显示P MOV P3,#0FFH NOKEY:MOV A,P3 CPL A JZ NOKEY ;无键按下 MOV TEMP,P3 ;有键按下 CALL D10ms MOV A,P3 CJNE A,TEMP,NOKEY;去抖 MOV R7,#16 MOV R2,#0,LOOP:MOV A,R2 MOV DPTR,#CODE_P0 MOVC A,A+DPTR MOV P0,A INC R2 SETB RS0 ;切换组 CALL D_1S CLR RS0 DJNZ R7,LOOP JMP START,D_1S:(子程序) D10ms:(子程序),CODE_P0:DB 0C0H,0F9H,0A4H,0B0H DB 99H,92H,82H,0F8H DB 80H,90H,88H,83H, DB 0C6H,0A1H,86H,8EH,2020/10/4,47,有时为方便走线而采用逆序连接,显示段码要进行调整: CODE_P2:DB 03H,9FH,25H,0DH,99H,49H,40H,1FH DB 01H,09H,11H,0C1H,63H,85H,61H,71H,CODE_P0:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H DB 80H,90H,88H,83H,0C6H,0A1H,86H,8EH,试比较:,2020/10/4,48,4.5.2 矩阵式键盘与LED显示示例,步骤:判有无键按下、判按下哪个键 、依键号进入相应程序,2020/10/4,49,判有无键按下 行线接输入口,列线接输出口。置所有列线为低电平,然后读行线状态,若行线均为高电平,则没有键按下;若行线状态不全为高电平,则可断定有键按下。,判按下哪个键 先让C0列为低电平,其余列线为高电平,读行线状态,如行线状态不全为“1”,则说明所按键在该列;否则所按键不在该列,再使C1列线为低电平,其它列为高电平,判断C1列有无按键按下。,进入相应程序 键号 = 行首号+列号。 根据键号进入相应的功能程序。,(程序略),2020/10/4,50,列数多时可用线反转法(依据键号与键值的对应关系 )。如“D”号键,先使行线输出全“0”,读列线,结果为D0H;再使列线输出全“0”,读行线,结果为07H。2次读的结果拼成一个字节,即D7H,该值称为键值。,将键值与键号的对应关系列成一个有序表,并设置一个计数器,将所按键值用线反转法求出后,将其作为关键字在键值表中从表首开始计数查找,查到匹配处时相应的计数值就是键号,根据键号就可以进入相应的处理程序了。,Thank You !,
展开阅读全文