1. 用C直接操作DPTR方式
我们平常用Keil C访问总线一般是定义unsigned char xdata *fardptr; fardptr=0xbf00; *fardptr=0; 来访问,这就涉及到一个问题:首先增加一个占两个字节的变量,其次是每次系统多了一个赋值给这个变量,不论你是否要用这个用量。用汇编操作总线 MOVX A,@DPTR 和MOVX @DPTR,A,我们可以用混汇编方法是可以插入,但象这种类似操作多了,代码看起来不清晰,还有一种办法:
我们先定义一个宏:#define dptr(n) (*((unsigned char xdata *)n)) 然后我们就可以象写函数一样
dptr(0xbf04)=0;
dptr(0xbf05)=0xff;
dptr(0xbf06)=0x18;
这种方式用Keil C 编译成的实际形式就是:
MOV DPTR,#0BF04H
CLR A
MOVX @DPTR,A
INC DPTR;这里Keil c自动优化为INC ,而不是 MOV DPTR,#0BF05H,使执行速度更快
MOV A,#0FFH
MOVX @DPTR,A
INC DPTR
MOV A,#018H
MOVX @DPTR,A
这种写法是和直接汇编的效率是一样高的!但反过来行不行呢?
unsigned char m;
dptr(0xbf04)=0; m=dptr(0xbf05); 编译后得到:MOV DPTR,#0BF04H
CLR A
MOVX @DPTR,A
INC DPTR
MOVX A,@DPTR
MOV m,A
效率看起来好象真不错呢!但这里有一种潜在的BUG,如我们要实现对写出去的总线再验证读的时候就出问题了,如:
do { dptr(0xbf00)=0; ACC=dptr(0xbf00); }while(!ACC0);
这段代码实际是送出总线值后再读回来,保证设置正确,但实际Keil C 编译后成了
?C0018:
MOV DPTR,#0BF00H
CLR A
MOVX @DPTR,A
MOV R7,A 这里不是 MOVX A,@DPTR
JNB ACC0,?C0018
如果真需要验证的情况下,显然没有达到我们的目的! 这种情况我一般是头文件里加 #define checkDPTR _asm MOVX A,@DPTR,在需要的时候(前后DPTR值不更改,ACC也没有再附值的时候)用于取出总线。大部分的时候,是可以这么取出来的。或者在程序过程如有加减运算(非加减1)或位运算后,累加器必参位运算,这时就可以用这种方法。程序的可读性就可大大提高的同时,保证效率。
2 循环的使用
看下面一段代码:
void SendSIOData2(const unsigned char value)
{
unsigned char i;
for(i=0,ACC=value;i<8;i++)
{
MCP2510_SCK2=0;
__asm RLC A
MCP2510_SI2=CY;
MCP2510_SCK2=1;
}
MCP2510_SCK2=0;
} 我相信至少一半的人会如此写这个循环,这种类似的代码在串行总线里是用得最多,也最可能占我们时间的,需要我们写出最经典的代码。但这种循环汇编后的代码是
CLR A
MOV R6,A
MOV A,R7
CLR MCP2510_SCK2 ......循环体省了
INC R6
CJNE R6,#08H,?C0005
如果我们把 for(i=0,ACC=value;i<8;i++) 改成 for(i=8,ACC=value;i!=0;i--) 呢?判断循环体就成了: MOV R6,08H 。。。DJNZ R6 ,?C0005
一个小小的编程习惯让我们在这里至少提高了10%-20%的效率。