MSP430G2553捕獲程序案例與經(jīng)驗分享
MSP430G2553單片機定時器A有3個捕獲比較寄存器CCR0,CCR1,CCR2.。MSP430G2553捕獲程序應用很廣泛,電子工程師可以多加了解。
本文引用地址:http://butianyuan.cn/article/201710/366352.htm所謂捕獲,就是我們來檢測外圍的信號跳變時刻(此時信號理解為數(shù)字信號,即脈沖),此信號乃為我們捕獲的對象,可以測量信號的脈沖寬度,即頻率等。
捕獲首先需要考慮的初始化工作
1.設置BCS模塊,確定系統(tǒng)時鐘MCLK子系統(tǒng)時鐘SMCLK
把MCLK設置為8MHZ,SMCLK設置為1MHZ。
2.捕獲輸入引腳的選擇
選擇IO引腳時應查閱器件的手冊,能夠快速的查閱PDF資料找到正確的答案是一個程序員的基本素質(zhì)。
3.程序設計思路
根據(jù)測頻的原理,需要2次捕獲才能測量一次輸入信號的頻率。因此要定義2個變量保存2次捕獲結(jié)果。變量是無符號的整數(shù)型變量(與捕獲寄存器的字長匹配)。
輸入信號與CPU的工作是異步的,所以設計程序的時候是不知道什么時候才有捕獲輸入。
程序處理何時發(fā)生了捕獲的方法有2種
一是查詢的方法,定時器硬件在發(fā)生捕獲事件后會置捕獲中斷表示CCIF為1,程序在主循環(huán)里不斷的查詢這個標志即可判斷是否有捕獲事件發(fā)生。
二是定時器中斷法,當發(fā)生捕獲事件時必產(chǎn)生定時器中斷,在中斷中讀取捕獲寄存器即可。
查詢的方法不是好的程序設計方法,因為查詢時要占用CPU,使得CPU不能再做其他任務。中斷的方法對初學者有一定的困難。即中斷程序如何與主程序通信(交換信息)。理解中斷及設計中斷服務程序要困難一些。
捕獲模式
捕獲外部輸入的信號的上升沿或下降沿或上升沿下降沿都捕捉,當捕捉發(fā)生時,把TAR的值裝載到TACCRx中,同時也可以進入中斷,執(zhí)行相應的操作。這樣利用捕捉上升沿或下降沿就可以計算外部輸入信號的周期,得出頻率。利用捕捉上升沿和下降沿可以得出輸入信號的高電平或低電平的持續(xù)時間。也可以算出占空比。下面是一個例子,是Timer_A捕獲初始化的程序:
void timer_init() //使用Timer1_A時要特別注意各個寄存器的寫法,因為Timer0_A的寄存器都簡寫了,所以在寫
//Timer1_A的寄存器時,要特別注意與Timer0_A的不同
{
P1SEL |= BIT2; //選擇P12作為捕捉的輸入端子 Timer0_A
//TACCTL1 |=CM_3+SCS+CAP+CCIE; //上下沿都觸發(fā)捕捉,用于測脈寬,同步模式、時能中斷 CCI1A
TACCTL1 |=CM_1+SCS+CAP+CCIE; //上升沿觸發(fā)捕捉,同步模式、時能中斷 CCI1A
TACTL |= TASSEL1+MC_2; //選擇SMCLK時鐘作為計數(shù)時鐘源,不分頻 增計數(shù)模式不行,必須連續(xù)計數(shù)模式
P2SEL |= BIT1; //選擇P21作為捕捉的輸入端子 Timer1_A
//TA1CCTL1 |=CM_3+SCS+CAP+CCIE; //上下沿都觸發(fā)捕捉,用于測脈寬,同步模式、時能中斷 CCI1A
TA1CCTL1 |=CM_1+SCS+CAP+CCIE; //上升沿觸發(fā)捕捉,同步模式、時能中斷 CCI1A
TA1CTL |= TASSEL1+MC_2; //選擇SMCLK時鐘作為計數(shù)時鐘源,不分頻 增計數(shù)模式不行,必須連續(xù)計數(shù)模式
}
相對應的中斷函數(shù)如下:
#pragma vector=TIMER0_A1_VECTOR //Timer0_A CC1 的中斷向量
__interrupt void Timer_A(void)
{
// CCI0A 使用的捕捉比較寄存器是TA0CCR0,TA0CCR0單獨分配給一個
//中斷向量TIMER1_A0_VECTOR,所以進入中斷后直接就是Timer0_A CC0產(chǎn)生的中斷,不用經(jīng)過類似
//下面的方法判斷中斷源了 。
//Timer0_A CC1-4, TA0公用一個中斷向量 TIMER0_A1_VECTOR,所以進入了中斷后還要用下面
//的方法進行判斷是哪一個中斷源產(chǎn)生的中斷
switch(TAIV) //如果是Timer0_A CC1產(chǎn)生的中斷
{
case 2:
{
flag=1;
LPM1_EXIT; //退出低功耗模式
// _BIC_SR_IRQ(LPM1_bits);
//_bic_SR_register_on_exit(LPM1_bits);
break;
}
case 4: break;
case 10:break;
}
}
#pragma vector=TIMER1_A1_VECTOR //Timer1_A CC1 的中斷向量
__interrupt void Timer_A1(void)
{
// P1OUT|=BIT0; //led調(diào)試用的
// LPM1_EXIT; //退出低功耗模式 因為使用的是CCI0A 使用的捕捉比較寄存器是TA1CCR0,TA1CCR0單獨分配給一個
//中斷向量TIMER1_A0_VECTOR,所以進入中斷后直接就是Timer1_A CC0產(chǎn)生的中斷,不用經(jīng)過類似
//下面注釋掉的方法判斷 。
//而Timer1_A CC1-4, TA1則公用一個中斷向量 TIMER1_A1_VECTOR,所以進入了中斷后還要用下面
//的方法進行判斷是哪一個中斷源產(chǎn)生的中斷
switch(TA1IV) //如果是Timer1_A CC1產(chǎn)生的中斷
{
case 2:
{
flag=2;
LPM1_EXIT; //退出低功耗模式
// _BIC_SR_IRQ(LPM1_bits);
//_bic_SR_register_on_exit(LPM1_bits);
break;
}
case 4:break;
case 10:break;
}
}
//如果要測量更低頻率的信號的話,可以在中斷中判斷溢出中斷發(fā)生的次數(shù),這樣就可以得到溢出的次數(shù),從而可以測量更
//低頻率的信號
程序例子---利用捕獲功能測一個正弦波信號的頻率
1.在進行測量之前,你需要對正弦波進行轉(zhuǎn)換,把它變?yōu)榉讲?。這個很簡單的電路。
2.測頻率,下面的代碼是我自己寫的,可以測到100K。精確度0.01HZ??偟膩碚f,用TIEMEA產(chǎn)生一個2S的中斷,2S后去去讀計算頻率。TIMERA0是對脈沖寬度的測量,TIMERA1是對定時器timerA中斷的處理
void Init_Capture(void)
{
P1DIR=~BIT1;
P1SEL|=BIT1;
BCSCTL2 |= SELS; // SMCLK=XT2=16M
BCSCTL2 |= DIVS_1; //SMCLK 2分頻,即SMCL=8MHZ
TACTL |=TASSEL_1+TAIE+TACLR; //8分頻,選擇ACLK為timerA的時鐘源(ACLK),開中斷,增計數(shù)模式
TACCTL0 |=CM_1+SCS+CAP+CCIS_0+CCIE; //上升沿捕獲+同步捕獲+開捕獲+timerA為捕獲+打開捕獲中斷
TACTL |=MC_2;
}
int main()
{
Init_Capture();
while(1)
{
if(global_a.Conver==1)//捕獲頻率
{
_DINT();
global_a.Conver=0;
global_a.CapCount=(float)((32768.0*global_a.pulse)/global_a.time);//計算頻率,注意理解!
Print_Fre();//顯示頻率
_EINT();
}
}
}
#pragma vector=TIMERA0_VECTOR
__interrupt void timer_A(void)
{
if(global_a.Cap_Tar==0)
{
global_a.Cap_First = TACCR0;
global_a.Cap_Tar++;
}
else
{
global_a.Cap_Last = TACCR0;
global_a.Cap_Tar++;
}
}
#pragma vector=TIMERA1_VECTOR
__interrupt void timeA1(void)
{
switch(TAIV)
{case 2:
break;
case 4:
break;
case 10: if(global_a.Cap_Tar==0)
global_a.pulse=0;
else
{
global_a.pulse=global_a.Cap_Tar-1;
global_a.time = global_a.Cap_Last-global_a.Cap_First;
global_a.Cap_Tar=0;
TACTL =~BIT0;
// BIC_SR_IRQ(LPM3_bits);
global_a.Conver=1;
_DINT();
}
break;
}
}
評論