溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

發(fā)布時(shí)間:2020-07-17 15:26:53 來(lái)源:網(wǎng)絡(luò) 閱讀:5452 作者:行飛子 欄目:開(kāi)發(fā)技術(shù)

單片機(jī)因具有體積小、功能強(qiáng)、成本低以及便于實(shí)現(xiàn)分布式控制而有非常廣泛的應(yīng)用領(lǐng)域。單片機(jī)開(kāi)發(fā)者在編制各種應(yīng)用程序時(shí)經(jīng)常會(huì)遇到實(shí)現(xiàn)精確延時(shí)的問(wèn)題,比如按鍵去抖、數(shù)據(jù)傳輸?shù)炔僮鞫家诔绦蛑胁迦胍欢位驇锥窝訒r(shí),時(shí)間從幾十微秒到幾秒。有時(shí)還要求有很高的精度,如使用單總線芯片DS18B20時(shí),允許誤差范圍在十幾微秒以?xún)?nèi),否則,芯片無(wú)法工作。為此我特意的將如何在C51程序中精確延時(shí)進(jìn)行了一個(gè)小結(jié)。

用51匯編語(yǔ)言寫(xiě)程序時(shí),這種問(wèn)題很容易得到解決,而目前開(kāi)發(fā)嵌入式系統(tǒng)軟件的主流工具為C語(yǔ)言,因此很有必要了解用C51寫(xiě)延時(shí)程序時(shí)需要的一些技巧。

實(shí)現(xiàn)延時(shí)通常有兩種方法

? 一種是硬件延時(shí),要用到定時(shí)器/計(jì)數(shù)器,這種方法可以提高CPU的工作效率,也能做到精確延時(shí);

? 一種是軟件延時(shí),這種方法主要采用循環(huán)體進(jìn)行。

?1 使用定時(shí)器/計(jì)數(shù)器實(shí)現(xiàn)精確延時(shí)

單片機(jī)系統(tǒng)一般常選用11.059 2 MHz、12 MHz或6 MHz晶振。第一種更容易產(chǎn)生各種標(biāo)準(zhǔn)的波特率,后兩種的一個(gè)機(jī)器周期分別為1 μs和2 μs,便于精確延時(shí)。假設(shè)使用頻率為12 MHz的晶振。最長(zhǎng)的延時(shí)時(shí)間可達(dá)2^16=65 536 μs。若定時(shí)器工作在方式2,則可實(shí)現(xiàn)極短時(shí)間的精確延時(shí);如使用其他定時(shí)方式,則要考慮重裝定時(shí)初值的時(shí)間(重裝定時(shí)器初值占用2個(gè)機(jī)器周期)。

? 在實(shí)際應(yīng)用中,定時(shí)常采用中斷方式,如進(jìn)行適當(dāng)?shù)难h(huán)可實(shí)現(xiàn)幾秒甚至更長(zhǎng)時(shí)間的延時(shí)。使用定時(shí)器/計(jì)數(shù)器延時(shí)從程序的執(zhí)行效率和穩(wěn)定性?xún)煞矫婵紤]都是最佳的方案。但應(yīng)該注意,C51編寫(xiě)的中斷服務(wù)程序編譯后會(huì)自動(dòng)加上PUSH ACC、PUSH PSW、POP PSW和POP ACC語(yǔ)句,執(zhí)行時(shí)占用了4個(gè)機(jī)器周期;如程序中還有計(jì)數(shù)值加1語(yǔ)句,則又會(huì)占用1個(gè)機(jī)器周期。這些語(yǔ)句所消耗的時(shí)間在計(jì)算定時(shí)初值時(shí)要考慮進(jìn)去,從初值中減去以達(dá)到最小誤差的目的。


?2 軟件延時(shí)與時(shí)間計(jì)算

  在很多情況下,定時(shí)器/計(jì)數(shù)器經(jīng)常被用作其他用途,這時(shí)候就只能用軟件方法延時(shí)。下面介紹幾種軟件延時(shí)的方法。


?2.1 短暫延時(shí)

?可以在C文件中通過(guò)使用帶_NOP_( )語(yǔ)句的函數(shù)實(shí)現(xiàn),定義一系列不同的延時(shí)函數(shù),如Delay10us( )、Delay25us( )、Delay40us( )等存放在一個(gè)自定義的C文件中,需要時(shí)在主程序中直接調(diào)用。如延時(shí)10 μs的延時(shí)函數(shù)可編寫(xiě)如下:

void Delay_10us()

{

?_NOP();

?_NOP();

?_NOP();

?_NOP();

?_NOP();

?_NOP();

}

?Delay_10us( )函數(shù)中共用了6個(gè)_NOP_( )語(yǔ)句,每個(gè)語(yǔ)句執(zhí)行時(shí)間為1 μs。主函數(shù)調(diào)用Delay_10us( )時(shí),先執(zhí)行一個(gè)LCALL指令(2 μs),然后執(zhí)行6個(gè)_NOP_( )語(yǔ)句(6 μs),最后執(zhí)行了一個(gè)RET指令(2 μs),所以執(zhí)行上述函數(shù)時(shí)共需要10 μs。

 可以把這一函數(shù)當(dāng)作基本延時(shí)函數(shù),在其他函數(shù)中調(diào)用,即嵌套調(diào)用延時(shí)函數(shù),以實(shí)現(xiàn)較長(zhǎng)時(shí)間的延時(shí);但需要注意,如在Delay40us( )中直接調(diào)用4次Delay10us( )函數(shù),得到的延時(shí)時(shí)間將是42 μs,而不是40 μs。這是因?yàn)閳?zhí)行Delay40us( )時(shí),先執(zhí)行了一次LCALL指令(2 μs),然后開(kāi)始執(zhí)行第一個(gè)Delay10us( ),執(zhí)行完最后一個(gè)Delay10us( )時(shí),直接返回到主程序。依此類(lèi)推,如果是兩層嵌套調(diào)用,如在Delay80us( )中兩次調(diào)用Delay40us( ),則也要先執(zhí)行一次LCALL指令(2 μs),然后執(zhí)行兩次Delay40us( )函數(shù)(84 μs),所以,實(shí)際延時(shí)時(shí)間為86 μs。簡(jiǎn)言之,只有最內(nèi)層的函數(shù)執(zhí)行RET指令。該指令直接返回到上級(jí)函數(shù)或主函數(shù)。如在Delay80μs( )中直接調(diào)用8次Delay10us( ),此時(shí)的延時(shí)時(shí)間為82 μs。通過(guò)修改基本延時(shí)函數(shù)和適當(dāng)?shù)慕M合調(diào)用,上述方法可以實(shí)現(xiàn)不同時(shí)間的延時(shí)。

對(duì)于_NOP()函數(shù),相信有不少人會(huì)感到疑惑,這里我就詳細(xì)的介紹一下_NOP();函數(shù):

_NOP();函數(shù)是用來(lái)產(chǎn)生空指令來(lái)進(jìn)行延時(shí)的,在匯編語(yǔ)言中寫(xiě)幾個(gè)nop指令就可以達(dá)到延時(shí)的效果。


注意:


1、 調(diào)用庫(kù)函數(shù)是一定要包含頭文件#include<intrins.h>,在該庫(kù)中聲明了void _NOP(void);


2、 這個(gè)函數(shù)相當(dāng)匯編NOP指令,延時(shí)幾微秒。NOP指令為單周期指令,可由晶振頻率算出延時(shí)時(shí)間,對(duì)于12M晶振,延時(shí)1uS。



關(guān)于C51的延時(shí)函數(shù)要注意:


求在大于10us,采用C51中的循環(huán)語(yǔ)句來(lái)實(shí)現(xiàn)。
在選擇C51中循環(huán)語(yǔ)句時(shí),要注意以下幾個(gè)問(wèn)題
第一、定義的C51中循環(huán)變量,盡量采用無(wú)符號(hào)字符型變量。
第二、在FOR循環(huán)語(yǔ)句中,盡量采用變量減減來(lái)做循環(huán)。
第三、在do…while,while語(yǔ)句中,循環(huán)體內(nèi)變量也采用減減方法。
這因?yàn)樵贑51編譯器中,對(duì)不同的循環(huán)方法,采用不同的指令來(lái)完成的。


下面舉例說(shuō)明:
unsigned char i;
for(i=0;i<255;i++);

unsigned char i;
for(i=255;i>0;i--);
其中,第二個(gè)循環(huán)語(yǔ)句C51編譯后,就用DJNZ指令來(lái)完成,相當(dāng)于如下指令:
MOV 09H,#0FFH
LOOP: ? ? DJNZ 09H,LOOP
指令相當(dāng)簡(jiǎn)潔,也很好計(jì)算精確的延時(shí)時(shí)間。


既然能用高級(jí)語(yǔ)言進(jìn)行延時(shí),當(dāng)然也能用最基本的匯編語(yǔ)言進(jìn)行相關(guān)的延時(shí),下面我們來(lái)簡(jiǎn)單的了解下(注:對(duì)于匯編語(yǔ)言我也只略懂一點(diǎn),這是我在網(wǎng)上相關(guān)的資料學(xué)習(xí)到的):

? 在C51中通過(guò)預(yù)處理指令#pragma asm和#pragma endasm可以嵌套匯編語(yǔ)言語(yǔ)句。用戶(hù)編寫(xiě)的匯編語(yǔ)言緊跟在#pragma asm之后,在#pragma endasm之前結(jié)束。

如: ?#pragma asm
    …
    匯編語(yǔ)言程序段
    …
    #pragma endasm

? 延時(shí)函數(shù)可設(shè)置入口參數(shù),可將參數(shù)定義為unsigned char、int或long型。根據(jù)參數(shù)與返回值的傳遞規(guī)則,這時(shí)參數(shù)和函數(shù)返回值位于R7、R7R6、R7R6R5中。在應(yīng)用時(shí)應(yīng)注意以下幾點(diǎn): ?

?◆ #pragma asm、#pragma endasm不允許嵌套使用;
  ◆ 在程序的開(kāi)頭應(yīng)加上預(yù)處理指令#pragma asm,在該指令之前只能有注釋或其他預(yù)處理指令;

?◆ 當(dāng)使用asm語(yǔ)句時(shí),編譯系統(tǒng)并不輸出目標(biāo)模塊,而只輸出匯編源文件;

  ◆ asm只能用小寫(xiě)字母,如果把a(bǔ)sm寫(xiě)成大寫(xiě),編譯系統(tǒng)就把它作為普通變量;
  ◆ #pragma asm、#pragma endasm和 asm只能在函數(shù)內(nèi)使用。

2.3 使用示波器確定延時(shí)時(shí)間

?熟悉硬件的開(kāi)發(fā)人員,也可以利用示波器來(lái)測(cè)定延時(shí)程序執(zhí)行時(shí)間。方法如下:編寫(xiě)一個(gè)實(shí)現(xiàn)延時(shí)的函數(shù),在該函數(shù)的開(kāi)始置某個(gè)I/O口線如P1.0為高電平,在函數(shù)的最后清P1.0為低電平。在主程序中循環(huán)調(diào)用該延時(shí)函數(shù),通過(guò)示波器測(cè)量P1.0引腳上的高電平時(shí)間即可確定延時(shí)函數(shù)的執(zhí)行時(shí)間。(有條件的哥們可以試試)


2.4 使用Keil_C中的性能分析器計(jì)算延時(shí)時(shí)間:

這里我就詳細(xì)介紹下,這是很實(shí)用的方法:

我們先在Keil_C中敲入如下代碼:

#include<reg52.h>


#define uint unsigned int


sbit led=P1^0;



main()


{

?uint i,j,x,y,k,n,m;


?while(1)


?{


? ?led=0;


? ?for(i=1000;i>0;i--)//延時(shí)1


? ? ?for(j=110;j>0;j--);


? ? ?led=1;



? ?for(x=0;x<500;x++)//延時(shí)2


? ? ?for(y=0;y<130;y++);


? ? ?led=0;



? ?for(n=500;n>0;n--)//延時(shí)3


? ? ?for(m=114;m>0;m--);


? ? ?led=1;



? ? ?k=90;//延時(shí)4


? ? ?while(k>0)k--;


? ? ?led=0;


? }


}



下面將介紹如何建立Keil工程,并分析延時(shí)時(shí)間的精確計(jì)算方法,利用keil可以比較方便、精確的計(jì)算程序延時(shí)時(shí)間。


1. 建立keil工程。


啟動(dòng)keil,選擇“ProjectàNew uVision Projectà輸入工程名稱(chēng),確定,彈出下面對(duì)話框,選擇Atmel


在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

接著選擇:AT89C52

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

選擇好芯片之后會(huì)彈出下面的對(duì)話框,選擇“否”:

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

點(diǎn)擊“FileàNew”,新建一個(gè)Text,用以輸入程序。程序輸入以后保存,保存名稱(chēng)需要和工程名稱(chēng)一致,如果使用C語(yǔ)言則以.c作為保存格式,使用匯編語(yǔ)言保存格式為.asm。保存之后如圖:

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

下一步就是把剛才保存的.c程序?qū)氲焦こ讨小_x中上圖中左上角的“Source Group 1”,單擊右鍵,選擇“Add Files to Group 'Source Group 1'..”,在彈出的對(duì)話框選擇剛才保存的.c文件,Add,即完成導(dǎo)入。

下面這一步設(shè)置對(duì)于使用keil精確計(jì)算延時(shí)時(shí)間很關(guān)鍵。選中下圖左上角的Target 1

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

單擊右鍵,選擇“Options for Target 'Target 1'..”,彈出下面對(duì)話框,把XtalMhz)的24.0修改成當(dāng)前使用的晶振頻率,這里改為11.0592Mhz。

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

如果還要生成.hex文件用于下載到芯片上,可以選擇“Output”,鉤選“Creat HEX File”選項(xiàng),如下:

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

這樣就建立好了一個(gè)keil工程。通過(guò)程序調(diào)試,“Save”,“Build”,生成.hex文件,下載到芯片就可以直接使用了。

1. 接著講第二個(gè)知識(shí)點(diǎn),就是如何精確計(jì)算延時(shí)的時(shí)間。


我們選擇開(kāi)頭給出的程序?yàn)槔?,延時(shí)1的程序如下:


for(i=1000;i>0;i--)//延時(shí)1


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


要精確計(jì)算它的延時(shí)時(shí)間,可以通過(guò)設(shè)置斷點(diǎn)來(lái)實(shí)現(xiàn)。斷點(diǎn)設(shè)置如下圖:


在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

在延時(shí)1的開(kāi)頭和下一句語(yǔ)句的開(kāi)頭分別設(shè)置斷點(diǎn)A1A2,然后全速運(yùn)行,運(yùn)行到A1處,程序停止,記錄這時(shí)的運(yùn)行時(shí)間t1,繼續(xù)全速運(yùn)行,遇到斷點(diǎn)A2,程序停止,記錄此刻的時(shí)間t2。那么延時(shí)1的延時(shí)時(shí)間就是t=t2-t1。

下面是具體步驟:

(1) 設(shè)置斷點(diǎn)。如上圖所示,在程序開(kāi)頭的數(shù)字處雙擊左鍵,就會(huì)出現(xiàn)一個(gè)紅色的點(diǎn),這就是斷點(diǎn)。如果要消去斷點(diǎn),同樣可以雙擊斷點(diǎn)。


(2) 進(jìn)入調(diào)試模式。單擊窗口上的調(diào)試按鍵快捷圖標(biāo):


在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

即可進(jìn)入調(diào)試模式。初次進(jìn)入調(diào)試模式的界面如下:

在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

首先介紹一下幾個(gè)重要按鈕。如下圖所示:


紅色數(shù)字1上面的圖標(biāo):將程序復(fù)位到主函數(shù)的最開(kāi)開(kāi)始處,準(zhǔn)備重新運(yùn)行程序;


紅色數(shù)字2上面的圖標(biāo):全速運(yùn)行,運(yùn)行程序時(shí)中間不停止,直到遇到斷點(diǎn);


紅色數(shù)字3上面的圖標(biāo):停止全速運(yùn)行。


紅色數(shù)字4上面的圖標(biāo):進(jìn)入子函數(shù)內(nèi)部。


紅色下劃線上的sec就是程序從開(kāi)始運(yùn)行到當(dāng)前停止處所用的時(shí)間。


在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹


(3) 先復(fù)位。即點(diǎn)擊上圖中紅字1上面的圖標(biāo)。


(4) 全速運(yùn)行,記錄運(yùn)行時(shí)間。即點(diǎn)擊上圖紅字2上面的圖標(biāo)。遇到09處的第一個(gè)斷點(diǎn),系統(tǒng)會(huì)自動(dòng)停止運(yùn)行,停在第一個(gè)斷點(diǎn)處。此時(shí)右邊記錄的時(shí)間sec就是程序從開(kāi)始運(yùn)行到當(dāng)前斷點(diǎn)處所經(jīng)歷的時(shí)間為t1=423.18us。如下圖所示:


在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

(5) 繼續(xù)全速運(yùn)行,第二次記錄運(yùn)行時(shí)間。遇到11處的第二個(gè)斷點(diǎn),系統(tǒng)停止運(yùn)行,此時(shí)已運(yùn)行時(shí)間為t2=966140.41us。如下圖所示:


在進(jìn)行C51程序設(shè)計(jì)時(shí)如何精確延時(shí)的常見(jiàn)方法介紹

(6) 計(jì)算延時(shí)時(shí)間t。從上面得到的數(shù)據(jù)可以計(jì)算出時(shí)間


t= t2-t1= 966140.41us- 423.18us= 965717.23us= 965.71723ms。


通過(guò)上面6個(gè)步驟,就可以精確,方便地計(jì)算出延時(shí)程序的時(shí)間,對(duì)于實(shí)現(xiàn)精確延時(shí),只需要調(diào)節(jié)參數(shù),再稍加計(jì)算就OK。需要注意的是,在上圖的調(diào)試模式下修改程序參數(shù),是無(wú)法生效的。復(fù)位之后全速運(yùn)行,顯示的十間仍然是修改之前的參數(shù)在起作用。所以如果修改程序參數(shù),需要到編輯模式下,重新下載,然后再進(jìn)入調(diào)試模式,才可以計(jì)算精確時(shí)間。同時(shí),在建立Keil工程的時(shí)候,一定要記得修改晶振的參數(shù),這很關(guān)鍵,如果晶振不對(duì),要實(shí)現(xiàn)相同的延時(shí)時(shí)間,程序參數(shù)的設(shè)置也就不一樣。


? ?可以使用同樣的方法計(jì)算延時(shí)2,延時(shí)3,延時(shí)4的精確延時(shí)時(shí)間。它們的延時(shí)時(shí)間分別是:498040.37us、500220.27us、783.42us。大家可以自己練習(xí)。


最后還要指出一點(diǎn)的是: ?

? ?上面使用的Keil版本是Keil uVision4,大家也可以使用Keil 3或者Keil 2來(lái)做,只是軟件的界面,圖標(biāo)等有差別,但都可以實(shí)現(xiàn)相同的功能。

















向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI