对于51,多数人觉得很简单,但是大家却极容易犯的错误就是忽略了编译器。Keil是无疑对于51系列最好的编译器了,但是它不是智能的(编译原理)。
在我再次拾起51时(此时是为了学习ucos在51上的移植,很有意思),我试着深入去了解一些C程序在进行编译后KEIL为我们做的工作到底是怎样的,当然这部分是很难了解的很清楚的,要相当多的经验与教训.
今天在试着写一个程序的时候,发现了如下的问题:
今天写的对键盘的扫描的小程序中,刚开始我是这样写的:
INT8U Keycheck(){
INT8U Keytmp;
P2 = 0xFF;
Keytmp = P2;
//Keytmp = P2&0x0f;
if(P2!=Keytmp){
switch(Keytmp){
case 0xFE : returnkey = 0x01;break;
case 0xFD : returnkey = 0x02;break;
case 0xFB : returnkey = 0x03;break;
case 0xF7 : returnkey = 0x04;break;
}
}
return returnkey;
}
但是仿真的时候却不对(没有加去抖动部分),查看汇编代码后发现如下的结果
C:0x008F 75A0FF MOV P2(0xA0),#0xFF
21: Keytmp = P2;
22: //Keytmp = P2&0x0f;
C:0x0092 AFA0 MOV R7,P2(0xA0)
23: if(P2!=Keytmp){
C:0x0094 E5A0 MOV A,P2(0xA0)
C:0x0096 6F XRL A,R7
C:0x0097 6022 JZ C:00BB
24: switch(Keytmp){ 省略
由生成的汇编代码中可以看出:XRL A,R7 就是对if(P2!=Keytmp)KEIL的翻译,但是此时的A和R7其实是相等的,也就是无法判断出按键的按下,实际仿真时可以发现极少的情况下能判断出按键的按下(偶尔有出现过)。
由上我将程序改成了如下(即将if里面的语句进行了调转)
此时的汇编程序为:
C:0x008F 75A0FF MOV P2(0xA0),#0xFF
21: Keytmp = P2;
22: //Keytmp = P2&0x0f;
C:0x0092 AFA0 MOV R7,P2(0xA0)
23: if(Keytmp!=P2){
C:0x0094 EF MOV A,R7
C:0x0095 65A0 XRL A,P2(0xA0)
C:0x0097 6022 JZ C:00BB
24: switch(Keytmp){
但是此时的汇编代码KEIL并没有做太大的改变,显然仿真的效果仍然不是很好,不能很好的检测到按键
此时再将程序改为如下形式:
INT8U Keycheck(){
INT8U Keytmp;
P2 = 0xFF;
//Keytmp = P2;
Keytmp = P2&0x0f;
if(Keytmp!=0x0f){
switch(Keytmp){
case 0x0E : returnkey = 0x01;break;
case 0x0D : returnkey = 0x02;break;
case 0x0B : returnkey = 0x03;break;
case 0x07 : returnkey = 0x04;break;
}
}
return returnkey;
}
此时在看汇编代码的时候发现KEIL给了较大的改变:
C:0x008F 75A0FF MOV P2(0xA0),#0xFF
22: Keytmp = P2&0x0f;
C:0x0092 E5A0 MOV A,P2(0xA0)
C:0x0094 540F ANL A,#0x0F
C:0x0096 FF MOV R7,A
23: if(Keytmp!=0x0f){
C:0x0097 640F XRL A,#0x0F
C:0x0099 6022 JZ C:00BD
此时对简单的汇编语句进行分析可以看到就不会出现上面的情况,此时通过仿真就能很好的进行按键的检测,不会出现错误(没加上去抖动部分程序)