3.3.2 汇编语言的程序编辑和汇编
伪指令
用DJNZ设计延时子程序
课本P68【例3-15】介绍如何实现20s的延时,视频讲解如何实现1s的延时。
汇编程序结构框架
编写汇编程序,一般应遵循图1所示框架;阅读他人编写的汇编程序,也可以按图1所示框架将其进行分解。
1.单片机复位后,(PC)=0000H,从0000H单元开始执行程序;此处放一条跳转指令,跳转到主函数。
2.在主函数前面的,是中断服务程序入口地址。
3.普通的8051单片机,中断源只有5个或者6个,主函数可以放置在0030H单元处;对于高性能的单片机,中断源比较多,主函数放置的位置比0030单元要靠后。
4.主函数开始后,要先对系统进行初始化,然后执行主循环;主循环里面可以调用普通的子程序,如果主循环什么事情都不做,就可以执行空操作;为了防止程序跑飞,主循环必不可少。
5.普通子程序和中断服务子程序放置在主循环的外面。
6.表格通常放在所有程序的后面。
7.最后程序以伪指令END结束。
文似看山不喜平,写程序要注意缩进,要有层次感。一般情况,标号左对齐,指令缩进若干个字符。

图1 汇编程序结构框架
★温馨提示:本部分内容选自《单片机学习与实践教程》,朱向庆编著,北京邮电大学出版社,2018年出版,引用请注明出处。
★温馨提示:本部分内容选自《单片机学习与实践教程》,朱向庆编著,北京邮电大学出版社,2018年出版,引用请注明出处。
Keil μVision编译错误与解决方法
标号、助记符、寄存器、立即数等,Keil μVision软件会用不同颜色显示,拼写错误时颜色会变化。编写代码的过程中可以通过颜色初步判断是否有问题。

图1 汇编代码
1. Interruption.asm(0): error A9: : SYNTAX ERROR
说明:第0行语法错误。
解决方法:语法错误的原因很多,例如:(1)混用字母O(哦)与数字0(零)、字母l(L的小写)与数字1(一);(2)错写、多写、漏写助记符、寄存器名称等;(3)将英文标点符号写成中文标点符号(汇编程序除了注释,其他地方必须使用英文标点符号)。
2. Interruption.asm(2): error A45: UNDEFINED SYMBOL (PASS-2)
说明:第2行符号未定义,例如:(1)标号拼写错误,MAIN拼写为MAIN2;(2)特殊功能寄存器或者其位名称拼写错误,P1(数字1)拼写为Pl(字母l),IT0拼写为ITO;(3)十六进制A~F开始的立即数,前面没有加0,#0FFH拼写为#FFH。
解决方法:仔细检查标号、子函数名称、寄存器名称、位名称等是否错写、多写、漏写字母或数字等。
3. Interruption.asm(2): error A51: TARGET OUT OF RANGE
说明:目标超出了范围,通常出在SJMP rel、AJMP addr11或者ACALL addr11这3条指令,跳转范围或者调用子函数的范围超出了该指令的最大范围。
解决方法:将SJMP改为AJMP或LJMP,AJMP改为LJMP,ACALL改为LCALL。
4. Interruption.asm(19): error A22: EXPRESSION TYPE DOES NOT MATCH INSTRUCTION
说明:表达式形式跟指令不匹配。
解决方法:没有按汇编的语法写指令,例如:PUSH ACC误写成PUSH A,前者是直接寻址,后者是寄存器寻址。
5. Interruption.asm(22): error A4: BAD INDIRECT REGISTER
说明:错误的间接寻址寄存器。
解决方法:寄存器间接寻址只能使用R0、R1或者DPTR,例如:MOV @R2, #9是错误的。
6. Interruption.asm(22): error A40: INVALID REGISTER
说明:无效的寄存器。
解决方法:虽然提示寄存器无效,但有可能是助记符出错,例如:(1)MOVC A, @A+DPTR误写成MOV A, @A+DPTR;(2)MOVX A,@DPTR误写成MOVX A, DPTR,MOVX A,@R1误写成MOVX A,R1。
7. Interruption.asm(32): warning A52: VALUE HAS BEEN TRUNCATED TO 8 BITS
说明:数值被缩减至8 bits,给一个8 bits的寄存器或者存储单元赋了超过其最大范围的值,被编译器缩减至8 bits。
解决方法:检查是否误写了立即数,例如:MOV R7, #250错写成MOV R7, #2500;此时编译器将2500除以256,得到余数196(C4H),编译时将R7赋值为196(#0xC4)。此时有逻辑错误,但没有语法错误。

图2 数值越界被缩减至8 bits
8. Interruption.asm(35): error A38: NUMBER OF OPERANDS DOES NOT MATCH INSTRUCTION
说明:操作数的数量跟指令不匹配。
解决方法:仔细检查该助记符对应的指令有几个操作数,例如DJNZ R6, DEL1误写成CJNE R6, DEL1,后者应该有3个操作数。
9. Interruption.asm(36): warning A41: MISSING 'END' STATEMENT
说明:汇编语言结束处,必须以伪指令END结尾,第36行缺少END。
解决方法:在第36行下方增加伪指令END。
一、单片机小精灵
使用图1所示的单片机小精灵软件,可以生成汇编或者C51语言的延时子程序。图1选择了“12T”,指12个振荡周期(时钟周期)为1个机器周期(1Tcy=12/fosc),对于传统的普通单片机(如STC89C52RC,STC-Y1),延时1s。如果将该代码用于高速的1T单片机(如STC12C5A60S2,STC-Y3),延时1/6s。因为该延时子程序大量的时间用于执行DJNZ Rn, rel指令和MOV Rn, #data指令,从图2和图3可见,执行上述两条指令的时间,STC89C52RC是STC12C5A60S2的6倍。
有此可见,移植程序时,对于时序要求严格的程序代码(如单总线方式访问数字温度传感器DS18B20、数字温湿度度传感器DHT11),除了要注意单片机的晶振频率外,还要注意单片机的型号,否则可能出错。

图1 单片机小精灵生成的延时子程序

图2 DJNZ Rn, rel指令

图3 MOV Rn, #data8指令
二、STC-ISP
设计STC单片机的延时子程序,建议使用图4所示STC-ISP自带的“软件延时计算器”。使用该延时计算器时,要注意根据所使用的单片机选择“8051指令集”。选择了指令集后,其右侧会显示适用的STC单片机系列。

图4 STC-ISP自带的“软件延时计算器”
★温馨提示:本部分内容选自《单片机学习与实践教程》,朱向庆编著,北京邮电大学出版社,2018年出版,引用请注明出处。