1. 程式人生 > >51微控制器的定時中斷(三)

51微控制器的定時中斷(三)

前言:微控制器的中斷系統(一)

圖片和內容來自普中科技的ppt。


相關知識:

週期:

振盪週期:為微控制器提供定時訊號的振盪源的週期(晶振週期或外加振盪週期)

狀態週期:2個振盪週期為1個狀態週期,用S表示。振盪週期又稱S週期或時鐘週期。

機器週期:1個機器週期含6個狀態週期,12個振盪週期。

指令週期:完成1條指令所佔用的全部時間,它以機器週期為單位。

(1M=1000000,所以在晶振頻率為12MHZ時,一個機器週期=1/12M=1us)

  (指令週期的長短不一,如果不知道一些指令週期的長度,即使定時中斷,也不能理論上絕對準確的中斷。因為函式的呼叫等也需    要時間)(這目前我還不會,但是感覺應該可以更精確延時,因為可以在計時中剪掉相應的操作時間)

IT0/IT1:

51微控制器有兩組定時器/計數器IT0/IT1,因為既可以定時又可以計數,故稱之為定時器/計數器。

定時器/計數器和微控制器的CPU是相互獨立的。定時器/計數器工作的過程是自動完成的,不需要CPU的參與。

51微控制器中的定時器/計數器是根據機器內部的時鐘或者是外部的脈衝訊號對暫存器中的資料加1。

有了定時器/計數器之後,可以增加微控制器的效率,一些簡單的重複加1的工作可以交給定時器/計數器處理。CPU轉而處理一些複雜的事情。同時可以實現精確定時作用。

 

定時/計數器的工作原理

定時/計數器實質上是一個加1計數器。它隨著計數器的輸入脈衝進行自加1,也就是每來一個脈衝,計數器就自動加1,,當加到計數器為全1時,再輸入一個脈衝就使計數器回零,且計數器的溢位使相應的中斷標誌位置1,向CPU發出中斷請求(定時/計數器中斷允許時)。如果定時/計數器工作於定時模式,則表示定時時間已到;如果工作於計數模式,則表示計數值已滿。

 

51微控制器定時/計數器結構

定時/計數器的實質是加1計數器(16位),由高8位和低8位兩個暫存器THx和TLx組成。TMOD是定時/計數器的工作方式暫存器,確定工作方式和功能;TCON是控制暫存器,控制T0、T1的啟動和停止及設定溢位標誌。

圖一:定時計數器結構

 

定時/計數器的控制

51微控制器定時/計數器的工作由兩個特殊功能暫存器控制。TMOD用於設定其工作方式;TCON用於控制其啟動和中斷申請。

工作方式暫存器TMOD

圖二:TMOD

1、高四位用來控制T1,低四位用來控制T0

2、GATE是門控位。GATE=0時,用於控制定時器的啟動不受外部中斷源訊號的影響。只要用軟體使TCON中的TR0或TR1為1,就可以啟動定時/計數器工作;GATA=1時,要用軟體使TR0或TR1為1,同時外部中斷引腳INT0/1也為高電平時,才能啟動定時/計數器工作。即此時定時器的啟動條件,加上了INT0/1引腳為高電平這一條件。

3、C/T :定時/計數模式選擇位。C/T =0為定時模式;C/T =1為計數模式。(T上有個非)

4、M1M0:工作方式設定位。定時/計數器有四種工作方式。(8位自動重灌,指的是將初始化值裝在高位,然後賦值給低位。低位進行計數或計溢位後,高位的數重新賦值給低位,重複)

圖三

 

控制暫存器TCON

制定時/計數器的啟動和中斷申請。其格式如下:

圖四

TF1(TCON.7):T1溢位中斷請求標誌位。T1計數溢位時由硬體自動置TF1為1。CPU響應中斷後TF1由硬體自動清0。T1工作時,CPU可隨時查詢TF1的狀態。所以,TF1可用作查詢測試的標誌。TF1也可以用軟體置1或清0,同硬體置1或清0的效果一樣。

TR1(TCON.6):T1執行控制位。TR1置1時,T1開始工作;TR1置0時,T1停止工作。TR1由軟體置1或清0。所以,用軟體可控制定時/計數器的啟動與停止。

TF0(TCON.5):T0溢位中斷請求標誌位,其功能與TF1類同。

TR0(TCON.4):T0執行控制位,其功能與TR1類同。

 

定時/計數器的工作方式

這裡僅僅提及方式一(我目前只用過這兩種)

方式1的計數位數是16位,由TL0作為低8位,TH0作為高8位,組成了16位加1計數器 。

        計數個數與計數初值的關係為:X=216-N

圖五

 

 

 

定時器的使用

對TMOD賦值,以確定T0和T1的工作方式。

計算初值,並將其寫入TH0、TL0或TH1、TL1。

中斷方式時,則對EA,ET0/1賦值,開放定時器中斷。

使TR0或TR1置位,啟動定時/計數器定時或計數。(這個最後設定,因為一旦設定,計時或計數就開始)

 

程式碼:

定時器0

#include<reg52.h>

sbit led=P2^0;//LED接在P2^0引腳上

int i=0;

void Timer0Init()
{
	TMOD|=0X01;//這樣寫是非常好的,僅僅設定定時器0,不影響定時器1的工作狀態。在多檔案程式設計中,這一點能更好的體現
	TH0=(65536-1000)/256;
   	TL0=(65536-1000)%256;
	//TH0=0xFC;//晶振頻率為12M
	//TL0=0X18;
	TH0=0xFC;//我板子上晶振頻率為11.05926M
	TL0=0X66;//這差別很小的
	ET0=1;//定時器0的中斷允許
	EA=1;//開啟總終端
	TR0=1;
}

void main(void)
{
	Timer0Init();
	while(1);			
}

void Timer0() interrupt 1//儘量減少中斷中的操作,提高精度
{
   i++;
   TH0=0xFC;//重新賦初值
   TL0=0X66;
   if(i==1000)
   {
   		led=~led;
		i=0;
   }
}


1、TMOD|=0X01;//這樣寫是非常好的,僅僅設定定時器0,不影響定時器1的工作狀態。在多檔案程式設計中,這一點能更好的體現

2、儘量減少定時中斷中的操作,提高精度。

3、這個定時中斷是1ms,中斷中的操作應該是不到1000的1/10,所以這個中斷在ms級別中,可能還是相對準確的。可以用於以後的實驗。但是在s級別誤差逐漸變大,下面是我簡單測量的方法和結果。

測量:

在燈滅下的瞬間,手機開始計時。如果要測10s,在第五次燈滅的時候結束計時。(因為點亮和熄滅各一秒)

下面用上述方法測量了10s,30s,50,70s,各三次。結果如下

1ms延時的測量
  10s 30s 50s 70s
第一次測量(s) 09.77 28.08 46.48 65.98
第二次測量(s) 09.38 28.15 46.44 65.88
第三次測量(s) 09.46 28.08 47.18 65.53
實際平均時間(s) 09.536 28.103 46.700 65.797

 上表可見,誤差越來越大。當然也可能我的晶振不是11.0592MHz,上面沒標註,問的淘寶客服。

好奇萬年曆是怎麼做出來的,回頭好好查查。

 

定時器1(普中科技的程式碼)

/**************************************************************************************
*		              定時器1實驗												  *
實現現象:下載程式後數碼管最後一位間隔一秒迴圈顯示0-F。使用微控制器內部定時器可以實現準確延時。
注意事項:如果不想讓點陣模組顯示,可以將74HC595模組上的JP595短接片拔掉。																				  
***************************************************************************************/

#include "reg52.h"			 //此檔案中定義了微控制器的一些特殊功能暫存器

typedef unsigned int u16;	  //對資料型別進行宣告定義
typedef unsigned char u8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//顯示0~F的值
u8 n=0;
/*******************************************************************************
* 函 數 名         : Timer1Init
* 函式功能		   : 定時器1初始化
* 輸    入         : 無
* 輸    出         : 無
*******************************************************************************/
void Timer1Init()
{
	TMOD|=0X10;//選擇為定時器1模式,工作方式1,僅用TR1開啟啟動。

	TH1=0XFC;	//給定時器賦初值,定時1ms
	TL1=0X18;	
	ET1=1;//開啟定時器1中斷允許
	EA=1;//開啟總中斷
	TR1=1;//開啟定時器			
}

/*******************************************************************************
* 函 數 名       : main
* 函式功能		 : 主函式
* 輸    入       : 無
* 輸    出    	 : 無
*******************************************************************************/
void main()
{	
	LSA=0;
	LSB=0;
	LSC=0;
	Timer1Init();  //定時器1初始化
	while(1);		
}

/*******************************************************************************
* 函 數 名         : void Timer1() interrupt 3
* 函式功能		   : 定時器0中斷函式
* 輸    入         : 無
* 輸    出         : 無
*******************************************************************************/
void Timer1() interrupt 3
{
	static u16 i;
	TH1=0XFC;	//給定時器賦初值,定時1ms
	TL1=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		P0=smgduan[n++];
		if(n==16)n=0;	
	}	
}

在定時中斷函式中,為了不斷定時,進行了重灌載(重新賦值)。當溢位的時候ET0置一,中斷標誌。

TR0=1,為開啟計時器;ET0=1是開啟定時器1中斷允許。我咋感覺這兩個有點重複呢?

 

補充:

來自百度百科:晶體振盪器

        石英晶體振盪器是高精度和高穩定度的振盪器,被廣泛應用於彩電、計算機、遙控器等各類振盪電路中,以及通訊系統中用於頻率發生器、為資料處理裝置產生時鐘訊號和為特定系統提供基準訊號。

        石英晶體振盪器是利用石英晶體(二氧化矽的結晶體)的壓電效應制成的一種諧振器件,它的基本構成大致是:從一塊石英晶體上按一定方位角切下薄片(簡稱為晶片,它可以是正方形、矩形或圓形等),在它的兩個對應面上塗敷銀層作為電極,在每個電極上各焊一根引線接到管腳上,再加上封裝外殼就構成了石英晶體諧振器,簡稱為石英晶體或晶體、晶振。其產品一般用金屬外殼封裝,也有用玻璃殼、陶瓷或塑料封裝的