没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
51 单片机KeilC延时程序的简单研究
作者:InniteSpaceStudio/isjfk
51 单片机KeilC延时程序的简单研究
by:InniteSpaceStudio/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,一般来说,这已经足够了。
现在,应用更广泛的毫无疑问是 Keil 的 C 编译器。相对汇编来说,C 固然有很多优点,
比如程序易维护,便于理解,适合大的项目。但缺点(我觉得这是 C 的唯一一个缺点了)
就是实时性没有保证,无法预测代码执行的指令周期。因而在实时性要求高的场合,还需
要汇编和 C 的联合应用。但是是不是这样一个延时程序,也需要用汇编来实现呢?为了找
到这个答案,我做了一个实验。
用 C 语言实现延时程序,首先想到的就是 C 常用的循环语句。下面这段代码是我经常在
网上看到的:
voiddelay2(unsignedchari)
{
for(;i!=0;i--);
}
到底这段代码能达到多高的精度呢?为了直接衡量这段代码的效果,我把KeilC根据这段
代码产生的汇编代码找了出来:
;FUNCTION_delay2(BEGIN)
;SOURCELINE#18
;----Variable'i'assignedtoRegister'R7'----
;SOURCELINE#19
;SOURCELINE#20
0000?C0007:
0000EFMOVA,R7
00016003JZ?C0010
00031FDECR7
000480FASJMP?C0007
;SOURCELINE#21
0006?C0010:
000622RET
;FUNCTION_delay2(END)
真是不看不知道~~~一看才知道这个延时程序是多么的不准点~~~光看主要的那四条语
句,就需要 6 个机器周期。也就是说,它的精度顶多也就是 6us 而已,这还没算上一条lc
all和一条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)
{
剩余11页未读,继续阅读
资源评论
- pinsy2013-05-01比较简单,不过什么都有一个过程,赞!
非知名码农
- 粉丝: 71
- 资源: 50
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功