KEIL C51代码优化详细分析
阅读了《单片机与嵌入式系统应用》2005年第10期杂志《经验交流》栏目的一篇文章《Keil C51对同一端口的连续读取方法》(原文)后,笔者认为该文并未就此问题进行深入准确的分析 文章中提到的两种解决方法并不直接和简单。笔者认为这并非是Keil C51中不能处理对一个端口进行连续读写的问题,而是对Kei1 C51的使用不够熟悉和设计不够细致的问题,因此特撰写本文。
本文中对原文提到的问题,提出了三种不同于原文的解决方法。每种方法都比原文中提到的方法更直接和简单,设计也更规范。(无意批评,请原文作者见谅)
1 问题回顾和分析
原文中提到:在实际工作中遇到对同一端口反复连续读取,Keil C51编译并未达到预期的结果。原文作者对C编译出来的汇编程序进行分析发现,对同一端口的第二次读取语句并未被编译。但可惜原文作者并未分析没有被编译的原因,而是匆忙地采用一些不太规范的方法试验出了两种解决办法。
对此问题,翻阅Keil C51的手册很容易发现:KeilC51的编译器有一个优化设置,不同的优化设置,会产生不同的编译结果。一般情况缺省编译优化设置被设定为8级优化,实际最高可设定为9级优化:
1. Dead code elimination。
2.Data overlaying。
3.Peephole optimization。
4.Register variables。
5.Common subexpression elimination。
6.Loop rotation。
7.Extended Index Access Optimizing。
8.Reuse Common Entry Code。
9.Common Block Subroutines。
而以上的问题,正是由于Keil C51编译优化产生的。因为在原文程序中将外设地址直接按如下定义:
unsigned char xdata MAX197 _at_ 0x8000
采用_at_将变量MAX197定义到外部扩展RAM 指定地址0x8000。因此,Keil C51优化编译理所当然认为重复读第二次是没有用的,直接用第一次读取的结果就可以了,因此编译器跳过了第二条读取语句。至此,问题就一目了然了。
2 解决方法
由以上分析很容易就能提出很好的解决办法。
2.1 最简单最直接的办法
程序一点都不用修改,将Keil C51的编译优化选择设置为0(不优化)就可以了。选择project窗口的Target,然后打开“Options for Target”设置对话框,选择“C51”选项卡,将“Code Optimiztaion”中的“Level”选择为“0:Costant folding”。再次编译后,大家会发现编译结果为:
CLR MAXHBEN
MOV DPTR,#MAX197
MOVX A,@DPTR
MOV R7,A
MOV down8,R7
SETB MAXHBEN
MOV DPTR,#MAX197
MOVX A,@DPTR
MOV R7,A
MOV up4,R7
两次读取操作都被编译出来了。
2.2 最好的方法
告诉Keil C51,这个地址不是一般的扩展RAM,而是连接的设备,具有“挥发”特性,每次读取都是有意义的。可以修改变量定义,增加“volatile”关键字说明其特征:
unsigned char volatile xdata MAX197 _at_ 0x8000;
也可以在程序中包含系统头文件;“#include”,然后在程序中修改变量,定义为直接地址:
#define MAX197 XBYTE[0x8000]
这样,Keil C51的设置仍然可以保留高级优化,且编译结果中,同样两次读取并不会被优化跳过。
2 3 硬件解决方法
原文中将MAX197的数据直接连接到数据总线,而对地址总线并未使用,采用一根端口线选择操作高低字节。很简单的修改方法就是使用一根地址线选择操作高低字节即可。比如:将P2.0(A8)连接到原来P1.0连接的HBEN脚(MAX197的5脚).在程序中分别定义高低字节的操作地址:
unsigned char volatile xdata MAX197_L _at_ 0x8000;
unsigned char volatile xdata MAX197_H _at_ 0x8100;
将原来的程序:
MAXHBEN =0;
down8=MAX197;//读取低8位
MAXHBEN =1;
up4=MAX197;//读取高4位
改为以下两句即可
down8= MAX197_L;//读取低8位
up4=MAX197_H;//读取高4位
3 小结
Keil C51经过长期考验和改进以及大量开发人员的实际使用,已经克服了绝大多数的问题,并且其编译效率也非常高。对于一般的使用.很难再发现什么问题。笔者曾经粗略研究过一下Keil C51优化编洋的结果.非常佩服Keil C51设计者的智慧,一些C程序编译产生的汇编代码.甚至比一般程序员直接用汇编编写的代码还要优秀和简练 通过研读Kell C51编译产生的汇编代码.对提高汇编语言编写程序的水平都是很有帮助的。
由本文中的问题可以看出:在设计中遇到问题时.一定不要被表面现象蒙蔽,不要急于解决,应该认真分析,找出问题的原因.这样才能从根本上彻底解决问题。
|
附表:Keil C51中的优化级别及优化作用 |
|
|
级别 |
说明 |
|
0 |
常数合并:编译器预先计算结果,尽可能用常数代替表达式。包括运行地址计算。 |
|
1 |
死代码删除:没用的代码段被删除。 |
|
2 |
数据覆盖:适合静态覆盖的数据和位段被确定,并内部标识。BL51连接/定位器可以通过全局数据流分析,选择可被覆盖的段。 |
|
3 |
窥孔优化:清除多余的MOV指令。这包括不必要的从存储区加载和常数加载操作。当存储空间或执行时间可节省时,用简单操作代替复杂操作。 |
|
4 |
寄存器变量:如有可能,自动变量和函数参数分配到寄存器上。为这些变量保留的存储区就省略了。 |
|
5 |
全局公共子表达式删除:一个函数内相同的子表达式有可能就只计算一次。中间结果保存在寄存器中,在一个新的计算中使用。 |
|
6 |
循环优化:如果结果程序代码更快和有效则程序对循环进行优化。 |
|
7 |
扩展索引访问优化:适当时对寄存器变量用DPTR。对指针和数组访问进行执行速度和代码大小优化。 |
|
8 |
公共尾部合并:当一个函数有多个调用,一些设置代码可以复用,因此减少程序大小。 |
|
9 |
公共块子程序:检测循环指令序列,并转换成子程序。Cx51甚至重排代码以得到更大的循环序列。 |
KEIL C51代码优化详细分析的更多相关文章
- Keil C51 详细设置
一.target名更改 打开Keil后,左侧Project Workspace中的target可改,方法:右击Target——Manage Compnents——双击待修改项即可,若要添加,使用对话框 ...
- keil c51笔记
第一章 Keil C51开发系统基本知识 第一节 系统概述 Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上.结构性.可读性. ...
- KEIL、uVision、RealView、MDK、KEIL C51区别比较
KEIL uVision,KEIL MDK,KEIL For ARM,RealView MDK,KEIL C51,KEIL C166,KEIL C251 从接触MCS-51单片机开始,我们就知道有一个 ...
- KEIL C51高级编程
第一节 绝对地址访问C51提供了三种访问绝对地址的方法: 1. 绝对宏:在程序中,用“#include”即可使用其中定义的宏来访问绝对地址,包括:CBYTE.XBYTE.PWORD.DBYTE.CWO ...
- 转:Keil MDK从未有过的详细使用讲解
来自:http://blog.csdn.net/zhzht19861011/article/details/5846510 熟悉Keil C 51的朋友对于Keil MDK上手应该比较容易,毕竟界面是 ...
- Keil C51 知识点
第一节 Keil C51扩展关键字 深入理解并应用C51对标准ANSIC的扩展是学习C51的关键之一.因为大多数扩展功能都是直接针对8051系列CPU硬件的.大致有以下8类: 8051存储类型 ...
- Keil C51里关于堆栈指针的处理
Keil C是非常优秀的C51编译器,可能是最好的C51编译器,提供各种优化模式,对变量的优化和地址安排做得非常好.这是用C语言写代码的好处之一,如果用汇编写,得费一大番功夫给各个变量安排内存物理地址 ...
- Keil C51编译及连接技术
主要介绍Keil C51的预处理方法如宏定义.常用的预处理指令及文件包含指令,C51编译库的选择及代码优化原理,C51与汇编混合编程的方法与实现以及超过64KB空间的地址分页方法的C51实现. 教学目 ...
- 关于Keil C51中using关键字的使用心得
刚才看到一位很牛的师兄写的一篇日志中提到了Keil C51中using这个关键字的用法,粗心的我本来一直都没有留意它是用来干嘛的(因为我一般看见它都是在中断服务函数的定义开头处,好像没有了它也可以中断 ...
随机推荐
- 用NI的数据采集卡实现简单电子测试之5——压控振荡器的测试
本文从本人的163博客搬迁至此. 为了展示连续信号采集的方法,以其外部触发采集功能.我用运算放大器实现了一个最简单的低频压控振荡器(VCO),作为USB-6009采集的信号源.在LabVIEW下编写的 ...
- 2017-2018-1 20155226 《信息安全系统设计基础》课下实践——实现mypwd
2017-2018-1 20155226 <信息安全系统设计基础>课下实践--实现mypwd 1 学习pwd命令 输入pwd命令 发现他是给出当前文件夹的绝对路径. 于是 man 1 pw ...
- 20155237 2016-2017-2 《Java程序设计》第4周学习总结
20155237 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 第六章 继承与多态 继承符合DRY原则. extends UML 多态: 继承可以复用代码, ...
- 【转载】ATL问题集
原文:http://blog.csdn.net/fengrx/article/details/4171629 这些问题是以前在csdn当版主是一些朋友整理的,今天找到了,贴到这里来! #1 如何使用控 ...
- CF GYM 101196 G That’s One Hanoi-ed Teacher
That’s One Hanoi-ed Teacher 链接 题意: 询问一个汉诺塔的状态是否是最优的状态,如果是,询问还有多少步到最终状态. 分析: 考虑汉诺塔是怎么操作的,首先是考虑F(i)是有i ...
- 5285: [Hnoi2018]寻宝游戏
5285: [Hnoi2018]寻宝游戏 链接 分析: 从下面依次确定运算符号,然后在确定的过程中,需要确定的位数会逐渐减少.比如最后有一个1,如果在从下往上确定了一个or 1,那么再往前可以随便选了 ...
- 2_C语言中的数据类型 (二)进制
1.1 二进制数.位.字节与字 我们习惯于十进制的数:10,12等 一个位只能表示0,或者1两种状态,简称bit,一个位是一个bit 一个字节为8个二进制,称为8位,简称BYTE,8个比特 ...
- P4360 [CEOI2004]锯木厂选址
P4360 [CEOI2004]锯木厂选址 这™连dp都不是 \(f_i\)表示第二个锯木厂设在\(i\)的最小代价 枚举1号锯木厂 \(f_i=min_{0<=j<i}(\sum_{i= ...
- 浅谈MVC Razor基本语法
首先说下MVC,mvc已经不用ViewState来保留网页的状态,所以大部分依赖ViewState的功能都将无法使用, 比如gridview的分页与排序,page trace等利用viewstate记 ...
- 六度空间(MOOC)
六度空间: “六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论.这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五 ...