用C51編寫(xiě)單片機(jī)延時(shí)函數(shù)
這里假定單片機(jī)是時(shí)鐘頻率為12MHz,則一個(gè)機(jī)器周期為:1us.
參考了51單片機(jī) Keil C 延時(shí)程序的簡(jiǎn)單研究后,我們可知道, 在Keil C中獲得最為準(zhǔn)確的延時(shí)函數(shù)將是
voiddelay(unsignedchart)
{
while(--t);
}
反匯編代碼如下:{
while(--t);
}
執(zhí)行DJNZ指令需要2個(gè)機(jī)器周期,RET指令同樣需要2個(gè)機(jī)器周期,根據(jù)輸入t,在不計(jì)算調(diào)用delay()所需時(shí)間的情況下,具體時(shí)間延時(shí)如下:
t | Delay Time (us) |
1 | 2×1+2 =4 |
2 | 2×2+2=6 |
N | 2×N+2=2(N+1) |
當(dāng)在main函數(shù)中調(diào)用delay(1)時(shí), 進(jìn)行反匯編如下:
調(diào)用delay()時(shí),多執(zhí)行了兩條指令,其中MOV R, #da
Keil C仿真截圖與計(jì)算過(guò)程:
加上調(diào)用時(shí)間,準(zhǔn)確的計(jì)算時(shí)間延時(shí)與Keil C仿真對(duì)比如下:(可見(jiàn),仿真結(jié)果和計(jì)算結(jié)果是很接近的)
t | Delay Time (us) | 仿真11.0592Mhz時(shí)鐘(us) |
1 | 3+2×1+2 =7 | 7.7(實(shí)際) | 7.60 |
2 | 3+2×2+2=9 | 9.9 | 9.76 |
N | 3+2×N+2=2N+5 | (2N+5)*1.1 | / |
3 | 11 | 12.1 | 11.94 |
15 | 35 | 38.5 | 37.98 |
100 | 205 | 225.5 | 222.44 |
255 | 515 | 566.5 | 558.81 |
也就是說(shuō),這個(gè)延時(shí)函數(shù)的精度為2us,最小的時(shí)間延時(shí)為7us,最大的時(shí)間延時(shí)為3+255×2+2=515us.
實(shí)際中使用11.0592MHz的時(shí)鐘,這個(gè)延時(shí)函數(shù)的精度將為2.2us,最小時(shí)間延時(shí)為7.7us, 最大時(shí)間延時(shí)為566.5us.
這個(gè)時(shí)間延時(shí)函數(shù),對(duì)于與DS18B20進(jìn)行單總線通信,已經(jīng)足夠準(zhǔn)確了。
現(xiàn)在,我們將時(shí)鐘換成11.0592MHz這個(gè)實(shí)際用到的頻率,每個(gè)機(jī)器周期約為1.1us.
現(xiàn)在讓我們來(lái)分析一下這個(gè)之前用過(guò)的延時(shí)函數(shù):
//延時(shí)函數(shù),對(duì)于11.0592MHz時(shí)鐘,例i=10,則大概延時(shí)10ms.
voiddelayMs(unsignedinti)
{
unsignedintj;
while(i--)
{
for(j=0;j<125;j++);
}
}
voiddelayMs(unsignedinti)
{
unsignedintj;
while(i--)
{
for(j=0;j<125;j++);
}
}
它的反匯編代碼如下:
分析: T表示一個(gè)機(jī)器周期(調(diào)用時(shí)間相對(duì)于這個(gè)ms級(jí)的延時(shí)來(lái)說(shuō),可忽略不計(jì))
1C:0000MOVA,R7;1T
2DECR7;1T低8位字節(jié)減1
3MOVR2,0x06;2T
4JNZC:0007;2T若低8位字節(jié)不為0,則跳到C:0007
5DECR6;1T低8位字節(jié)為0,則高8位字節(jié)減1
6C:0007ORLA,R2;1T
7JZC:001D;2T若高8位也減為0,則RET
8CLRA;1TA清零
9MOVR4,A;1TR4放高位
10MOVR5,A;1TR5放低位
11C:000DCLRC;1TC清零
12MOVA,R5;1T
13SUBBA,#0x7d;1TA=A-125
14MOVA,R4;1T
15SUBBA,#0x00;1TA
16JNCC:0000;2TA為零則跳到C:0000
17INCR5;1TR5增1
18CJNER5,#0x00,C:001B;2TR5>0,跳轉(zhuǎn)到C:000D
19INCR4;1T
20C:001BSJMPC:000D;2T
21C:001DRET
2DECR7;1T低8位字節(jié)減1
3MOVR2,0x06;2T
4JNZC:0007;2T若低8位字節(jié)不為0,則跳到C:0007
5DECR6;1T低8位字節(jié)為0,則高8位字節(jié)減1
6C:0007ORLA,R2;1T
7JZC:001D;2T若高8位也減為0,則RET
8CLRA;1TA清零
9MOVR4,A;1TR4放高位
10MOVR5,A;1TR5放低位
11C:000DCLRC;1TC清零
12MOVA,R5;1T
13SUBBA,#0x7d;1TA=A-125
14MOVA,R4;1T
15SUBBA,#0x00;1TA
16JNCC:0000;2TA為零則跳到C:0000
17INCR5;1TR5增1
18CJNER5,#0x00,C:001B;2TR5>0,跳轉(zhuǎn)到C:000D
19INCR4;1T
20C:001BSJMPC:000D;2T
21C:001DRET
對(duì)于delayMs(1), 執(zhí)行到第7行就跳到21行, 共需時(shí)12T, 即13.2us
對(duì)于delayMs(2), 需時(shí)9T+13T+124×10T+7T+12T = 9T+13T+1240T+7T+12T =1281T =1409.1us.
對(duì)于delayMs(3), 需時(shí)9T×(3-1)+(13T+124×10T+7T)×(3-1)+12T
=1269T×(3-1)+12T=2550T=2805us.
對(duì)于delayMs(N),N>1, 需時(shí)1269T×(N-1)+12T = 1269NT-1257T=(1395.9N-1382.7)us.
利用Keil C仿真delayMs(1) = 0.00166558s = 1.67ms 截圖如下:
由分析可知具體的計(jì)算延時(shí)時(shí)間與Keil C仿真延時(shí)對(duì)比如下:
i | Time Delay | 仿真延時(shí) |
1 | 13.2us | 1.67ms |
2 | 1409.1us | 3.31ms |
3 | 2805us | 4.96ms |
N | (1395.9N-1382.7)us | |
10 | 12.6ms | 16.50ms |
20 | 26.5ms | 32.98ms |
30 | 40.5ms | 49.46ms |
50 | 68.4ms | 82.43ms |
100 | 138.2ms | 164.84ms |
200 | 277.8ms | 329.56ms |
500 | 696.6ms | 824.13ms |
1000 | 1394.5ms | 1648.54ms |
1500 | 2092.5ms | 2472.34ms |
2000 | 2790.4ms | 3296.47ms |
5 | 5.6ms | 8.26ms |
73 | 100.5ms | 120.34ms |
720 | 1003.7ms = 1s | 1186.74ms |
計(jì)算delayMs(10)得到延時(shí)時(shí)間為:12576.3us約等于12.6ms,接近我們認(rèn)為的10ms。
經(jīng)過(guò)以上分析,可見(jiàn)用C語(yǔ)言來(lái)做延時(shí)并不是不太準(zhǔn)確,只是不容易做到非常準(zhǔn)確而已,若有一句語(yǔ)句變了,延時(shí)時(shí)間很可能會(huì)不同,因?yàn)榫幾g程序生成的匯編指令很可能不同。
PS:
對(duì)于每條51單片機(jī)匯編指令的字長(zhǎng)和所需機(jī)器周期匯總?cè)缦拢恨D(zhuǎn)自:http://bbs.mcustudy.com/printpage.asp?BoardID=2&ID=1454
Appendix E - 8051 Instruction Set
Arithmetic Operations
MnemonicDescriptionSizeCycles
ADD A,Rn Add register to Accumulator (ACC).11
ADD A,direct Add direct byte to ACC.21
ADD A,@Ri Add indirect RAM to ACC.11
ADD A,#da
ADDC A,Rn Add register to ACC with carry.11
ADDC A,direct Add direct byte to ACC with carry.21
ADDC A,@Ri Add indirect RAM to ACC with carry.11
ADDC A,#da
SUBB A,Rn Subtract register from ACC with borrow.11
SUBB A,direct Subtract direct byte from ACC with borrow21
SUBB A,@Ri Subtract indirect RAM from ACC with borrow.11
SUBB A,#da
INC A Increment ACC.11
INC Rn Increment register.11
INC direct Increment direct byte.21
INC @Ri Increment indirect RAM.11
DEC A Decrement ACC.11
DEC Rn Decrement register.11
DEC direct Decrement direct byte.21
DEC @Ri Decrement indirect RAM.11
INC DPTR Increment da
MUL AB Multiply A and B Result: A <- low byte, B <- high byte.14
DIV AB Divide A by B Result: A <- whole part, B <- remainder. 14
DA A Decimal adjust ACC.11
Logical Operations
MnemonicDescriptionSizeCycles
ANL A,Rn AND Register to ACC.11
ANL A,direct AND direct byte to ACC.21
ANL A,@Ri AND indirect RAM to ACC.11
ANL A,#da
ANL direct,A AND ACC to direct byte.21
ANL direct,#da
ORL A,Rn OR Register to ACC.11
ORL A,direct OR direct byte to ACC.21
ORL A,@Ri OR indirect RAM to ACC.11
ORL A,#da
ORL direct,A OR ACC to direct byte.21
ORL direct,#da
XRL A,Rn Exclusive OR Register to ACC.11
XRL A,direct Exclusive OR direct byte to ACC.21
XRL A,@Ri Exclusive OR indirect RAM to ACC.11
XRL A,#da
XRL direct,A Exclusive OR ACC to direct byte.21
XRL direct,#da
CLR A Clear ACC (set all bits to zero).11
CPL A Compliment ACC.11
RL A Rotate ACC left.11
RLC A Rotate ACC left through carry.11
RR A Rotate ACC right.11
RRC A Rotate ACC right through carry.11
SWAP A Swap nibbles within ACC.11
Da
MnemonicDescriptionSizeCycles
MOV A,Rn Move register to ACC.11
MOV A,direct Move direct byte to ACC.21
MOV A,@Ri Move indirect RAM to ACC.11
MOV A,#da
MOV Rn,A Move ACC to register.11
MOV Rn,direct Move direct byte to register.22
MOV Rn,#da
MOV direct,A Move ACC to direct byte.21
MOV direct,Rn Move register to direct byte.22
MOV direct,direct Move direct byte to direct byte.32
MOV direct,@Ri Move indirect RAM to direct byte.22
MOV direct,#da
MOV @Ri,A Move ACC to indirect RAM.11
MOV @Ri,direct Move direct byte to indirect RAM.22
MOV @Ri,#da
MOV DPTR,#da
MOVC A,@A+DPTR Move co
MOVC A,@A+PC Move co
MOVX A,@Ri Move external RAM to ACC (8 bit address).12
MOVX A,@DPTR Move external RAM to ACC (16 bit address).12
MOVX @Ri,A Move ACC to external RAM (8 bit address).12
MOVX @DPTR,A Move ACC to external RAM (16 bit address).12
PUSH direct Push direct byte on
POP direct Pop direct byte from stack.22
XCH A,Rn Exchange register with ACC.11
XCH A,direct Exchange direct byte with ACC.21
XCH A,@Ri Exchange indirect RAM with ACC.11
XCHD A,@Ri Exchange low order nibble of indirect RAM with low order nibble of ACC.11
Boolean Variable Manipulation
MnemonicDescriptionSizeCycles
CLR C Clear carry flag.11
CLR bit Clear direct bit.21
SETB C Set carry flag.11
SETB bit Set direct bit.21
CPL C Compliment carry flag.11
CPL bit Compliment direct bit.21
ANL C,bit AND direct bit to carry flag.22
ANL C,/bit AND compliment of direct bit to carry.22
ORL C,bit OR direct bit to carry flag.22
ORL C,/bit OR compliment of direct bit to carry.22
MOV C,bit Move direct bit to carry flag.21
MOV bit,C Move carry to direct bit.22
JC rel Jump if carry is set.22
JNC rel Jump if carry is not set.22
JB bit,rel Jump if direct bit is set.32
JNB bit,rel Jump if direct bit is not set.32
JBC bit,rel Jump if direct bit is set & clear bit.32
Program Branching
MnemonicDescriptionSizeCycles
ACALL addr11 Absolute subroutine call.22
LCALL addr16 Long subroutine call.32
RET Return from subroutine.12
RETI Return from interrupt.12
AJMP addr11 Absolute jump.22
LJMP addr16 Long jump.32
SJMP rel Short jump (relative address).22
JMP @A+DPTR Jump indirect relative to the DPTR.12
JZ rel Jump relative if ACC is zero.22
JNZ rel Jump relative if ACC is not zero.22
CJNE A,direct,rel Compare direct byte to ACC and jump if not equal.32
CJNE A,#da
CJNE Rn,#da
CJNE @Ri,#da
DJNZ Rn,rel Decrement register and jump if not zero.22
DJNZ direct,rel Decrement direct byte and jump if not zero.32
Other Instructions
MnemonicDescriptionSizeCycles
NOP No operation.11
其它可查看《單片機(jī)基礎(chǔ)》-李廣弟等編著,P70 “MCS-51單片機(jī)指令匯總”
評(píng)論