[原创]伟福与Keil的比较--51汇编提高篇
hefanghua2011/04/23电子技术 IP:广西

[写在前面]
本文适合有一定汇编水平的人(了解大半的汇编语句,能区分全角与半角符号,能够独立编写流水灯、数码管等程序),传授51单片机的汇编语言经验。如果您发现不少指令不知道意思,请从网上搜索入门教程学习。本人编程有几年了,虽然不是高手,只以老手自居,写点经验分享,希望对编程有帮助。

[优缺点比较]
Keil是德国人开发出来的一款集成开发环境,与它同类的软件还有IAR等等。Keil自带有简单的调试工具ISD5与较复杂RTX51 OS,可以与proteus联合调试,能够不接硬件进行调试。虽然拥有强大的功能,但是软件是要钱的,用HX版总归不好,且全英文界面不适合新手。由于keil用得少,它的毛病没找出多少。以下是Keil μvision3(以下简称keil)的一些问题归纳:
1. 对汇编文件进行编译时使允许用C语言的语法,不规范,在标准汇编器上会报错。比如引用符号/* */,以及表格部分。
2. Keil必须把源文件放入工程文件中才可标记语法。
3. Keil的标题“礦ision3”(可参考网上的修改方法)
4. Keil的某些版本光标定位不准。出现字符与实际错位的现象(解决办法:在字体的ASM、C编译列表里,改text字体为fixedsys,大小为10)
5. Keil的汉字问题。对部分汉字的ASCII码引用出错误,导致液晶上看到的不对。(也请参考网上的修改办法)--偶暂时没遇到额。
6. 可以整段拖动,是优点也是缺点,有可能打瞌睡不小心移动了都不知道。
7. keil无法使用PSW寄存器里面留给用户使用的f0, f1位地址,不知道什么原因,这点比较郁闷。
8. "Go To Definiton Of 'xxx'"在汇编里是废的

伟福WAVE6000不出名,主要特点是免费,软件体积小等等。它也有不少问题:
1.长时间使用wave可能导致一些莫明其妙的错误,比如:编译得不到正确结果,进不了中断现象,软件仿真时指针不前进等怪问题。关掉软件重新打开即可。另外,请备份一个设置好的XXXXXXXi文件,如果遇到打字的速度变得贼慢,覆盖掉它就解决了。
2. WAVE的窗口比较残疾。刚打开的时候不是最大化的,一不小心就挪走了(偶的鼠标比较龊)。点击任务栏不能最小化,而是“恢复窗口”。不能记忆编写的位置,这点比不上keil。
3. 比较跳转之类的指令,如果编写有错,WAVE经常不能指向错误所在行。(解决办法见提高部分的“跳转范围”)
4. 伟福编译器的位地址BIT显示到了0FFH,过了7F以后都无法在RAM里看到修改结果,即为无效。--BUG之一
5. WAVE仿真首次运行时时间不对,运行时间超过分钟级别也会不正确(运行数分钟以上的程序会出现时间不停、回0的现象),是编译器问题。
6. 原版WAVE不支持鼠标滚轮翻页,已找到解决方案,见参考资料。

在51单片机汇编下,WAVE与Keil两者的比较:
1. keil只能用EQU语句定义,不能直接用=号定义, 而WAVE可以用=定义(定义数值、口线、特殊寄存器地址等),但不等同于字符串替换。
2. keil包含文件采用#include "XXXXXXXXXXXX"的形式,不能有中文符号;WAVE少个#号,可以有中文符号。(具体用法见提高部分)
3. Keil设置中文字体后,可以整个字符操作(需在注释里面才能显示);WAVE却把一个汉字当两个字符处理了。(<伟福软件的另类用法>我们可以利用这特点快速显示网页部分内容的乱码:把乱码部分拷到伟福里,然后用鼠标从乱码的开头开始算的半个字开始拖动,原来的乱码一下就全正常了。原因是网页里的文字是以两字节存储的,由于传输等问题导致正好多了或少了一个字节,则该行全部内容不能正常识别显示。)
4. 在表格部分,keil不允许每行最后一个数据后面有逗号, WAVE可以。
5. 在END结束后面如果有中文字符, keil会乱报错,WAVE则无视之。

[一些经验]
1. WAVE出现"错误 346: ORG 错",并指向ORG 0(一般犯错是在多文件包含模式),说明主文件中在包含ORG 0的语句前出现指令。
2. 不能同时开多个不关联文件调试, 容易调错文件。如果同时打开多个源程序就不能使用“全部编译”功能。
3. 对于超出的数,编译器将超出位(高位)去掉。如果用的是keil,还会看到警告提示。
4. WAVE与keil都不能正确显示所谓1T的STC指令执行时间,自己手算吧。哪位有计算一段指令执行时间的好软件,不妨推荐下。
5. 我自己建立的keil工程编译总是出错,不知道哪里没设置对。我采取从正确的程序里拷*.uv2过来,添加源文件就可以用了。

[提高部分]
为什么有些汇编文件看了头大,主要还是编写没有规范,纯粹代码的堆叠。编程应该统一规范,可借鉴C语言规范的特点。文件开头先写明程序的注释,分几块写口线定义、位定义、寄存器定义、数值定义等,然后是51单片机的中断入口,接着到主程序和主循环,往下为子程序、中断处理程序,最后到表格(如果表格很短也可放到对应子程序下方)。子程序名顶头写,里面每一级判断嵌套都缩进2个空格,算法完成一步可空一行,RET返回也顶头写,这样排版就不会让人想晕。注释应当合适,不要所有指令都写上,子程序的功能、入口、出口要注明,关键语句也加上注释。
将两个及以上变量定义到同一个寄存器属于寄存器地址重复使用,汇编器是不会报错的。用的时候千万小心,只能分时使用,或者当一个用,否则查错会让人抓狂。
有些书上没讲到的补充一下:打JMP等效于LJMP, CALL等效于LCALL,$为跳转到当前语句所在行。A5指令,也就是DB 0A5H这个数据表,51运行时当几个NOP处理,加蜜用。一些指令需配合其它指令才能发挥正确的作用,比如SUBB A,#Num, 该句会把进位/借位C一起计算,如果不需要应该CLR C;再比如MOVC A,@A+DPTR,根据需要CLR A或者把A作为偏移量一起用。
有了以上的认识,我们可以扬长避短,两个软件一起使用!首先确保源文件不要同时被打开,然后是使用两者都支持的语句,将C版的表格用WORD替换成汇编版(见C转汇编部分),最后再用条件编译选择其一汇编器。

一、条件汇编(条件编译)
汇编器(编译器)根据条件是否成立,决定是否对里面的代码进行汇编,不合条件的不参与汇编,被忽视掉。支持ELSEIF,支持嵌套。可用于软件调试过程中直接跳过死循环等。条件是否成立的判断,我测试可用的只有等于,可以等于许多数值。比如先定义:
WAVE_Keil equ 1
然后在需要分开不同汇编器的地方加入以下条件汇编:
if WAVE_Keil =1 ;包含STC的定义
#include "XXXXXXXXXXXXc" ;for Keil uv3 compiler
else
include "XXXXXXXXXXXXc" ;for WAVE6000 assembler
endif

二、include包含文件
汇编的包含文件不同于C语言的,它是源文件的一部分,放到主文件中顺序自然有讲究。它可以在被包含的文件里又包含其它文件(不同汇编器支持的层数不同,不宜多)。要求:
(1)后缀不限,但应为ASCII码.(建议用INC后缀)
(2)尽量与主文件在同一目录中。
(3)包含文件中不能有END语句。
它有3种用法(依此类推, 换一个目录可由它们复合而成):
⑴在同级目录,最常用,不容易修改错一个文件。
⑵包含文件在下一级目录中,写为:include"folder\XXXXXXXXXXXXc"
⑶包含文件在上一级目录中,写为:include "..\XXXXXXXXXXXXc"

三、汇编宏定义
我只了解皮毛而已,什么macro在WAVE上没能捣腾出来,keil上虽能通过编译,但不知道具体有什么用。
我们可以对数值用另一数值定义,数值可以加减乘除计算,最终结果是固定的数值就行。不过算式不能太复杂,具体由编译器决定(可参考伟福6000使用帮助)。宏定义的好处是可以对改动频繁的数据做快速修改,原本不能位寻址的一些位,可以被拆开分别赋值。举个例子,STC 5A系列的第2串口是新增加的功能,给AUXR赋初值的数据里揉了些串口以外的位,以前专门为串口写的初值计算设置程序又得重写了,这里我们只需用宏定义实现:
;---第2串口的宏定义---
T0x12 equ 0 ;=0: T0为普通12T, =1: T0为1T
T1x12 equ 0 ;=0: T1为普通12T, =1: T1为1T
UART_M0x6 equ 0 ;=0: UART1为普通12T, =1: UART为6T(6倍)
BRTR equ 1 ;=1: 启动独立波特率发生器BRT, =0: 停止BRT
S2SMOD equ 1 ;=1: UART2的波特率 x2. (=0: BRT的溢出率/32, =1: 溢出率/16)
BRTx12 equ 0 ;=0: BRT为普通12T, =1: BRT为1T
EXTRAM equ 0 ;=0: 使用内部扩展的XRAM, =1: 只使用外部数据存储器(XRAM)
S1BRS equ 1 ;=1: 用BRT作波特率发生器, =0: UART用T1作波特率发生器
AUXR_Dat equ T0x12*80h +T1x12*40h +UART_M0x6*20h +BRTR*10h +S2SMOD*8 +BRTx12*4 +EXTRAM*2 +S1BRS

S2SM equ 1 ;=0: 方式0, 同步移位串行方式, Fosc/12, =1: 方式1, 8位可变波特率,
;=2: 方式2, 9位固定波特率, =3: 方式3, 9位可变波特率
S2SM2 equ 0 ;?
S2REN equ 1 ;允许第2串口接收
S2TB8 equ 0 ;方式2、3时为第9位数据位
S2RB8 equ 0 ;方式1时为接收到的停止位
S2TI equ 0 ;第2串口发送完成标志
S2RI equ 0 ;第2串口接收完成标志
S2CON_Dat equ S2SM*40h +S2SM2*20h +S2REN*10h +S2TB8*8 +S2RB8*4 +S2TI*2 +S2RI
;---第2串口的宏定义 by HeFanghua---

AUXR_Dat跟S2CON_Dat就是我们要赋的值,修改串口方式只需改S2CON_Dat上面几个单独的位即可。S2SM可以等于0、1、2、3,正好与方式0~3一一对应。在程序中赋值,用以下语句:
MOV S2CON, #S2CON_Dat
简单吧?。

接着举个数据表格宏定义的例子:
DB S2CON_Dat*1, AUXR_Dat, (S2CON_Dat + AUXR_Dat)/2 ,00h ;这样都行
DB "Good" ;ASCII码的字符串数据
DW 0D0Ah ;ASCII码的回车符, 大端存储模式

四、跳转范围
比较跳转之类的指令包括CJNE, DJNZ, JB等,这类指令如果编写有错,WAVE会指向65536行(不存在),到了反汇编窗口。可采取从最远的条件跳转开始搜索排错。如果跳转超出范围,则应该给它加一个长跳转。比如JZ rel指令,rel是个- +127的数(偏移量),该数由编译器计算标号的实际位置自动得到。如果JZ指令与标号中间隔了许多代码,导致标号离得太远就会超出范围。
解决办法是在没超出的地方,一般是在JMP语句下面写跳转到的中间标号,然后再JMP到需要跳转之处(JMP的范围是64KB,大于64K的特殊51单片机没玩过,有兴趣可以试下)。如果遇到一段很长又没有JMP的代码,只能用JMP把代码打断一行再放入了。举例:

DS 300 ;假设是一段很长的代码
JZ run
NOP
DS 256 ;假设也是一段很长的代码
run:
NOP


打断长代码后改写为:
DS 300
JZ run_1
NOP
DS 120
jmp code_next1
;打断出来的空隙
run_1:
jmp run
code_next1:
DS 136
run:
NOP

五、C转汇编
8位以上的数据计算会比较麻烦,我们可以找段现成的C代码,用keil反汇编来参考编写。反汇编尽量少用,keil反汇编出来的代码超难理解。转换的步骤是:1.归纳C程序的流程,2.转换简单的部分(寄存器定义等) 3.逐个读懂各子函数,4.参考keil提供的反汇编 5.其它整理、检查、调试工作。其实就是把自己当成编译器编译C的过程,还是少转为妙,费时费力效果不好。有些软件只能生成C的表格(比如Image2Lcd),用WORD替换的速度比别的快, 不过偶尔有几行回车漏掉替换。下面讲下C语言版的表格转汇编版过程。
在WORD里选择:替换->查找内容:(即->高级->特殊字符->段落标记)。然后按以下步骤依次替换内容:
步骤⑴
,^p
替换为:
h^pDB□
其中□表示空格
步骤⑵
,0x替换成h,0
步骤⑶
0x替换成0
步骤⑷
手动检查下错漏,在步骤⑴时WORD经常漏替换

[打包输出]
其实除了源文件外,一些大些的程序最好有流程图、状态机,方便日后查阅维护。
WAVE的输出除了ASM和inc包含文件之外,还有个Hex文件或者BIN文件。BIN文件与HEX都可烧录,BIN打包后体积更小。
keil编译出来的文件,除了以上几个,最好保留*.uv2工程文件,其它的用不到。Keil也可得到BIN文件,请参考下面的贴《用keil直接生成BIN文件》。

[参考资料]
其他人的相关帖子请参考:
<南京伟福仿真器IDE鼠标滚轮外挂>
XXXXXXXXXXXXXXXXXXXXXXXX/t/31254
<用keil直接生成BIN文件>

用keil直接生成BIN文件
1.下载hex2bin到keil的任意目录,下载地址:XXXXXXXXXXXXXXXXXXX/download/docs/XXXXp 或者 XXXXXXXXXXXXXXXXXXXXXX/files/hex2bin.zip
2.然后"option for target ......"选项里面的output标签,下面有after make框架,选中"Run User Program #1" 。然后填入HEX2BIN.exe所在目录,同时加上生成的HEX文件名(在name of executable里设置的名字),比如“D:\Keil\UV2\HEX2BIN.EXE 12232.hex”
这样编译完成后,会自动产生bin文件。

+2000  科创币    科创网    2011/04/24 原创分享。对本帖内容,版主进行过详细讨论,对于这种商品级系统,希望站在商业应用的角度看待问题。
来自:电子信息 / 电子技术
2
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
dome
10年1个月前 IP:广东
735836
相当感谢
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
hefanghua
学者 笔友
文章
34
回复
860
学术分
2
2010/06/26注册,1年0个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}