天天看點

單片機延時問題20問及解決方法

部落客福利:100G+電子設計學習資源包!

​​http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect​​ --------------------------------------------------------------------------------------------------------------------------

1、單片機延時程式的延時時間怎麼算的?

答:如果用循環語句實作的循環,沒法計算,但是可以通過軟體仿真看到具體時間,但是一般精精确延時是沒法用循環語句實作的。

如果想精确延時,一般需要用到定時器,延時時間與晶振有關系,單片機系統一般常選用11.059 2 MHz、12 MHz或6 MHz晶振。第一種更容易産生各種标準的波特率,後兩種的一個機器周期分别為1 μs和2 μs,便于精确延時。本程式中假設使用頻率為12 MHz的晶振。最長的延時時間可達216=65 536 μs。若定時器工作在方式2,則可實作極短時間的精确延時;如使用其他定時方式,則要考慮重裝定時初值的時間(重裝定時器初值占用2個機器周期)。

2、求個單片機89S51 12M晶振 用定時器延時10分鐘,控制1個燈就可以

答:可以設50ms中斷一次,定時初值,TH0=0x3c、TL0=0xb0。中斷20次為1S,10分鐘的話,需中斷12000次。計12000次後,給一IO口一個低電平(如功率不夠,可再加擴充),就可控制燈了。

而且還要看你用什麼語言計算了,彙編延時準确,知道單片機工作周期和循環次數即可算出,但不具有可移植性,在不同種類單片機中,彙編不通用。用c的話,由于各種軟體執行效率不一樣,不會太準,通常用定時器做延時或做一個不準确的延時,延時短的話,在c中使用彙編的nop做延時

3、51單片機C語言for循環延時程式時間計算 ,設晶振12MHz,即一個機器周期是1us。

for(i=0,i<100;i++)

for(j=0,j<100;j++)

我覺得時間是100*100*1us=10ms,怎麼會是100ms

答:

不可能的,是不是你的編譯有錯的啊

我改的晶振12M,在KEIL 4.0 裡面編譯的,為你得出的結果最大也就是40ms,這是軟體的原因,

不可能出現100ms那麼大的差距,是你的軟體的原因。

不信你實際編寫一個秒鐘,利用原理計算編寫一個燒進單片機和利用軟體測試的秒程式燒進單片機,你會發現原理計算的程式是正确的

4 、51單片機c語言 _nop_()是一個空指令?短時間延時的?空幾個機器周期?

答:這個_nop_()等效與彙編裡面的,NOP指令,也就是空一個機器周期,如果是傳統51單片機的話,等于空12個時鐘周期【即一個機器周期】

5、51單片機 延時500ms 用機器周期疊加怎麼算?

答:DELAY:

MOV R7,#4

D2:MOV R6,#250

D1:MOV R5,#250

DJNZ R5,$

DJNZ R6,D1

DJNZ R7,D2

RET

假設晶振為12MHz

剛延時時間為:

250*250*4*2=500MS

6、51單片機C語言程式中延時函數delay的原理是什麼?

現在找到兩個函數

第一:

void delay(void)

{ unsigned int i,j;

for(i=0;i<500;i++)

{ for(j=0;j<121;j++)

{;}

}

}

第二:

void delay(unsigned int k)

{ unsigned int i,j;

for(i=0;i<k;i++)

{ for(j=0;j<121;j++)

{;}

}

}

現有幾個疑問:

(1):延時函數的原理?

(2):兩個for循環的作用?

(3):i、j的取值有什麼規律和依據?是不是和單片機接的晶振頻率有關?所能延時的最小機關時間是怎麼計算的?

延時時間怎麼計算啊!假如用的是AT89C51RC+11.0592M的晶振呢?

答:

1:原理:僅僅執行一些,沒有實質性影響的所謂“無意義指令”,比如做比大小啊,做某個int的自加運算啊之類的

2:兩重for的作用:簡單的說,就像高中數學中的“乘法原理”一樣,這樣可以很輕易的迅速增加上述“無意義指令”的數目

3:關于取值大小:這個如果是在C下變成,這個值不僅僅與晶振、單片機本身運算速度有關,而且還與C的編譯器有關,是以說,這個值雖說是可以精确計算的,但大多數情況下,程式員用的都是“經驗值”——當然,如果用彙編程式設計,情況就不一樣了,因為每一條指令所使用的機器周期是一定的,你當然可以根據所有指令使用的總時間,精确的算出具體延時的總時間

綜合你的的問題,我給你一點建議,就是剛學單片機的時候,還是一定要老老實實的從彙編程式設計學起——這樣,在你以後接觸到C之後,你才能明白,這中間實際上經曆了一個什麼樣的過程,隻有這樣你才能真正了解單片機。當然,等最終你完全拿下一種單片機之後,盡量使用C程式設計,無疑是曆史所肯定的。

7、51單片機,晶振為6M,求一個10ms的延時程式

答:延時有很多種方法,有一種是讓單片機去做無聊的循環,還有一種是用定時器。

第一種的算法是:

晶振的周期T1=1/f; 這裡f=6MHz 是以T1=1/6 us;(微秒)

單片機花12個T1去執行一個指令,

是以一個機器周期等于12個晶振周期,

T2=12*T1=2us

10ms=1000 0us

是以你要得到10ms的延時就要想辦法讓機器去做5000條“無聊的指令”

是以

DEL: MOV R5,#05H

F1: MOV R6,#05H

F2: MOV R7,#32H

F3: DJNZ R7,F3

DJNZ R6,F2

DJNZ R5,F1

RET

這種方法是用于對時間要求不高的地方,我說的是其思想,程式中可能有錯的地方

用定時器的方法我不太會就不誤人了 (補充一下就是這個是用彙編寫的,你在主程式中用ACALL DEL調用就延時了。

8、今天我用單片機做“眨眼的LED”實驗時,程式運作,每次隻令燈亮或滅都沒問題,但是一開延時不能出現期盼的燈亮燈滅的現象,這是怎麼回事?

實驗的硬體條件是:STC89C52,編譯環境:keil 3。

下面是我寫的程式,請教高手!!!

#include <reg51.h> // 檔案包含處理
 #define uchar unsigned char //宏定義,友善以後程式的書寫
 #define uint unsigned int
 sbit P1_0 = P1 ^ 0; //位變量定義
 void Delay(uint t)
 {
 uchar i;
 while(--t)
 {
 for(i = 0; i < 125; i++) //延時1MS,在這裡我們用的晶振是是12M,根據機器周期的計算,我們
 {;} //可算得本次循環延時約1MS
 }
 }
 void main(void)
 {
 while(1)
 {
 P1_0 = 0; //點亮LED燈
 Delay(1000); //應單片執行程式的時間很快,是以必須延時,要不看不到實驗現象
 P1_0 = 1; //熄滅LED燈
 }      

補充提問:我是讓P1.0先低然後延時之後再高,即燈先亮再滅,然後開始循環的

答:應該這樣寫

while(1)

{

P1_0 = 0; //點亮LED燈

Delay(1000); //應單片執行程式的時間很快,是以必須延時,要不看不到實驗現象

P1_0 = 1; //熄滅LED燈

Delay(1000);

補充問題回複:問題恰恰就錯在這了,循環完一遍之後燈由滅到亮根本沒有時間延時,即第一次循環中燈還沒來的機滅呢,就進入到第二輪循環中的亮了,是以原因就在這,這錯誤太低級了,以後引以為鑒吧

9、單片機延時函數的問題

void delay(uchar i)

{

uchar j;

while(i--)

{

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

;

}

}

這個函數中的i,j的大小有**嗎?

答:這個函數中j的大小和你定義的資料類型有關,因為你定義的為無符号字元型,為單位元組資料,是以最大為255。.

如果你需要增大,可以改變j的資料類型定義,如unsigned int (2位元組)可以到65535;無符号長整形unsigned long(4位元組) 可以到4294967295。 而上面所所256是-1,而你定義的是無符号字元型。

10、請教一個AVR單片機延時的問題

外部晶振用的是8MHz,延時1微秒的程式如下:

void delay_us(unsigned int delay_counter)//延時1us
 {
 do
 {
 delay_counter--;
 }
 while(delay_counter>1);
 }      

請問,為什麼能延時1微秒啊?

答:8MHZ表示單片機的運作周期為1/8us,也就是0.125us執行一步

你使用的是軟體延時

那麼包括程式的提取,執行等都要花費時間

比如,你提取這個函數可能花去一步,那現在就使用了0.125us啦

接着你執行這個函數,在單片機内部,運算是通過寄存器的移來移去實作的

這都需要時間,可能你看到的就一句counter--這個指令,可能會花費好幾個時鐘周期來實作

舉個例子:

c=a+b,隻有一句,但實際上花費的時間并不短

mov a,#data1;//資料data1放入a寄存器

mov b,#data2;//資料data2放入b寄存器

add a,b;//寄存器a的值與b相加,結果放入a

mov c,a;//将a的值放入c

這樣才是單片機内部真正執行的指令,這需要花費至少4個時鐘周期,而不是1個

至于半導體級的我就不解釋了,你得好好學習彙編才能了解單片機的運作。

至于這個函數為什麼能延時1ms,這個是靠經驗來判斷的,最直接的方法就是用示波器看,以上均為推論。

11、PIC單片機的延時問題 晶振4Mhz:

void delay()
 {
 unsigned int d=1000;
 while(--d){;}
 }      

此函數在4M晶體下産生10003us的延時,也就是10MS。

問題:我剛算了一下他應該執行了999條指令,1條單周期的指令也才1US,那就是999us,為什麼會有10ms的延時?

1:for(x=100;--x;){;} : 2: for(x=0;x<100;x++){;} 2句話相同

第一句:X的值範圍是不是 1~99?為什麼?

第二句:X的範圍是不是0~99?為什麼?這麼算的。我知道符号在前在後的差別。2句話應該是不一樣的才對啊!

答:

問題1:“我剛算了一下他應該執行了999條指令”因為你算錯了。延時時間是由産生的彙編代碼所決定的,C語言語句隻是個假象,千萬不要以為C語言一行就是一條指令!此處由于涉及到雙位元組減法,是以會有額外的判斷,編譯結果每次循環耗費幾十個周期毫不奇怪。

問題2:前一句x從100開始遞減,遞減至1時退出循環。後一句x從0開始遞增,遞增到100時退出循環。所謂“2句話”相同僅僅是指這兩個循環體的循環次數相同。實際上兩個循環的執行過程是完全不同的,所消耗時間也有可能不同。

12、stc單片機的延時問題 ,STC10F08XE單片機,晶振22.1184M

void delay(unsigned long uldata)
 {
 unsigned int j = 0;
 unsigned int g = 0;
 for (j=0;j<5;j++)
 {
 for (g=0;g<uldata;g++)
 {
 _nop_();
 _nop_();
 _nop_();
 }
 }
 }      

當uldata=1時延時多少秒?

請給出具體算法…………

答:用keil轉換成彙編語句,然後對照指令表計算就行了

13、我想用單片機連接配接不斷地向電腦發數,如下:

while (1)
 {
 send_char('9');
 delay(n);
 }      

如每發送一個數,應延時多少微妙好呢?即一般最短能延時多少微米呢?如延時太長的話,那發送很多資料不就用很長時間嗎?

答:不做太多的序列槽處理分析,隻順着你的問題和你的方法說說:

先考慮下序列槽的速率 假設9600,那麼發送一個字元要多久?

(9600bit/S) / 10bit(一個字元1+8+1) = 960字元/秒 約 1ms/byte

也就是說你如果在1ms内發送超過一個字元就沒意義了,硬體速度達不到。

while(1)
 {
 send_char('9');
 delay(n);
 }      
void Delay(uint del)
 {
 uint i,j;
 for(i=0; i<del; i++)
 for(j=0; j<1827; j++) //這個是通過軟體仿真得出的數
 ;
 }      
{
 uchar bt;
 for(;dt;dt--);
 for(bt=0;bt<255;bt++);
 }      

繼續閱讀