用C51編寫單片機延時函數(轉貼)
51單片機 2008-07-17 15:56:59 閱讀128 評論0 字号:大中小
參考了51單片機 Keil C 延時程式的簡單研究,自己也親身測試和計算了一些已有的延時函數。
這裡假定單片機是時鐘頻率為12MHz,則一個機器周期為:1us.
參考了51單片機 Keil C 延時程式的簡單研究後,我們可知道, 在Keil C中獲得最為準确的延時函數将是
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuUmbv50LcNncvRXYjlGZul0ZulmbpxGd190LcNXZnFWbJ9CXt92YuM3ZvxmYuNmL3d3dvw1LcpDc0RHaiojIsJye.gif)
void delay(unsigned char t)
{
while(--t);
}
反彙編代碼如下:
執行DJNZ指令需要2個機器周期,RET指令同樣需要2個機器周期,根據輸入t,在不計算調用delay()所需時間的情況下,具體時間延時如下:
t | Delay Time (us) |
1 | 2×1+2 =4 |
2 | 2×2+2=6 |
N | 2×N+2=2(N+1) |
當在main函數中調用delay(1)時, 進行反彙編如下:
調用delay()時,多執行了兩條指令,其中MOV R, #data需要1個機器周期,LJMP需要2個機器周期,即調用delay()需要3us.
Keil C仿真截圖與計算過程:
加上調用時間,準确的計算時間延時與Keil C仿真對比如下:(可見,仿真結果和計算結果是很接近的)
t | Delay Time (us) | 仿真11.0592Mhz時鐘(us) |
1 | 3+2×1+2 =7 | 7.7(實際) | 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 |
也就是說,這個延時函數的精度為2us,最小的時間延時為7us,最大的時間延時為3+255×2+2=515us.
實際中使用11.0592MHz的時鐘,這個延時函數的精度将為2.2us,最小時間延時為7.7us, 最大時間延時為566.5us.
這個時間延時函數,對于與DS18B20進行單總線通信,已經足夠準确了。
現在,我們将時鐘換成11.0592MHz這個實際用到的頻率,每個機器周期約為1.1us.
現在讓我們來分析一下這個之前用過的延時函數:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuUmbv50LcNncvRXYjlGZul0ZulmbpxGd190LcNXZnFWbJ9CXt92YuM3ZvxmYuNmL3d3dvw1LcpDc0RHaiojIsJye.gif)
//延時函數, 對于11.0592MHz時鐘, 例i=10,則大概延時10ms.
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuUmbv50LcNncvRXYjlGZul0ZulmbpxGd190LcNXZnFWbJ9CXt92YuM3ZvxmYuNmL3d3dvw1LcpDc0RHaiojIsJye.gif)
void delayMs(unsigned int i)
{
unsigned int j;
while(i--)
{
for(j = 0; j < 125; j++);
}
}
它的反彙編代碼如下:
分析: T表示一個機器周期(調用時間相對于這個ms級的延時來說,可忽略不計)
1 C:0000 MOV A, R7 ;1T
2 DEC R7 ;1T 低8位位元組減1
3 MOV R2, 0x06 ;2T
4 JNZ C:0007 ;2T 若低8位位元組不為0, 則跳到C:0007
5 DEC R6 ;1T 低8位位元組為0, 則高8位位元組減1
6 C:0007 ORL A, R2 ;1T
7 JZ C:001D ;2T 若高8位也減為0, 則RET
8 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 ;1T
13 SUBB A, #0x7d ;1T A = A-125
14 MOV A, R4 ;1T
15 SUBB A, #0x00 ;1T A
16 JNC C:0000 ;2T A為零則跳到C:0000
17 INC R5 ;1T R5增1
18 CJNE R5,#0x00, C:001B ;2T R5>0, 跳轉到C:000D
19 INC R4 ;1T
20 C:001B SJMP C:000D ;2T
21 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 截圖如下:
由分析可知具體的計算延時時間與Keil C仿真延時對比如下:
i | Time Delay | 仿真延時 |
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 |
計算delayMs(10)得到延時時間為:12576.3us約等于12.6ms,接近我們認為的10ms。
計算結果和仿真結果隻要delayMs(1)有很大出入, 其它都接近, 在接受範圍内.
經過以上分析,可見用C語言來做延時并不是不太準确,隻是不容易做到非常準确而已,若有一句語句變了,延時時間很可能會不同,因為編譯程式生成的彙編指令很可能不同。
PS:
對于每條51單片機彙編指令的字長和所需機器周期彙總如下:轉自:http://bbs.mcustudy.com/printpage.asp?BoardID=2&ID=1454
Appendix E - 8051 Instruction Set
Arithmetic Operations
Mnemonic Description Size Cycles
ADD A,Rn Add register to Accumulator (ACC). 1 1
ADD A,direct Add direct byte to ACC. 2 1
ADD A,@Ri Add indirect RAM to ACC. 1 1
ADD A,#data Add immediate data to ACC. 2 1
ADDC A,Rn Add register to ACC with carry. 1 1
ADDC A,direct Add direct byte to ACC with carry. 2 1
ADDC A,@Ri Add indirect RAM to ACC with carry. 1 1
ADDC A,#data Add immediate data to ACC with carry. 2 1
SUBB A,Rn Subtract register from ACC with borrow. 1 1
SUBB A,direct Subtract direct byte from ACC with borrow 2 1
SUBB A,@Ri Subtract indirect RAM from ACC with borrow. 1 1
SUBB A,#data Subtract immediate data from ACC with borrow. 2 1
INC A Increment ACC. 1 1
INC Rn Increment register. 1 1
INC direct Increment direct byte. 2 1
INC @Ri Increment indirect RAM. 1 1
DEC A Decrement ACC. 1 1
DEC Rn Decrement register. 1 1
DEC direct Decrement direct byte. 2 1
DEC @Ri Decrement indirect RAM. 1 1
INC DPTR Increment data pointer. 1 2
MUL AB Multiply A and B Result: A <- low byte, B <- high byte. 1 4
DIV AB Divide A by B Result: A <- whole part, B <- remainder. 1 4
DA A Decimal adjust ACC. 1 1
Logical Operations
Mnemonic Description Size Cycles
ANL A,Rn AND Register to ACC. 1 1
ANL A,direct AND direct byte to ACC. 2 1
ANL A,@Ri AND indirect RAM to ACC. 1 1
ANL A,#data AND immediate data to ACC. 2 1
ANL direct,A AND ACC to direct byte. 2 1
ANL direct,#data AND immediate data to direct byte. 3 2
ORL A,Rn OR Register to ACC. 1 1
ORL A,direct OR direct byte to ACC. 2 1
ORL A,@Ri OR indirect RAM to ACC. 1 1
ORL A,#data OR immediate data to ACC. 2 1
ORL direct,A OR ACC to direct byte. 2 1
ORL direct,#data OR immediate data to direct byte. 3 2
XRL A,Rn Exclusive OR Register to ACC. 1 1
XRL A,direct Exclusive OR direct byte to ACC. 2 1
XRL A,@Ri Exclusive OR indirect RAM to ACC. 1 1
XRL A,#data Exclusive OR immediate data to ACC. 2 1
XRL direct,A Exclusive OR ACC to direct byte. 2 1
XRL direct,#data XOR immediate data to direct byte. 3 2
CLR A Clear ACC (set all bits to zero). 1 1
CPL A Compliment ACC. 1 1
RL A Rotate ACC left. 1 1
RLC A Rotate ACC left through carry. 1 1
RR A Rotate ACC right. 1 1
RRC A Rotate ACC right through carry. 1 1
SWAP A Swap nibbles within ACC. 1 1
Data Transfer
Mnemonic Description Size Cycles
MOV A,Rn Move register to ACC. 1 1
MOV A,direct Move direct byte to ACC. 2 1
MOV A,@Ri Move indirect RAM to ACC. 1 1
MOV A,#data Move immediate data to ACC. 2 1
MOV Rn,A Move ACC to register. 1 1
MOV Rn,direct Move direct byte to register. 2 2
MOV Rn,#data Move immediate data to register. 2 1
MOV direct,A Move ACC to direct byte. 2 1
MOV direct,Rn Move register to direct byte. 2 2
MOV direct,direct Move direct byte to direct byte. 3 2
MOV direct,@Ri Move indirect RAM to direct byte. 2 2
MOV direct,#data Move immediate data to direct byte. 3 2
MOV @Ri,A Move ACC to indirect RAM. 1 1
MOV @Ri,direct Move direct byte to indirect RAM. 2 2
MOV @Ri,#data Move immediate data to indirect RAM. 2 1
MOV DPTR,#data16 Move immediate 16 bit data to data pointer register. 3 2
MOVC A,@A+DPTR Move code byte relative to DPTR to ACC (16 bit address). 1 2
MOVC A,@A+PC Move code byte relative to PC to ACC (16 bit address). 1 2
MOVX A,@Ri Move external RAM to ACC (8 bit address). 1 2
MOVX A,@DPTR Move external RAM to ACC (16 bit address). 1 2
MOVX @Ri,A Move ACC to external RAM (8 bit address). 1 2
MOVX @DPTR,A Move ACC to external RAM (16 bit address). 1 2
PUSH direct Push direct byte onto stack. 2 2
POP direct Pop direct byte from stack. 2 2
XCH A,Rn Exchange register with ACC. 1 1
XCH A,direct Exchange direct byte with ACC. 2 1
XCH A,@Ri Exchange indirect RAM with ACC. 1 1
XCHD A,@Ri Exchange low order nibble of indirect RAM with low order nibble of ACC. 1 1
Boolean Variable Manipulation
Mnemonic Description Size Cycles
CLR C Clear carry flag. 1 1
CLR bit Clear direct bit. 2 1
SETB C Set carry flag. 1 1
SETB bit Set direct bit. 2 1
CPL C Compliment carry flag. 1 1
CPL bit Compliment direct bit. 2 1
ANL C,bit AND direct bit to carry flag. 2 2
ANL C,/bit AND compliment of direct bit to carry. 2 2
ORL C,bit OR direct bit to carry flag. 2 2
ORL C,/bit OR compliment of direct bit to carry. 2 2
MOV C,bit Move direct bit to carry flag. 2 1
MOV bit,C Move carry to direct bit. 2 2
JC rel Jump if carry is set. 2 2
JNC rel Jump if carry is not set. 2 2
JB bit,rel Jump if direct bit is set. 3 2
JNB bit,rel Jump if direct bit is not set. 3 2
JBC bit,rel Jump if direct bit is set & clear bit. 3 2
Program Branching
Mnemonic Description Size Cycles
ACALL addr11 Absolute subroutine call. 2 2
LCALL addr16 Long subroutine call. 3 2
RET Return from subroutine. 1 2
RETI Return from interrupt. 1 2
AJMP addr11 Absolute jump. 2 2
LJMP addr16 Long jump. 3 2
SJMP rel Short jump (relative address). 2 2
JMP @A+DPTR Jump indirect relative to the DPTR. 1 2
JZ rel Jump relative if ACC is zero. 2 2
JNZ rel Jump relative if ACC is not zero. 2 2
CJNE A,direct,rel Compare direct byte to ACC and jump if not equal. 3 2
CJNE A,#data,rel Compare immediate byte to ACC and jump if not equal. 3 2
CJNE Rn,#data,rel Compare immediate byte to register and jump if not equal. 3 2
CJNE @Ri,#data,rel Compare immediate byte to indirect and jump if not equal. 3 2
DJNZ Rn,rel Decrement register and jump if not zero. 2 2
DJNZ direct,rel Decrement direct byte and jump if not zero. 3 2
Other Instructions
Mnemonic Description Size Cycles
NOP No operation. 1 1
其它可檢視《單片機基礎》-李廣弟等編著,P70 “MCS-51單片機指令彙總”