導航:首頁 > 操作系統 > 單片機c語言延時

單片機c語言延時

發布時間:2022-09-14 23:55:32

單片機C語言延時需要注意的問題

標準的C語言中沒有空語句。但在單片機的C語言編程中,經常需要用幾個空指令產生短延時的效果。這在匯編語言中很容易實現,寫幾個nop就行了。
在keil C51中,直接調用庫函數:
#include // 聲明了void _nop_(void);
_nop_(); // 產生一條NOP指令

作用:對於延時很短的,要求在us級的,採用「_nop_」函數,這個函數相當匯編NOP指令,延時幾微秒。NOP指令為單周期指令,可由晶振頻率算出延時時間,對於12M晶振,延時1uS。對於延時比較長的,要求在大於10us,採用C51中的循環語句來實現。

在選擇C51中循環語句時,要注意以下幾個問題
第一、定義的C51中循環變數,盡量採用無符號字元型變數。
第二、在FOR循環語句中,盡量採用變數減減來做循環。
第三、在do…while,while語句中,循環體內變數也採用減減方法。
這因為在C51編譯器中,對不同的循環方法,採用不同的指令來完成的。
下面舉例說明:
unsigned char i;
for(i=0;i<255;i++);
unsigned char i;
for(i=255;i>0;i--);

其中,第二個循環語句C51編譯後,就用DJNZ指令來完成,相當於如下指令:
MOV09H,#0FFH
LOOP: DJNZ09H,LOOP
指令相當簡潔,也很好計算精確的延時時間。
同樣對do…while,while循環語句中,也是如此
例:
unsigned char n;
n=255;
do{n--}
while(n);

n=255;
while(n)
{n--};

這兩個循環語句經過C51編譯之後,形成DJNZ來完成的方法,
故其精確時間的計算也很方便。
其三:對於要求精確延時時間更長,這時就要採用循環嵌套的方法來實現,因此,循環嵌套的方法常用於達到ms級的延時。對於循環語句同樣可以採用for,do…while,while結構來完成,每個循環體內的變數仍然採用無符號字元變數。
unsigned char i,j
for(i=255;i>0;i--)
for(j=255;j>0;j--);

unsigned char i,j
i=255;
do{j=255;
do{j--}
while(j);
i--;
}
while(i);

unsigned char i,j
i=255;
while(i)
{j=255;
while(j)
{j--};
i--;
}
這三種方法都是用DJNZ指令嵌套實現循環的,由C51編譯器用下面的指令組合來完成的
MOVR7,#0FFH
LOOP2: MOVR6,#0FFH
LOOP1: DJNZR6,LOOP1
DJNZR7,LOOP2
這些指令的組合在匯編語言中採用DJNZ指令來做延時用,因此它的時間精確計算也是很簡單,假上面變數i的初值為m,變數j的初值為n,則總延時時 間為:m×(n×T+T),其中T為DJNZ指令執行時間(DJNZ指令為雙周期指令)。這里的+T為MOV這條指令所使用的時間。同樣對於更長時間的延 時,可以採用多重循環來完成。
只要在程序設計循環語句時注意以上幾個問題。
下面給出有關在C51中延時子程序設計時要注意的問題
1、在C51中進行精確的延時子程序設計時,盡量不要或少在延時子程序中定義局部變數,所有的延時子程序中變數通過有參函數傳遞。
2、在延時子程序設計時,採用do…while,結構做循環體要比for結構做循環體好。
3、在延時子程序設計時,要進行循環體嵌套時,採用先內循環,再減減比先減減,再內循環要好。
unsigned char delay(unsigned char i,unsigned char j,unsigned char k)
{unsigned char b,c;
b="j";
c="k";
do{
do{
do{k--};
while(k);
k="c";
j--;};
while(j);
j=b;
i--;};
while(i);
}

這精確延時子程序就被C51編譯為有下面的指令組合完成
delay延時子程序如下:
MOV R6,05H
MOV R4,03H
C0012: DJNZ R3, C0012
MOV R3,04H
DJNZ R5, C0012
MOV R5,06H
DJNZ R7, C0012
RET
假設參數變數i的初值為m,參數變數j的初值為n,參數變數k的初值為l,則總延時時間為:l×(n×(m×T+2T)+2T)+3T,其中T為 DJNZ和MOV指令執行的時間。當m=n=l時,精確延時為9T,最短;當m=n=l=256時,精確延時到16908803T,最長。

❷ 單片機C語言編程問題:延時函數運行中能否響應中斷

摘要 所謂中斷,就是可以打斷正常運行的程序,這個程序也可以是正在運行的延時程序,除非程序中主動禁止

❸ 單片機延時1秒如何計算要最詳細一點的要過程用C語言

unsigned char rSecondCount; //秒計時數
unsigned char rMinuteCount; //分計時數
sbit IsOneSecondReach;
sbit Pulse_Sec=P1^0;
sbit Pulse_Min=P1^1;
main()
{
rSecondCount=0;
rMinuteCount=0;
TH1=0x3C;
TL1=0xAF; //定時器50ms產生一次中斷 (FFFF-3CAF)us
MOD = 0x10; //定時器1工作於模式1,(用工作於模式2也可以,而且更 簡便)
TR1=1; //使能定時器1
ET1=1; //開中斷
EA=1; //開全局中斷
while(1)
{
if (IsOneSecondReach)
{
IsOneSecondReach = 0;
//do something,如果一秒延時標志為1,則清除此標志,等待下次1秒,在此處
//執行需要執行的程序
}
}
}
/* 定時器50ms產生一次中斷 */
void Timer(void) interrupt 3
{
/* 重新載入T1參數 */
TH1=0x3C;
TL1=0xAF;
/* 一秒累加 */
rSecondCount++;//秒計時+1
if (rSecondCount==20) //1sec到,50ms*20
{
IsOneSecondReach = 1;
}
}
//
脈沖寬度為50ms,如果有其他要求的話,修改T1參數和「秒分」的參數湊下就行了.

❹ 51單片機C語言程序中延時函數delay的原理是什麼

原理:只是執行一些所謂的「無實際意義的指令」,如縮放或執行一個int自加,簡單地說,就像高中數學中的「乘法原理」一樣,很容易迅速增加上面提到的「無意義指令」的數量

關於大小的值:如果是在C語言中,該值不僅與水晶振動、單片機本身的速度,但也與C的編譯器,所以,雖然這個值可以精確計算,但大多數情況下,程序員是經驗值。

當然,如果你在匯編中編程,情況就不同了,因為每條指令使用一定數量的機器周期,你當然可以根據所有指令使用的總時間來計算特定延遲的總時間。

(4)單片機c語言延時擴展閱讀:

定義延遲XMS毫秒的延遲函數

Voiddelay(unsignedintXMS)//XMS表示需要延遲的毫秒數

無符號intx,y;

For(x=XMS;X0;X-)

For(y=110;Y」0;Y-);

使用:

VoidDelay10us(ucharMs)

Uchar數據我;

(;女士「0;------Ms)

對於(I = 26)我> 0;我-);

I=[(延遲值-1.75)*12/ms-15]/4

❺ 怎麼用C語言做單片機的精確延時

在單片機應用中,經常會遇到需要短時間延時的情況,一般都是幾十到幾百μs,並且需要很高的精度(比如用單片機驅動DS18B20時,誤差容許的范圍在十幾μs以內,不然很容易出錯);而某些情況下延時時間較長,用計時器往往有點小題大做。另外在特殊情況下,計時器甚至已經全部用於其他方面的定時處理,此時就只能使用軟體定時了[1]。
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工具的模擬功能,調整延遲量,從而得到較理想的結果。

❻ 單片機c語言帶參數延時怎麼寫

在循環里判斷是否滿足跳出的條件,滿足則跳出循環,不滿足就繼續延時直到延時結束。
具體的條件要有程序的要求來,比如說某個io口的電平的狀態。
sbit
state=p1^7;
delay(uint)
{
uint
x,y;
for(x=1000;x>0;x--)
for(y=1200;y>0;y--)
{
if(state==1)
return
;//當p1.7口為高時跳出循環
}
}
//由於加入了一條語句,延時要重新計算

❼ 單片機c語言的延時程序500ms

一般單片機在c語言中很難得到精確的延時,所以一般對時間要求高的都用計時器中斷來做了。如果時間要求不嚴格可以用for循環來做,你可以實際測試一下,把時間延時到大概一秒左右,然後燒進單片機里運行,比如一個燈亮燈滅的程序,看著燈計數,同時用秒錶計時,幾個幾十次後取平均值就能知道大概時間了。

❽ 51單片機用c語言怎麼寫延時函數

延時時間的計算與單片機的晶振頻率有關。若晶振頻率為12Mhz,那麼單片機每震動一次所需要的時間是1/12M s。那麼再來看看單片機執行一次自減所需要的振動次數是96次,假如我們對時間要求不是特別精確的話,可以約等於100來計算。現在通過上面兩個數據可以得出:單片機每執行一次自減所需要的時間是1/12M *100(s),即1/120000 s,逆向計算一下,每1ms需要自減多少次?120次對吧。所以一個簡單的延時功能就誕生了,我們只需要自減120次,就可以延時1ms,如果我們要延時50ms呢,那就自減50*120=6000次。那麼在程序上如何表達呢?我們可以用兩套for循環
void delay(int i){
int x,y;
for(x=i;x>0;x--){
for(y=120;y>0;y--)
}
}
參數 i 代表該函數延時多少ms

閱讀全文

與單片機c語言延時相關的資料

熱點內容
dd命令u盤 瀏覽:568
單片機生日快樂程序 瀏覽:891
安卓手機連車載的叫什麼 瀏覽:223
怎麼讓自己的手機鍵盤變得好看app 瀏覽:53
能看qq的文件夾 瀏覽:515
android二維碼生成代碼 瀏覽:567
焦爐氣壓縮機 瀏覽:402
imap接收郵件伺服器地址 瀏覽:291
小喬肖恩解壓密碼 瀏覽:645
php網頁網盤源碼 瀏覽:181
簽到任務源碼 瀏覽:814
母親節的文案怎麼寫app 瀏覽:984
加密協議aes找不到 瀏覽:250
java伺服器端開發源碼 瀏覽:551
編譯器編譯運行快捷鍵 瀏覽:333
住房app怎麼快速選房 瀏覽:174
怎麼在電腦上編譯成功 瀏覽:214
單片機可調時鍾設計方案 瀏覽:193
qq文件夾密碼忘記怎麼找回 瀏覽:683
php擴展插件 瀏覽:610