c语言void delay什么意思_delay函数延时时间

c语言void delay什么意思_delay函数延时时间参考了51单片机KeilC延时程序的简单研究,自己也亲身测试和计算了一些已有的延时函数。这里假定单片机是时钟频率为12MHz,则一个机器周期为:1us.参考了51单片机KeilC延时程序的简单研究后,我们可知道,在KeilC中获得最为准确的延时函数将是voiddelay(unsignedchart){while(--t);}反汇编代码如下:执行DJNZ指令需要2个机器周期,RET指...

参考了51单片机 Keil C 延时程序的简单研究,自己也亲身测试和计算了一些已有的延时函数。

这里假定单片机是时钟频率为12MHz,则一个机器周期为:1us.

参考了51单片机 Keil C 延时程序的简单研究后,我们可知道, 在Keil C中获得最为准确的延时函数将是

f0cd6c7f9e7ae96feae062cb48f670f0.pngvoiddelay(unsignedchart)

34031c708bfe702fe82d01ff5c6593aa.png

0be121fa5b8988fbabbbc526af3b0fc0.gifb854634c0904529d4018c4c3336be836.png{

587e34b10dcf5efbc0859b53470a2db3.pngwhile(--t);

4fd96b3cf02f4c7b5c8964ac8167f7af.png}

反汇编代码如下:

b6cc3a1c3e94f7bc59fb2c0f1f051cec.png

执行DJNZ指令需要2个机器周期,RET指令同样需要2个机器周期,根据输入t,在不计算调用delay()所需时间的情况下,具体时间延时如下:tDelay Time (us)

12×1+2 =4

22×2+2=6

N2×N+2=2(N+1)

当在main函数中调用delay(1)时, 进行反汇编如下:

2a08c0858b3c375d89db54a24ec93553.png

调用delay()时,多执行了两条指令,其中MOV R, #data需要1个机器周期,LJMP需要2个机器周期,即调用delay()需要3us.

Keil C仿真截图与计算过程:

cdef4affd59c1771ae2941f703675399.png

a91a54461b971b1840c689ee847a4f4d.png

加上调用时间,准确的计算时间延时与Keil C仿真对比如下:(可见,仿真结果和计算结果是很接近的)

tDelay Time (us)仿真11.0592Mhz时钟(us)

13+2×1+2 =7 | 7.7(实际)7.60

23+2×2+2=9 | 9.99.76

N3+2×N+2=2N+5 | (2N+5)*1.1/

311 | 12.111.94

1535 | 38.537.98

100205 | 225.5222.44

255515 | 566.5558.81

也就是说,这个延时函数的精度为2us,最小的时间延时为7us,最大的时间延时为3+255×2+2=515us.

实际中使用11.0592MHz的时钟,这个延时函数的精度将为2.2us,最小时间延时为7.7us, 最大时间延时为566.5us.

这个时间延时函数,对于与DS18B20进行单总线通信,已经足够准确了。

现在,我们将时钟换成11.0592MHz这个实际用到的频率,每个机器周期约为1.1us.

现在让我们来分析一下这个之前用过的延时函数:

f0cd6c7f9e7ae96feae062cb48f670f0.png//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.f0cd6c7f9e7ae96feae062cb48f670f0.pngvoiddelayMs(unsignedinti)

34031c708bfe702fe82d01ff5c6593aa.png

0be121fa5b8988fbabbbc526af3b0fc0.gifb854634c0904529d4018c4c3336be836.png{

587e34b10dcf5efbc0859b53470a2db3.png    unsignedintj;

587e34b10dcf5efbc0859b53470a2db3.pngwhile(i--)

3112b7b6526db5bc83e275260ae60525.png

f2671b7f42ce505d9bf55a7a0ca257fb.gifb854634c0904529d4018c4c3336be836.png{

587e34b10dcf5efbc0859b53470a2db3.pngfor(j=0; j<125; j++);

eec4c0236afc26744c9c4e910bc34958.png    }4fd96b3cf02f4c7b5c8964ac8167f7af.png}

它的反汇编代码如下:

67842391524e94c60720c0a54073b0c3.png

分析: T表示一个机器周期(调用时间相对于这个ms级的延时来说,可忽略不计)

1 C:0000MOV   A,    R7       ;1T2 DEC   R7                ;1T   低8位字节减13 MOV   R2,   0x06   ;2T4 JNZ   C:0007;2T   若低8位字节不为0, 则跳到C:00075 DEC   R6                ;1T   低8位字节为0, 则高8位字节减16 C:0007ORL   A,   R2         ;1T7 JZ      C:001D         ;2T   若高8位也减为0, 则RET8 CLR   A                  ;1T   A清零9 MOV   R4,   A        ;1T   R4放高位10 MOV   R5,   A        ;1T   R5放低位11 C:000D      CLR   C                  ;1T   C清零12 MOV   A,   R5        ;1T13 SUBB   A, #0x7d    ;1T   A=A-12514 MOV   A,   R4        ;1T15 SUBB   A,  #0x00   ;1T   A16 JNC  C:0000;2T   A为零则跳到C:000017 INC   R5                 ;1T   R5增118 CJNE R5,#0x00, C:001B ;2T   R5>0, 跳转到C:000D19 INC   R4                 ;1T20 C:001B      SJMP      C:000D    ;2T21 C:001D      RET

对于delayMs(1), 执行到第7行就跳到21行, 共需时12T, 即13.2us

对于delayMs(2), 需时9T+13T+124×10T+7T+12T = 9T+13T+1240T+7T+12T =1281T =1409.1us.

对于delayMs(3), 需时9T×(3-1)+(13T+124×10T+7T)×(3-1)+12T

=1269T×(3-1)+12T=2550T=2805us.

对于delayMs(N),N>1, 需时1269T×(N-1)+12T = 1269NT-1257T=(1395.9N-1382.7)us.

利用Keil C仿真delayMs(1) = 0.00166558s = 1.67ms 截图如下:

91a9fdb4f504c68600f28b1f74c0f88e.png

a9e54e951cbfb7b6a4ac7fc0e309ee3c.png

ed011562e837ee9c965e1f5d738a98dc.png

由分析可知具体的计算延时时间与Keil C仿真延时对比如下:iTime Delay仿真延时

113.2us1.67ms

21409.1us3.31ms

32805us4.96ms

N(1395.9N-1382.7)us

1012.6ms16.50ms

2026.5ms32.98ms

3040.5ms49.46ms

5068.4ms82.43ms

100138.2ms164.84ms

200277.8ms329.56ms

500696.6ms824.13ms

10001394.5ms1648.54ms

15002092.5ms2472.34ms

20002790.4ms3296.47ms

55.6ms8.26ms

73100.5ms120.34ms

7201003.7ms = 1s1186.74ms

计算delayMs(10)得到延时时间为:12576.3us约等于12.6ms,接近我们认为的10ms。

计算结果和仿真结果只要delayMs(1)有很大出入, 其它都接近, 在接受范围内.

经过以上分析,可见用C语言来做延时并不是不太准确,只是不容易做到非常准确而已,若有一句语句变了,延时时间很可能会不同,因为编译程序生成的汇编指令很可能不同。

架构君码字不易,如需转载,请注明出处:https://javajgs.com/archives/222529
0
 

发表评论