伟福与Keil的比较--51汇编提高篇
[写在前面]
本文适合有一定汇编水平的人(了解大半的汇编语句,能区分全角与半角符号,能够独立编写流水灯、数码管等程序),传授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可能导致一些莫明其妙的错误,比如:编译得不到正确结果,进不了中断现象,软件仿真时指针不前进等怪问题。关掉软件重新打开即可。另外,请备份一个设置好的wave.ini文件,如果遇到打字的速度变得贼慢,覆盖掉它就解决了。
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 "filename.xxx"的形式,不能有中文符号;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 "STCdefine.inc" ;for Keil uv3 compiler
else
include "STCdefine.inc" ;for WAVE6000 assembler
endif
二、include包含文件
汇编的包含文件不同于C语言的,它是源文件的一部分,放到主文件中顺序自然有讲究。它可以在被包含的文件里又包含其它文件(不同汇编器支持的层数不同,不宜多)。要求:
(1)后缀不限,但应为ASCII码.(建议用INC后缀)
(2)尽量与主文件在同一目录中。
(3)包含文件中不能有END语句。
它有3种用法(依此类推, 换一个目录可由它们复合而成):
⑴在同级目录,最常用,不容易修改错一个文件。
⑵包含文件在下一级目录中,写为:include"folder\hefanghua.inc"
⑶包含文件在上一级目录中,写为:include "..\hefanghua.inc"
三、汇编宏定义
我只了解皮毛而已,什么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鼠标滚轮外挂>
http://www.kechuang.ac.cn/read.php?tid=31254
伟福与Keil的比较--51汇编提高篇的更多相关文章
- Keil uVision4 创建51单片机工程
Keil uVision4 创建51单片机工程 版权声明:未经授权,严禁转载! 在学习51单片机的过程当中,我们需要使用 Keil uVision4 来创建一个项目,今天就来图示一下创建的流程. 首先 ...
- 鸿蒙内核源码分析(汇编汇总篇) | 所有的汇编代码都在这里 | 百篇博客分析OpenHarmony源码 | v40.03
百篇博客系列篇.本篇为: v40.xx 鸿蒙内核源码分析(汇编汇总篇) | 汇编可爱如邻家女孩 | 51.c.h .o 硬件架构相关篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪 ...
- 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班? | 百篇博客分析OpenHarmony源码 | v22.01
百篇博客系列篇.本篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班 | 51.c.h .o 硬件架构相关篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在 ...
- KEIL C51 中嵌入汇编以及C51与A51间的相互调用
如何在 KEIL C51(v6.21) 中调用汇编函数的一个示例 有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者通过一个简单例子 ...
- keil Uvision4 面向51单片机数据类型属性一览表
- 洗礼灵魂,修炼python(51)--爬虫篇—变色龙般的伪装
变色龙原理 变色龙这种动物想必大家都了解,它们会根据周遭环境的局势来改变自己的颜色,伪装自己. 那么爬虫有这种技能吗?当然是有的,先不着急说这个问题. 从上一篇开始,你有没有想过,站在网站管理的角度, ...
- 51单片机 Keil C 延时程序的简单研究
应用单片机的时候,经常会遇到需要短时间延时的情况.需要的延时时间很短,一般都是几十到几百微妙(us).有时候还需要很高的精度,比如用单片机驱动DS18B20的时候,误差容许的范围在十几us以内,不然很 ...
- Keil 中关于C语言编译生成汇编代码函数名规则
在keil 中 C语言的函数有带参数和不带参数之分. 一般的资料里说fun(void)类型的函数不带参数,所以,keil编译器生成的汇编的调用地址(函数名) 为fun.这没有错.事实上,不管C语言的函 ...
- keil C 应注意的几个问题
我们使用Keil C调试某系统时积累的一些经验 1.在Windows2000下面,我们可以把字体设置为Courier,这样就可以显示正常.2.当使用有片外内存的MCU(如W77E58,它有1K片外内存 ...
随机推荐
- 关于标准C语言的预定义宏
标准C语言预处理要求定义某些对象宏,每个预定义宏的名称一两个下划线字符开头和结尾,这些预定义宏不能被取消定义(#undef)或由编程人员重新定义.下面预定义宏表,被我抄了下来.__LINE__ 当前 ...
- EF 接收OUTPUT参数的方法 How to Retrieve Stored Procedure Output Parameters in Entity Framework
原文地址:http://blogs.microsoft.co.il/gilf/2010/05/09/how-to-retrieve-stored-procedure-output-parameters ...
- Dijkstra优先队列优化
Dijkstra算法的核心思想就是两步排序,一个是对于一个点而言,他的最小边要经过所有其他点最小边的测试才能确认,也就是说要在这其中找一个最大的边出来:第二个是对于每次循环而言的,每次的更新d数组都是 ...
- enable ide
http://pve.proxmox.com/wiki/Migration_of_servers_to_Proxmox_VE The vmware system consists of two dis ...
- 取得select框的text
function selectInput(choose) { alert(choose.options[choose.selectedIndex].text); }
- MySQL日期函数
1.已知出生日期,求年龄 SELECT '1992-04-10' as birthday, curdate(), ( YEAR (curdate()) - YEAR ('1992-04-10')-1 ...
- web性能优化——JSP
一.啰嗦 做web开发的都知道,性能的重要性就不必强调了.就前端展示的工作来说,jsp大家都熟悉html更熟悉:web服务器tomcat应该是最熟悉的了:web方面的基础知识上来说,静态页面比动态页面 ...
- Java基础知识强化61:经典查找之 常见查找算法小结
一.顺序查找 条件:无序或有序队列. 原理:按顺序比较每个元素,直到找到关键字为止. 时间复杂度:O(n) 二.二分查找(折半查找) 条件:有序数组 原理:查找过程从数组的中间元素开始,如果中间元素正 ...
- Java基础知识强化35:String类之String的其他功能
1. String类的其他功能: (1)替换功能: String replace(char old, char new) String replace(String old,String new) ( ...
- TreeGrid( 树形表格)
本节课重点了解 EasyUI 中 TreeGrid(树形表格)组件的使用方法,这个组件依赖于DataGrid(数据表格)组件 一. 加载方式//建立一个 JSON 文件[{"id" ...