51单片机KeilC延时程序的研究doc 13页.docx

上传人:b****5 文档编号:7881658 上传时间:2023-01-26 格式:DOCX 页数:7 大小:48.10KB
下载 相关 举报
51单片机KeilC延时程序的研究doc 13页.docx_第1页
第1页 / 共7页
51单片机KeilC延时程序的研究doc 13页.docx_第2页
第2页 / 共7页
51单片机KeilC延时程序的研究doc 13页.docx_第3页
第3页 / 共7页
51单片机KeilC延时程序的研究doc 13页.docx_第4页
第4页 / 共7页
51单片机KeilC延时程序的研究doc 13页.docx_第5页
第5页 / 共7页
点击查看更多>>
下载资源
资源描述

51单片机KeilC延时程序的研究doc 13页.docx

《51单片机KeilC延时程序的研究doc 13页.docx》由会员分享,可在线阅读,更多相关《51单片机KeilC延时程序的研究doc 13页.docx(7页珍藏版)》请在冰豆网上搜索。

51单片机KeilC延时程序的研究doc 13页.docx

51单片机KeilC延时程序的研究doc13页

51单片机KeilC延时程序的研究(doc13页)

51单片机KeilC延时程序的简单研究

by:

InfiniteSpaceStudio/isjfk,1.21.2004

应用单片机的时候,经常会遇到需要短时间延时的情况。

需要的延时时间很短,一般都是几十到几百微妙(us)。

有时候还需要很高的精度,比如用单片机驱动DS18B20的时候,误差容许的范围在十几us以内,不然很容易出错。

这种情况下,用计时器往往有点小题大做。

而在极端的情况下,计时器甚至已经全部派上了别的用途。

这时就需要我们另想别的办法了。

以前用汇编语言写单片机程序的时候,这个问题还是相对容易解决的。

比如用的是12MHz晶振的51,打算延时20us,只要用下面的代码,就可以满足一般的需要:

movr0,#09h

loop:

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'----

;SOURCELINE#19

;SOURCELINE#21

;----Variable'a'assignedtoRegister'R7'----

0000?

C0007:

0000EFMOVA,R7

00016003JZ?

C0010

00031FDECR7

000480FASJMP?

C0007

;SOURCELINE#22

0006?

C0010:

000622RET

;FUNCTION_delay2(END)

其生成的代码是一样的。

不过这的确不是什么好的习惯。

因为这里实在没有必要再引入多余的变量。

我们继续讨论正题。

有的朋友为了得当更长的延时,甚至用了这样的代码:

voiddelay2(unsignedlongi)

{

for(;i!

=0;i--);

}

这段代码产生的汇编代码是什么样子的?

其实不用想也知道它是如何恐怖的$#^%&%$......让我们看一看:

;FUNCTION_delay2(BEGIN)

;SOURCELINE#18

00008F00RMOVi+03H,R7

00028E00RMOVi+02H,R6

00048D00RMOVi+01H,R5

00068C00RMOVi,R4

;SOURCELINE#19

;SOURCELINE#20

0008?

C0007:

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?

C0010

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?

C0007

;SOURCELINE#21

0035?

C0010:

003522RET

;FUNCTION_delay2(END)

呵呵,这倒是的确可以延迟很长时间~~~但是毫无精度可言了。

那么,用C到底能不能实现精确的延时呢?

我把代码稍微改了一下:

voiddelay1(unsignedchari)

{

while(i--);

}

因为根据经验,越简洁的C代码往往也能得出越简洁的机器代码。

那这样结果如何呢?

把它生成的汇编代码拿出来看一看就知道了。

满怀希望的我按下了“Buildtarget”键,结果打击是巨大的:

;FUNCTION_delay1(BEGIN)

;SOURCELINE#13

;----Variable'i'assignedtoRegister'R7'----

;SOURCELINE#14

0000?

C0004:

;SOURCELINE#15

0000AE07MOVR6,AR7

00021FDECR7

0003EEMOVA,R6

000470FAJNZ?

C0004

;SOURCELINE#16

0006?

C0006:

000622RET

;FUNCTION_delay1(END)

虽说生成的代码跟用for语句是不大一样,不过我可以毫无疑问的说,这两种方法的效率是一样的。

似乎到此为止了,因为我实在想不出来源程序还有什么简化的余地。

看来我就要得出来这个结论了:

“如果需要us级的延时精度,需要时用汇编语言。

”但是真的是这样吗?

我还是不甘心。

因为我不相信大名鼎鼎的KeilC编译器居然连djnz都不会用?

因为实际上程序体里只需要一句loop:

djnzr7,loop。

近乎绝望之际(往往人在这种情况下确可以爆发出来,哦呵呵呵~~~),我随手改了一下:

voiddelay1(unsignedchari)

{

while(--i);

}

心不在焉的编译,看源码:

;FUNCTION_delay1(BEGIN)

;SOURCELINE#13

;----Variable'i'assignedtoRegister'R7'----

;SOURCELINE#14

0000?

C0004:

;SOURCELINE#15

0000DFFEDJNZR7,?

C0004

;SOURCELINE#16

0002?

C0006:

000222RET

;FUNCTION_delay1(END)

天~~~奇迹出现了......我想这个程序应该已经可以满足一般情况下的需要了。

如果列个表格的话:

idelaytime/us

15

27

39

...

计算延时时间时,已经算上了调用函数的lcall语句所花的2个时钟周期的时间。

终于,结果已经明了了。

只要合理的运用,C还是可以达到意想不到的效果。

很多朋友抱怨C效率比汇编差了很多,其实如果对KeilC的编译原理有一个较深入的理解,是可以通过恰当的语法运用,让生成的C代码达到最优化。

即使这看起来不大可能,但还是有一些简单的原则可循的:

1.尽量使用unsigned型的数据结构。

2.尽量使用char型,实在不够用再用int,然后才是long。

3.如果有可能,不要用浮点型。

4.使用简洁的代码,因为按照经验,简洁的C代码往往可以生成简洁的目标代码(虽说不是在所有的情况下都成立)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1