拜讀了網(wǎng)上《51單片機 Keil C 延時程序的簡單研究 》(by: InfiniteSpace Studio/isjfk, 1.21.2004 )一文,借鑒了文中的方法,測試發(fā)現(xiàn)有一點點出入,原文作者在計算延時時間的時候是否忘了加上RET指令……下面介紹我的測試結(jié)果,歡迎交流探討——
一、單獨定義變量,for語句
28: delay1(1);
C:0x0005 7F01 MOV R7,#0x01
C:0x0007 1121 ACALL delay1(C:0021)
12: void delay1(unsigned char k)
13: {
17: unsigned char i=0;
C:0x0021 E4 CLR A
C:0x0022 FE MOV R6,A
18: for(i=0;i0;i--);相同
C:0x0023 EE MOV A,R6
C:0x0024 C3 CLR C
C:0x0025 9F SUBB A,R7
C:0x0026 5003 JNC C:002B
C:0x0028 0E INC R6
C:0x0029 80F8 SJMP C:0023
19: }
C:0x002B 22 RET
分析:
delay1(1); 410-390=20
delay1(2); 439-411=28
delay1(3); 476-440=36
即:指令周期(即實際延時)= 12 + 延時參數(shù) * 8
二、不再重新定義變量,for語句
28: delay1(1);
C:0x0005 7F01 MOV R7,#0x01
C:0x0007 1123 ACALL delay1(C:0023)
12: void delay1(unsigned char k)
13: {
18: for(;k>0;k--);
C:0x0023 EF MOV A,R7
C:0x0024 D3 SETB C
C:0x0025 9400 SUBB A,#0x00
C:0x0027 4003 JC C:002C
C:0x0029 1F DEC R7
C:0x002A 80F7 SJMP delay1(C:0023)
19: }
C:0x002C 22 RET
分析:
delay1(1); 491-473=18
delay1(2); 518-492=26
指令周期(即實際延時)= 10 + 延時參數(shù) * 8
對比一和二可知,延時函數(shù)中有重新定義循環(huán)變量i時,理所當(dāng)然地多了2行代碼
不知原文中 “其生成的代碼是一樣的。”的結(jié)論是如何得來的?
三、for語句,改變循環(huán)結(jié)束條件
23: delay1(1);
C:0x0005 7F01 MOV R7,#0x01
C:0x0007 1123 ACALL delay1(C:0023)
11: void delay1(unsigned char i)
12: {
13: // while(--i);
14: // while(i--);
15: for(; i != 0; i--);
C:0x0023 EF MOV A,R7
C:0x0024 6003 JZ C:0029
C:0x0026 1F DEC R7
C:0x0027 80FA SJMP delay1(C:0023)
16: }
C:0x0029 22 RET
分析:
delay1(1); 404-390=14
delay1(2); 425-405=20
delay1(3); 452-426=26
指令周期(即實際延時)= 8 + 延時參數(shù) * 6
對比二和三可知循環(huán)結(jié)束條件不同,編譯結(jié)果理當(dāng)不同,用i != 0快2個周期。
四、while語句1
21: delay1(1);
C:0x0005 7F01 MOV R7,#0x01
C:0x0007 1123 ACALL delay1(C:0023)
11: void delay1(unsigned char i)
12: {
13: while(i--);
C:0x0023 AE07 MOV R6,0x07
C:0x0025 1F DEC R7
C:0x0026 EE MOV A,R6
C:0x0027 70FA JNZ delay1(C:0023)
14: }
C:0x0029 22 RET
407-390=17,有點夸張
當(dāng)delay1(2)時,為431-408=23
delay1(3)時,為461-432=29
指令周期(即實際延時)= 11 + 延時參數(shù) * 6
五、while語句2
21: delay1(1);
444 C:0x0005 7F01 MOV R7,#0x01
445 C:0x0007 111D ACALL delay1(C:001D)
11: void delay1(unsigned char i)
12: {
13: while(--i);
447 C:0x001D DFFE DJNZ R7,delay1(C:001D)
14: }
449 C:0x001F 22 RET
451
從上看出451-444=7個周期,指令周期為1us的話,就是7us
指令周期(即實際延時)= 5 + 延時參數(shù) * 2
綜上可知:
共性:裝載函數(shù)參數(shù)用時1,調(diào)用用2,返回用2,1+2+2=5為固定開銷。
從以上各個結(jié)果的指令周期和延時參數(shù)的關(guān)系上看,很明顯,以后如果要求不用定時器實現(xiàn)us級的延時(按晶振12M,指令周期1us算),那么首選第五:
while(--i);
語句,其分辨率是最高,最精確的,當(dāng)然,對于相同的延時參數(shù),它的實際延時時間也是最短的,它只能最高延時5+255*2=515us,若所需延時大于此值,則需要循環(huán)嵌套;或者,可考慮選用
for(;k>0;k--);
最高延時=10 + 255*8=2050us=2.05ms
需要其他的延時時間片的話,再參考以上的公式計算即可。
擴展閱讀:單片機程序延時方法詳細介紹