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