商務英語計算機英語

c語言delay的用法

本文已影響 9.3K人 

在微控制器應用中,經常會遇到需要短時間延時的情況,一般都是幾十到幾百μs,並且需要很高的精度(比如用微控制器驅動DS18B20時,誤差容許的範圍在十幾μs以內,不然很容易出錯);而某些情況下延時時間較長,用計時器往往有點小題大做。另外在特殊情況下,計時器甚至已經全部用於其他方面的定時處理,此時就只能使用軟體定時了。下面小編就和大家分享下c語言delay的用法

ing-bottom: 150.23%;">c語言delay的用法

1 C語言程式延時

Keil C51的程式語言常用的有2種: 一種是組合語言;另一種是C 語言。用匯編語言寫微控制器程式時,精確時間延時是相對容易解決的。比如,用的是晶振頻率為12 MHz的AT89C51,打算延時20 μs,51微控制器的指令週期是晶振頻率的1/12,即一個機器週期為1 μs;“MOV R0,#X”需要2個機器週期,DJNZ也需要2個機器週期,單迴圈延時時間t=2X+3(X為裝入暫存器R0的時間常數)[2]。這樣,存入R0裡的數初始化為8即可,其精度可以達到1 μs。用這種方法,可以非常方便地實現512 μs以下時間的延時。如果需要更長時間,可以使用兩層或更多層的巢狀,當然其精度誤差會隨著巢狀層的增加而成倍增加。

雖然組合語言的機器程式碼生成效率很高,但可讀性卻並不強,複雜一點的程式就更難讀懂;而C語言在大多數情況下,其機器程式碼生成效率和組合語言相當,但可讀性和可移植性卻遠遠超過組合語言,且C 語言還可以嵌入彙編程式來解決高時效性的程式碼編寫問題。就開發週期而言,中大型軟體的編寫使用C 語言的開發週期通常要比組合語言短很多,因此研究C語言程式的精確延時效能具有重要的意義。

C程式中可使用不同型別的變數來進行延時設計。經實驗測試,使用unsigned char型別具有比unsigned int更優化的程式碼,在使用時應該使用unsigned char作為延時變數。

2 單層迴圈延時精度分析

下面是進行μs級延時的while程式程式碼。

延時函式:

void delay1(unsigned char i) {

while(i );}

主函式:

void main() {

while(1) {

delay1(i);

}

}

使用Keil C51的反彙編功能,延時函式的彙編程式碼如下:

C:0x00E6AE07MOVR6,0x07

C:0x00E81FDECR7

C:0x00E9EEMOVA,R6

C:0x00EA70FAJNZC:00E6

C:0x00EC22RET

圖1 斷點設定位置圖

通過對i賦值為10,在主程式中圖1所示的位置設定斷點。經過測試,第1次執行到斷點處的時間為457 μs,再次執行到該處的時間為531 μs,第3次執行到斷點處的時間為605 μs,10次while迴圈的時間為74 μs,整個測試結果如圖2所示。

圖2 使用i--方式測試模擬結果圖

通過對彙編程式碼分析,時間延遲t=7X+4(其中X為i的取值)。測試表明,for迴圈方式雖然生成的程式碼與用while語句不大一樣,但是這兩種方法的效率幾乎相同。C語言中的自減方式有兩種,前面都使用的是i--的方式,能不能使用--i方式來獲得不同的效果呢?將前面的主函式保持不變,delay1函式修改為下面的方式:

void delay1(unsigned char i) {

while(--i);}

同樣進行反彙編,得到如下結果:

C:0x00E3DFFEDJNZR7,

C:00E3C:0x00E522RET

比較發現,--i的彙編程式碼效率明顯高於i--方式。由於只有1條語句DJNZ,執行只需要2個時鐘週期, 1個時鐘週期按1 μs計算,其延時精度為2 μs;另外,RET需要2個時鐘週期,能夠達到組合語言程式碼的效率。按前面的測試條件進行測試,第1次執行到斷點處的時間為437 μs,再次執行到該處的時間為465 μs,第3次執行到斷點處的時間為493 μs,10次while迴圈的時間為28 μs,整個測試結果如圖3所示。

圖3 使用--i方式測試模擬結果圖

調整i的取值,i取8時延時時間為24 μs,i取9時延時時間為26 μs。通過分析得出,10次迴圈為28 μs是由於外層迴圈造成的,其精度可以達到2 μs。在設計時應該考慮引數傳遞和RET語句執行所需要的時間週期。實驗分析發現,for語句使用--i方式,同樣能夠達到與彙編程式碼相同的精度。i取不同值時延時模擬結果如圖4所示。

圖4 i取不同值時延時模擬結果圖

3 多重巢狀下的C程式延時

在某些情況下,延時較長,僅使用單層迴圈方式是不能完成的。此時,只能使用多層迴圈方式,那麼多重迴圈條件下,C程式的精度如何呢?下面是一個使用for語句實現1 s延時的函式。

延時函式

void delay1s(void) {

for(k=100;k>0;k--) //定時1 s

for(i=20;i>0;i--)

for(j=248;j>0;j--);

}

主函式呼叫延時函式程式碼段:

while(1) {

delay1s();

scond+=1;

}

為了直接衡量這段程式碼的效果,利用Keil C找出這段程式碼產生的彙編程式碼:

C:0x00B37002JNZ

C:00B7C:0x00B5150CDEC0x0C

C:0x00B7E50DMOVA,0x0D

C:0x00B9450CORLA,0x0C

C:0x00BB70DEJNZC:009B

C:0x00BDE50BMOVA,0x0B

C:0x00BF150BDEC0x0B

C:0x00C17002JNZC:00C5

C:0x00C3150ADEC0x0A

C:0x00C5E50BMOVA,0x0B

C:0x00C7450AORLA,0x0A

C:0x00C970CAJNZC:0095

C:0x00CB22RET

分析彙編程式碼,其他彙編程式碼使用的不是DJNZ跳轉方式,而是DEC和JNZ語句來實現迴圈判斷。1條JNZ指令要花費2個時鐘週期,3條指令就需要6個機器週期,MOV指令和DEC指令各需要1小時鐘週期,1個時鐘週期按1 μs算,其精度最多達到8 μs,最後加上一條LCALL和一條RET語句,所以整個延時精度較差[4]。

利用Keil C的測試工具,在一處設定一個斷點。第1次執行到中斷處的時間為0.000 513 s,第2次執行到中斷處的時間為1.000 922 s,時間延遲為1.000 409 s,測試結果如圖5所示。對於上面的3種迴圈巢狀,迴圈次數為100×20×248=496 000,每次迴圈的時間約為2 μs。

圖5 三重巢狀迴圈1 s實現時間測試結果

為獲取與組合語言延時的差距,同樣進行1 s的延時,程式程式碼段如下:

LCALL DELY1S

INC Second

DELY1S:MOV R5,#100

D2:MOV R6,#20

D1:MOV R7,#248

DJNZ R7,$

DJNZ R6,D1

DJNZ R5,D2

RET

通過Keil C51測試,其實際延遲時間為0.997 943 s。雖然C語言實現延時方式的彙編程式碼複雜度增加,但是與組合語言實現的方式效能差距並不大。

4 總結

組合語言在實時性方面具有較大的優越性,雖然使用Keil C51可以在C語言程式中嵌入彙編程式碼,但是複雜度明顯提高。實驗證明,只要合理地運用C語言,在延時程式設計方面就可以達到與組合語言相近的精度。為了獲得精確的時間延遲,可通過Keil C工具的模擬功能,調整延遲量,從而得到較理想的結果。

猜你喜歡

熱點閱讀

最新文章

推薦閱讀