51单片机KeilC延时程序的研究doc 13页Word文档格式.docx
《51单片机KeilC延时程序的研究doc 13页Word文档格式.docx》由会员分享,可在线阅读,更多相关《51单片机KeilC延时程序的研究doc 13页Word文档格式.docx(7页珍藏版)》请在冰豆网上搜索。
djnzr0,loop
51单片机的指令周期是晶振频率的1/12,也就是1us一个周期。
movr0,#09h需要2个极其周期,djnz也需要2个极其周期。
那么存在r0里的数就是(20-2)/2。
用这种方法,可以非常方便的实现256us以下时间的延时。
如果需要更长时间,可以使用两层嵌套。
而且精度可以达到2us,一般来说,这已经足够了。
;
SOURCELINE#19
SOURCELINE#20
0000?
C0007:
0000EFMOVA,R7
00016003JZ?
C0010
00031FDECR7
000480FASJMP?
C0007
SOURCELINE#21
0006?
C0010:
000622RET
FUNCTION_delay2(END)
真是不看不知道~~~一看才知道这个延时程序是多么的不准点~~~光看主要的那四条语句,就需要6个机器周期。
也就是说,它的精度顶多也就是6us而已,这还没算上一条lcall和一条ret。
如果我们把调用函数时赋的i值根延时长度列一个表的话,就是:
idelaytime/us
06
112
218
...
因为函数的调用需要2个时钟周期的lcall,所以delaytime比从函数代码的执行时间多2。
顺便提一下,有的朋友写的是这样的代码:
voiddelay2(unsignedchari)
{
unsignedchara;
for(a=i;
a!
=0;
a--);
}
可能有人认为这会生成更长的汇编代码来,但是事实证明:
FUNCTION_delay2(BEGIN)
SOURCELINE#18
----Variable'
i'
assignedtoRegister'
R7'
----
a'
SOURCELINE#22
其生成的代码是一样的。
不过这的确不是什么好的习惯。
因为这里实在没有必要再引入多余的变量。
我们继续讨论正题。
有的朋友为了得当更长的延时,甚至用了这样的代码:
voiddelay2(unsignedlongi)
for(;
i!
i--);
这段代码产生的汇编代码是什么样子的?
其实不用想也知道它是如何恐怖的$#^%&
%$......让我们看一看:
00008F00RMOVi+03H,R7
00028E00RMOVi+02H,R6
00048D00RMOVi+01H,R5
00068C00RMOVi,R4
0008?
0008E4CLRA
0009FFMOVR7,A
000AFEMOVR6,A
000BFDMOVR5,A
000CFCMOVR4,A
000DAB00RMOVR3,i+03H
000FAA00RMOVR2,i+02H
0011A900RMOVR1,i+01H
0013A800RMOVR0,i
0015C3CLRC
0016120000ELCALL?
C?
ULCMP
0019601AJZ?
001BE500RMOVA,i+03H
001D24FFADDA,#0FFH
001FF500RMOVi+03H,A
0021E500RMOVA,i+02H
002334FFADDCA,#0FFH
0025F500RMOVi+02H,A
0027E500RMOVA,i+01H
002934FFADDCA,#0FFH
002BF500RMOVi+01H,A
002DE500RMOVA,i
002F34FFADDCA,#0FFH
0031F500RMOVi,A
003380D3SJMP?
0035?
003522RET
呵呵,这倒是的确可以延迟很长时间~~~但是毫无精度可言了。
那么,用C到底能不能实现精确的延时呢?
我把代码稍微改了一下:
voiddelay1(unsignedchari)
while(i--);
因为根据经验,越简洁的C代码往往也能得出越简洁的机器代码。
那这样结果如何呢?
把它生成的汇编代码拿出来看一看就知道了。
满怀希望的我按下了“Buildtarget”键,结果打击是巨大的:
FUNCTION_delay1(BEGIN)
SOURCELINE#13
SOURCELINE#14
C0004:
SOURCELINE#15
0000AE07MOVR6,AR7
00021FDECR7
0003EEMOVA,R6
000470FAJNZ?
C0004
SOURCELINE#16
C0006:
FUNCTION_delay1(END)
虽说生成的代码跟用for语句是不大一样,不过我可以毫无疑问的说,这两种方法的效率是一样的。
似乎到此为止了,因为我实在想不出来源程序还有什么简化的余地。
看来我就要得出来这个结论了:
“如果需要us级的延时精度,需要时用汇编语言。
”但是真的是这样吗?
我还是不甘心。
因为我不相信大名鼎鼎的KeilC编译器居然连djnz都不会用?
?
因为实际上程序体里只需要一句loop:
djnzr7,loop。
近乎绝望之际(往往人在这种情况下确可以爆发出来,哦呵呵呵~~~),我随手改了一下:
while(--i);
心不在焉的编译,看源码:
0000DFFEDJNZR7,?
0002?
000222RET
天~~~奇迹出现了......我想这个程序应该已经可以满足一般情况下的需要了。
如果列个表格的话:
15
27
39
计算延时时间时,已经算上了调用函数的lcall语句所花的2个时钟周期的时间。
终于,结果已经明了了。
只要合理的运用,C还是可以达到意想不到的效果。
很多朋友抱怨C效率比汇编差了很多,其实如果对KeilC的编译原理有一个较深入的理解,是可以通过恰当的语法运用,让生成的C代码达到最优化。
即使这看起来不大可能,但还是有一些简单的原则可循的:
1.尽量使用unsigned型的数据结构。
2.尽量使用char型,实在不够用再用int,然后才是long。
3.如果有可能,不要用浮点型。
4.使用简洁的代码,因为按照经验,简洁的C代码往往可以生成简洁的目标代码(虽说不是在所有的情况下都成立)