阅读了《单片机与嵌入式系统应用》2005年第10期杂志《经验交流》栏目的一篇文章《Keil C51对同一端口的连续读取方法》(原文)后,笔者认为该文并未就此问题进行深刻准确的分析 文章中提到的两种解决方法并不直接和简单。笔者认为这并不是是Keil C51中不能处理对一个端口进行连续读写的问题,而是对Kei1 C51的使用不够熟悉和设计不够细致的问题,所以特撰写本文。程序员
本文中对原文提到的问题,提出了三种不一样于原文的解决方法。每种方法都比原文中提到的方法更直接和简单,设计也更规范。(无心批评,请原文做者见谅)express
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的设置仍然能够保留高级优化,且编译结果中,一样两次读取并不会被优化跳过。oop
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中的优化级别及优化做用spa |
|
级别设计 |
说明 |
0 |
常数合并:编译器预先计算结果,尽量用常数代替表达式。包括运行地址计算。 |
1 |
死代码删除:没用的代码段被删除。 |
2 |
数据覆盖:适合静态覆盖的数据和位段被肯定,并内部标识。BL51链接/定位器能够经过全局数据流分析,选择可被覆盖的段。 |
3 |
窥孔优化:清除多余的MOV指令。这包括没必要要的从存储区加载和常数加载操做。当存储空间或执行时间可节省时,用简单操做代替复杂操做。 |
4 |
寄存器变量:若有可能,自动变量和函数参数分配到寄存器上。为这些变量保留的存储区就省略了。 |
5 |
全局公共子表达式删除:一个函数内相同的子表达式有可能就只计算一次。中间结果保存在寄存器中,在一个新的计算中使用。 |
6 |
循环优化:若是结果程序代码更快和有效则程序对循环进行优化。 |
7 |
扩展索引访问优化:适当时对寄存器变量用DPTR。对指针和数组访问进行执行速度和代码大小优化。 |
8 |
公共尾部合并:当一个函数有多个调用,一些设置代码能够复用,所以减小程序大小。 |
9 |
公共块子程序:检测循环指令序列,并转换成子程序。Cx51甚至重排代码以获得更大的循环序列。 |