天天看點

用C51編寫單片機延時函數(轉貼)

用C51編寫單片機延時函數(轉貼)

51單片機 2008-07-17 15:56:59 閱讀128 評論0 字号:大中小

參考了51單片機 Keil C 延時程式的簡單研究,自己也親身測試和計算了一些已有的延時函數。

這裡假定單片機是時鐘頻率為12MHz,則一個機器周期為:1us.

參考了51單片機 Keil C 延時程式的簡單研究後,我們可知道, 在Keil C中獲得最為準确的延時函數将是

用C51編寫單片機延時函數(轉貼)

void delay(unsigned char t)

用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)

{

用C51編寫單片機延時函數(轉貼)

    while(--t);

用C51編寫單片機延時函數(轉貼)

}

反彙編代碼如下:

用C51編寫單片機延時函數(轉貼)

執行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)時, 進行反彙編如下:

用C51編寫單片機延時函數(轉貼)

調用delay()時,多執行了兩條指令,其中MOV R, #data需要1個機器周期,LJMP需要2個機器周期,即調用delay()需要3us.

Keil C仿真截圖與計算過程:

用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)

加上調用時間,準确的計算時間延時與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.

現在讓我們來分析一下這個之前用過的延時函數:

用C51編寫單片機延時函數(轉貼)

//延時函數, 對于11.0592MHz時鐘, 例i=10,則大概延時10ms.

用C51編寫單片機延時函數(轉貼)

void delayMs(unsigned int i)

用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)

{

用C51編寫單片機延時函數(轉貼)

    unsigned int j;

用C51編寫單片機延時函數(轉貼)

    while(i--)

用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)

{

用C51編寫單片機延時函數(轉貼)

        for(j = 0; j < 125; j++);

用C51編寫單片機延時函數(轉貼)

    }

用C51編寫單片機延時函數(轉貼)

}

它的反彙編代碼如下:

用C51編寫單片機延時函數(轉貼)

分析: 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 截圖如下:

用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)
用C51編寫單片機延時函數(轉貼)

由分析可知具體的計算延時時間與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單片機指令彙總”