新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > STC單片機timer2捕獲模式測頻率

STC單片機timer2捕獲模式測頻率

作者: 時間:2016-11-19 來源:網絡 收藏

在使用STC單片機測頻率最常用的方法是在一定時間內計算脈沖個數,這種方式一般需要一個計數器和一個定時器配合,而且對低頻信號也不太準確,下面我們可以用到timer2捕獲模式通過測量兩個下降沿的時間,來計算頻率,這樣做僅使用timer2就好了,而且對低頻信號測量準確,經實際測試,在100Hz一下時,精度可達0.05Hz。

本文引用地址:http://butianyuan.cn/article/201611/318508.htm

下面先介紹一下STC51 timer2的捕獲模式:

在捕獲模式中,通過T2CON中的EXEN2設置兩個選項,如果EXEN2=0,定時器作為一個16位的定時器或計數器,溢出時置位TF2。該位可用于產生中斷(ET2=1)。如果EXEN2=1,就增加了一個特性,即外部輸入T2EX(P11)有下降沿時,將timer2中的TH2和TL2當前值各自捕獲到RCAP2L和RCAP2H。另外,T2EX的負跳變使T2CON中的EXF2置位,EXF2也想TF2一樣來產生中斷(其向量與timer2溢出中斷相同,timer2的中斷服務通過查詢TF2和EXF2來確定引起的中斷事件),若是T2EX中斷,進來后TH2和TL2不會重新裝載值,會繼續(xù)以當前計數往上計數,除非你確實想改變TH2和TL2的值,如需要重新計數。


下面介紹下程序:

因為外部跳變和溢出均可以進入中斷,我們可以利用這一特性來做對兩個脈沖之間的時間測量,初始時設置TH2和TL2值為0,如果發(fā)生溢出中斷,我們的計時變量就自加65536,如果進入外部跳變中斷,則我們讀取RCAP2L和RCAP2H的值并與前面的計時變量相加即可得到這個跳變與上一跳變的時間,注意測量結束后要清空計時變量以及H2和TL2,方便下一次的重新計數。

初始化程序如下:

//定時器2設置為捕獲模式,用戶計算速度void Timer2Init(){char i;EXEN2 = 1;//timer2 outside enableCP_RL2 = 1;//enable capture modeTH2 = TL2 = 0;RCAP2H = RCAP2L = 0;TR2 = 1;//enable timer2ET2=1; //enable timer2 interrupt//將計時器存儲區(qū)設置的很大,也就是頻率先接近0 for(i=0;i<5;i++){plus_length[i] = 6553600;}}
中斷服務程序如下,在這里keil對long型的數據計算有點問題,需要格外注意:

/** 函 數 名 :Timer2Int* 函數功能 :定時器2中斷函數 , 捕獲模式* 輸    入 :無* 輸    出 :無 */void Timer2Int() interrupt 5{static volatile long plus_length_temp=0;static char index=0;if(TF2 == 1)//overflow int{TF2 = 0;TH2 = 0;TL2 = 0;RCAP2H = 0;RCAP2L = 0;plus_length_temp = plus_length_temp + 65536;if(plus_length_temp > 6553600) {plus_length[index] = plus_length_temp;//對最近5個求平均值index++;if(index == 5) index = 0;plus_length_temp = 0;}}if(EXF2 == 1)//capture int{long temp;TH2 = 0;TL2 = 0;//WTF!!!  clear TH2 and TL2,not TH0 and TH1EXF2 = 0;temp = ((long)(RCAP2H<<8) + RCAP2L) & 0xffff; //奇怪的問題,如果不加0xffff,temp高位會全為ff,從而產生負數RCAP2H = 0;RCAP2L = 0;temp = plus_length_temp + temp;//在對long計算時要小心,一步一來plus_length_temp = temp;plus_length[index] = plus_length_temp;//對最近5個求平均值index++;if(index == 5) index = 0;plus_length_temp = 0;//read calc next plus}}

最后就是主函數部分內容,每隔500ms求平均值并打印一次當前頻率:

calc_plength = 0;Delayms(500);for(count = 0;count<5;count++){calc_plength += plus_length[count];}calc_plength = calc_plength/5;freq = (float)3990000/calc_plength;//read real frequenceprintf("freq=%frn",freq);

這種方法對低頻情況下比較有效,但頻率較高時如達到上k的頻率,誤差比較大,有明顯的偏高,至于原因,還等待進一步研究。


評論


技術專區(qū)

關閉