c語(yǔ)言delay的用法
在單片機(jī)應(yīng)用中,經(jīng)常會(huì)遇到需要短時(shí)間延時(shí)的情況,一般都是幾十到幾百μs,并且需要很高的精度(比如用單片機(jī)驅(qū)動(dòng)DS18B20時(shí),誤差容許的范圍在十幾μs以內(nèi),不然很容易出錯(cuò));而某些情況下延時(shí)時(shí)間較長(zhǎng),用計(jì)時(shí)器往往有點(diǎn)小題大做。另外在特殊情況下,計(jì)時(shí)器甚至已經(jīng)全部用于其他方面的定時(shí)處理,此時(shí)就只能使用軟件定時(shí)了。下面小編就和大家分享下c語(yǔ)言delay的用法
1 C語(yǔ)言程序延時(shí)
Keil C51的編程語(yǔ)言常用的有2種: 一種是匯編語(yǔ)言;另一種是C 語(yǔ)言。用匯編語(yǔ)言寫(xiě)單片機(jī)程序時(shí),精確時(shí)間延時(shí)是相對(duì)容易解決的。比如,用的是晶振頻率為12 MHz的AT89C51,打算延時(shí)20 μs,51單片機(jī)的指令周期是晶振頻率的1/12,即一個(gè)機(jī)器周期為1 μs;“MOV R0,#X”需要2個(gè)機(jī)器周期,DJNZ也需要2個(gè)機(jī)器周期,單循環(huán)延時(shí)時(shí)間t=2X+3(X為裝入寄存器R0的時(shí)間常數(shù))[2]。這樣,存入R0里的數(shù)初始化為8即可,其精度可以達(dá)到1 μs。用這種方法,可以非常方便地實(shí)現(xiàn)512 μs以下時(shí)間的延時(shí)。如果需要更長(zhǎng)時(shí)間,可以使用兩層或更多層的嵌套,當(dāng)然其精度誤差會(huì)隨著嵌套層的增加而成倍增加。
雖然匯編語(yǔ)言的機(jī)器代碼生成效率很高,但可讀性卻并不強(qiáng),復(fù)雜一點(diǎn)的程序就更難讀懂;而C語(yǔ)言在大多數(shù)情況下,其機(jī)器代碼生成效率和匯編語(yǔ)言相當(dāng),但可讀性和可移植性卻遠(yuǎn)遠(yuǎn)超過(guò)匯編語(yǔ)言,且C 語(yǔ)言還可以嵌入?yún)R編程序來(lái)解決高時(shí)效性的代碼編寫(xiě)問(wèn)題。就開(kāi)發(fā)周期而言,中大型軟件的編寫(xiě)使用C 語(yǔ)言的開(kāi)發(fā)周期通常要比匯編語(yǔ)言短很多,因此研究C語(yǔ)言程序的精確延時(shí)性能具有重要的意義。
C程序中可使用不同類型的變量來(lái)進(jìn)行延時(shí)設(shè)計(jì)。經(jīng)實(shí)驗(yàn)測(cè)試,使用unsigned char類型具有比unsigned int更優(yōu)化的代碼,在使用時(shí)應(yīng)該使用unsigned char作為延時(shí)變量。
2 單層循環(huán)延時(shí)精度分析
下面是進(jìn)行μs級(jí)延時(shí)的while程序代碼。
延時(shí)函數(shù):
void delay1(unsigned char i) {
while(i );}
主函數(shù):
void main() {
while(1) {
delay1(i);
}
}
使用Keil C51的反匯編功能,延時(shí)函數(shù)的匯編代碼如下:
C:0x00E6AE07MOVR6,0x07
C:0x00E81FDECR7
C:0x00E9EEMOVA,R6
C:0x00EA70FAJNZC:00E6
C:0x00EC22RET
圖1 斷點(diǎn)設(shè)置位置圖
通過(guò)對(duì)i賦值為10,在主程序中圖1所示的位置設(shè)置斷點(diǎn)。經(jīng)過(guò)測(cè)試,第1次執(zhí)行到斷點(diǎn)處的時(shí)間為457 μs,再次執(zhí)行到該處的時(shí)間為531 μs,第3次執(zhí)行到斷點(diǎn)處的時(shí)間為605 μs,10次while循環(huán)的時(shí)間為74 μs,整個(gè)測(cè)試結(jié)果如圖2所示。
圖2 使用i--方式測(cè)試仿真結(jié)果圖
通過(guò)對(duì)匯編代碼分析,時(shí)間延遲t=7X+4(其中X為i的取值)。測(cè)試表明,for循環(huán)方式雖然生成的代碼與用while語(yǔ)句不大一樣,但是這兩種方法的效率幾乎相同。C語(yǔ)言中的自減方式有兩種,前面都使用的是i--的方式,能不能使用--i方式來(lái)獲得不同的效果呢?將前面的主函數(shù)保持不變,delay1函數(shù)修改為下面的方式:
void delay1(unsigned char i) {
while(--i);}
同樣進(jìn)行反匯編,得到如下結(jié)果:
C:0x00E3DFFEDJNZR7,
C:00E3C:0x00E522RET
比較發(fā)現(xiàn),--i的匯編代碼效率明顯高于i--方式。由于只有1條語(yǔ)句DJNZ,執(zhí)行只需要2個(gè)時(shí)鐘周期, 1個(gè)時(shí)鐘周期按1 μs計(jì)算,其延時(shí)精度為2 μs;另外,RET需要2個(gè)時(shí)鐘周期,能夠達(dá)到匯編語(yǔ)言代碼的效率。按前面的測(cè)試條件進(jìn)行測(cè)試,第1次執(zhí)行到斷點(diǎn)處的時(shí)間為437 μs,再次執(zhí)行到該處的時(shí)間為465 μs,第3次執(zhí)行到斷點(diǎn)處的時(shí)間為493 μs,10次while循環(huán)的時(shí)間為28 μs,整個(gè)測(cè)試結(jié)果如圖3所示。
圖3 使用--i方式測(cè)試仿真結(jié)果圖
調(diào)整i的取值,i取8時(shí)延時(shí)時(shí)間為24 μs,i取9時(shí)延時(shí)時(shí)間為26 μs。通過(guò)分析得出,10次循環(huán)為28 μs是由于外層循環(huán)造成的,其精度可以達(dá)到2 μs。在設(shè)計(jì)時(shí)應(yīng)該考慮參數(shù)傳遞和RET語(yǔ)句執(zhí)行所需要的時(shí)間周期。實(shí)驗(yàn)分析發(fā)現(xiàn),for語(yǔ)句使用--i方式,同樣能夠達(dá)到與匯編代碼相同的精度。i取不同值時(shí)延時(shí)仿真結(jié)果如圖4所示。
圖4 i取不同值時(shí)延時(shí)仿真結(jié)果圖
3 多重嵌套下的C程序延時(shí)
在某些情況下,延時(shí)較長(zhǎng),僅使用單層循環(huán)方式是不能完成的。此時(shí),只能使用多層循環(huán)方式,那么多重循環(huán)條件下,C程序的精度如何呢?下面是一個(gè)使用for語(yǔ)句實(shí)現(xiàn)1 s延時(shí)的函數(shù)。
延時(shí)函數(shù)
void delay1s(void) {
for(k=100;k>0;k--) //定時(shí)1 s
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
主函數(shù)調(diào)用延時(shí)函數(shù)代碼段:
while(1) {
delay1s();
scond+=1;
}
為了直接衡量這段代碼的效果,利用Keil C找出這段代碼產(chǎn)生的匯編代碼:
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跳轉(zhuǎn)方式,而是DEC和JNZ語(yǔ)句來(lái)實(shí)現(xiàn)循環(huán)判斷。1條JNZ指令要花費(fèi)2個(gè)時(shí)鐘周期,3條指令就需要6個(gè)機(jī)器周期,MOV指令和DEC指令各需要1小時(shí)鐘周期,1個(gè)時(shí)鐘周期按1 μs算,其精度最多達(dá)到8 μs,最后加上一條LCALL和一條RET語(yǔ)句,所以整個(gè)延時(shí)精度較差[4]。
利用Keil C的測(cè)試工具,在一處設(shè)置一個(gè)斷點(diǎn)。第1次執(zhí)行到中斷處的時(shí)間為0.000 513 s,第2次執(zhí)行到中斷處的時(shí)間為1.000 922 s,時(shí)間延遲為1.000 409 s,測(cè)試結(jié)果如圖5所示。對(duì)于上面的3種循環(huán)嵌套,循環(huán)次數(shù)為100×20×248=496 000,每次循環(huán)的時(shí)間約為2 μs。
圖5 三重嵌套循環(huán)1 s實(shí)現(xiàn)時(shí)間測(cè)試結(jié)果
為獲取與匯編語(yǔ)言延時(shí)的差距,同樣進(jìn)行1 s的延時(shí),程序代碼段如下:
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
通過(guò)Keil C51測(cè)試,其實(shí)際延遲時(shí)間為0.997 943 s。雖然C語(yǔ)言實(shí)現(xiàn)延時(shí)方式的匯編代碼復(fù)雜度增加,但是與匯編語(yǔ)言實(shí)現(xiàn)的方式性能差距并不大。
4 總結(jié)
匯編語(yǔ)言在實(shí)時(shí)性方面具有較大的優(yōu)越性,雖然使用Keil C51可以在C語(yǔ)言程序中嵌入?yún)R編代碼,但是復(fù)雜度明顯提高。實(shí)驗(yàn)證明,只要合理地運(yùn)用C語(yǔ)言,在延時(shí)編程方面就可以達(dá)到與匯編語(yǔ)言相近的精度。為了獲得精確的時(shí)間延遲,可通過(guò)Keil C工具的仿真功能,調(diào)整延遲量,從而得到較理想的結(jié)果。