天天看點

MSP430G2553與MSP430F5336系列單片機總結[2]——定時器與捕捉比較器以及中斷介紹

        在研究定時器與捕捉比較器之前,我們可以先讨論一下,他們能做什麼?

        1.定時,産生固定頻率的波形,或者使LED等按照固定時間閃亮

        2.産生Timer0定時中斷,在一定的時間間隔執行某些功能,例如超音波傳感器的使用,可以設定超音波測量距離的測量頻率

        3.可以測量脈沖或PWM波的的高低電平時間或頻率

        4.脈沖計數

        5.捕捉比較模式可以産生PWM波

        6.可以産生PPM波

        7.可以測量PPM波的各通道占空比 

        是以定時器是單片機中使用頻率很高的資源,不要随便使用定時器的IO口直接做輸入輸出使用,這樣有點浪費。

        先對MSP430G2553進行分析,通過使用者手冊和Datasheet,我們可以知道G2553隻有定時器A,沒有定時器B,并且沒有定時器A2,定時器A隻有捕捉比較器0(TA0.CCI0A  引腳P1.1),捕捉比較器1(TA0.CCI1A  引腳P1.2)等資源,Timer_A為16為定時器,也就是說最高可以計數到65536,當定時到實踐或者滿足捕獲比較條件時可以出發定時器A中斷。

        在這裡對中斷進行一定的介紹,中斷使暫停CPU正在運作的程式,轉去執行相應的中斷服務程式,中斷完畢後傳回被中斷的程式并且繼續運作的現象和技術,中斷的存在是很必要的,可以很好地處理突發事件,并且不與主程式内容沖突。這些解釋或許不便于了解,我現在舉一個例子來說明中斷的必要性。例如,我現在要用MSP430系列的單片機做飛控控制四軸飛行器,首先他需要不斷産生200HZ的四路PWM波,還需要不斷的讀來自MPU6050傳遞過來的飛信器加速度角速度等資料,還需要擷取超音波傳回的距離資訊以避障,還需要進行四元素融合計算歐拉角以及進行PID疊代,這麼多的操作要同時執行,假如說沒有中斷,我們産生200HZ的PWM波的方式或許會采用延時,也就是寫一些延時程式延時到5ms則取反則能産生200HZ的pwm波,但是這樣你的程式需要不斷執行延時程式,并且不能被打斷,因為一旦被打斷,你産生的波形的周期也就變了,這樣我們将不能加入MPU6050等傳感器。但是使用中斷可以很好地解決這一問題。我們的主程式不斷執行的就是PID疊代這個操作,然後再5ms的計時周期到了之後,進入定時器中斷并且産生pwm波,序列槽中斷到了之後進入序列槽讀MPU6050的資料,echo信号的高電平到了之後進入超音波對應的定時器讀高電平,在這些中斷結束後繼續在主函數進行PID疊代,這樣就可以不斷地更新資訊,産生波形,并且不影響主函數的執行。是以學會使用中斷使很重要的。中斷的來源有内部中斷和外部中斷,并且可以設定優先級,要能夠進入中斷也必須先在相關的寄存器中設定中斷使能,這些内容大家可以參照代碼和一些資料自己學習,現在我來講幾個定時器中斷的典型例子:

#include  
    
     

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // 關閉看門狗定時器
  P1DIR |= 0x01;                            // 設定P1.0為輸出
  CCTL0 = CCIE;                             // TA0CCR0定時器使能,這裡的CCTL0在宏定義中其實就是TACCTL0
  CCR0 = 1000-1;                            //設定計數為1000
  TACTL = TASSEL_1 + MC_1;                  // 使用ACLK=32768HZ 上數模式

  _BIS_SR(LPM3_bits + GIE);                 // 進入LPM3中斷并且中斷使能
}

// 定時器A0的捕捉比較器0中斷
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
  P1OUT ^= 0x01;                            // P1.0口取反進而産生方波
}
/*
 * 産生方波的周期為:32768hz/1000*2=16HZ
 */
    
           

        上面這個例子采用的是捕捉比較器A0的中斷,A0和其他捕捉比較器的中斷使不同的,A0的中斷格式如這個程式所示,其他捕捉比較器的中斷我們之後再說,上面的程式基本有注釋,很容易看懂,其中要注意的就是定時器計數的四種模式,分别是停止模式(不計數),增計數模式(從0計數到TAxCCR0),連續計數模式(從0計數到0FFFFh),增減計數模式(從0計數到TAxCCR0之後減計數到0循環往複),是以通過增計數或者增減計數模式可以通過改變TAxCCR0改變計數周期,也就是改變要生成的波形周期。此外還有輸入輸出的模式定義,對應可以生成不同需求的波形,例如pwm波等等,這個可以詳細看使用者手冊了解。接下來看第二個例子:

#include 
    
      
int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// 關閉看門狗計時器
	P1DIR|=0X01;
	TACTL=TASSEL_2+MC_2+TAIE;    //SMCLK=1.048576Mhz定時器為16位,溢出計數為65536
	_BIS_SR(LPM0_bits+GIE);    //f=1.048576MHZ/65536*2=8hz
}
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
{
	switch(TA0IV)
	{
	case 2:break;
	case 4:break;
	case 10:P1OUT^=0x01;
	              break;
	}
}
/*
 * 定時器A有兩個不同的中斷向量位址,一個是CCR0的定時器溢出中斷,是定時或計數周期時間到了之後進入該中斷
 * 程式如下:
 * #pragma vector=TIMER0_A0_VECTOR
 * __interrupt void Timer_A0(void)
 * {
 * }
 * 另一個是CCR1/CCR2以及TAR計數溢出中斷
 * 程式如本程式所示
 * 其中case2是CCR1産生的中斷,case2是CCR2産生的中斷,case10是定時器TAR溢出中斷
 */
    
           

        這個例子使用的是A1的中斷,像注釋中所說,其中case2是CCR1産生的中斷,case4是CCR2産生的下降沿中斷,case10是定時器TAR溢出中斷,是以你想要在8hz時P1.0取反,則在case10時寫這句話,當然你也可以設定在CCR1或者CCR2的計數時間到時取反,如下方代碼所示:

#include 
    
      
int main(void) {
    WDTCTL = WDTPW +WDTHOLD;	// Stop watchdog timer
	P1DIR|=0x01;
	CCTL1=CCIE;
	CCR1=50000;
	TACTL=TASSEL_2+MC_2;   //SMCLK=1.048576MHZ 連續計數模式  計數100000個,是以頻率為10hz左右
	_BIS_SR(LPM0_bits+GIE);
}
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
{
	switch(TA0IV)
	{
	case 2:
	{
		P1OUT^=0x01;   //捕獲比較器1觸發
		CCR1+=50000;
	}
	    break;
	case 4:break;
	case 10:break;
	}
}
/*
 * f=10.89hz
 * 使用捕獲比較器1
 */

    
           
#include 
    
      
void main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
	P1SEL|=BIT1+BIT2;
	P1DIR|=BIT0+BIT1+BIT2;
	CCTL0=OUTMOD_4+CCIE;
	CCTL1=OUTMOD_4+CCIE;
	TACTL=TASSEL_2+MC_2+TAIE;
	_BIS_SR(LPM0_bits+GIE);
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0(void)
{
	CCR0+=200;
}
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A1(void)
{
	switch(TA0IV)
	{
	case 2:CCR1+=1000;
	            break;
	case 10:P1OUT^=0x01;
	            break;
	}
}
/*
 * 對于P1.0 f=1M/65536*2=8HZ
 * 對于P1.1即CCR0 f=1M/2*200=2500hz
 * 對于P1.2即CCR1 f=1M/2*1000=500HZ
 */
    
           

        以上的代碼大緻是定時器中斷的介紹,相信大家不難了解,但是到這裡會有一個問題,就是假如不用中斷,能不能産生一定周期的信号呢,答案是可以的,可以配置CCR1和CCR0的引腳為比較輸出模式,便可以産生一定頻率的方波。這裡比較簡單,不再仔細講,具體代碼和注釋如下:

#include  
    
     

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // 關閉看門狗計時器
  P1DIR |= 0x02;                            // P1.1 輸出
  P1SEL |= 0x02;                            // P1.1 第二功能選擇
  CCTL0 = OUTMOD_4;                         // CCR0 比較輸出模式4
  CCR0 = 500-1;                             //計數為500,是以周期為SMCLK/1000
  TACTL = TASSEL_2 + MC_1;                  // SMCLK為時鐘,上數模式

  _BIS_SR(CPUOFF);                          // 關閉CPU進入休眠,P1.1頻率為SMCLK/1000
}
    
           

        下面這個例子是不用中斷生成pwm波波形的例子,用中斷生成pwm波的例子我之後會專門寫文章說明

#include  
     
      

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // 關狗
  P1DIR |= 0x0C;                            // P1.2 P1.3 設定為輸出
  P1SEL |= 0x0C;                            // P1.2 P1.3 選擇TA1/2 功能
  CCR0 = 512-1;                             // 設定PWM波周期 
  CCTL1 = OUTMOD_7;                         // CCR1 模式7
  CCR1 = 384;                               // 設定CCR1占空比75%
  TACTL = TASSEL_2 + MC_1;                  // SMCLK為時鐘,上數模式

  _BIS_SR(CPUOFF);                          // 進入休眠
}
     
           

        以上基本是MSP430G2553的定時器A的說明,還有一些其他的例程可能配置時鐘為ACLK,或者産生不同的占空比,或者使用不同的引腳,不過原理都大同小異,大家要注意的就是選擇哪個時鐘,哪種計數模式,便能很好地運用定時器A。         同樣我們來看一下MSP430F5336的定時器使用,F5336的定時器資源相對來說就豐富的多,定時器有定時器A0,定時器A1,定時器A2,定時器B四個不同的定時器子產品,定時器A0有CCI0-CCI4五個捕捉比較器,還有CCI1B和CCI2B做為選擇,是管教P1.1-P1.7的第二功能;定時器A1和定時器A2都是分别有CCI0-CCI2三個捕捉比較器,在引腳P3上;定時器B有CCI0-CCI6七個捕捉比較器,在引腳P4上;具體的原理和G2553差不多,不過寄存器略有差別,我不詳細講了,直接貼代碼:         定時器A:

#include 
     
      
/*
 * 定時器A的寄存器情況基本與G2553一緻,可以參考中文資料
 * P1頻率為10hz,是以48ms發生一次中斷
 * SMCLK為1M左右,是以為50000us相當于50ms
 */
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;               	// 關閉看門狗
  P1DIR |= 0x01;                            // P1.0設為輸出
  TA0CCTL0 = CCIE;                         	// CCR0中斷使能
  TA0CCR0 = 50000;
  TA0CTL = TASSEL_2 + MC_1 + TACLR;  	// SMCLK, 增計數模式, 清除TAR計數器
  __bis_SR_register(LPM0_bits + GIE);  // 進入LPM0,使能中斷
}
// TA0中斷服務程式
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
  P1OUT ^= 0x01;                            	// 反轉P1.0口輸出狀态
}
     
           
#include 
    
     
/*
 * 定時器A的寄存器情況基本與G2553一緻,可以參考中文資料
 * 65536一次溢出
 * SMCLK為1M左右,是以為65535us相當于65ms
 */
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;              // 關閉看門狗
  P1DIR |= 0x01;                           // P1.0設為輸出
  TA1CTL = TASSEL_2 + MC_2 + TACLR + TAIE;
// SMCLK,連續計數模式,清除TAR,并使能TAIFG中斷
  __bis_SR_register(LPM0_bits + GIE); // 進入LPM0, 并啟動中斷
}
// TA1中斷服務程式
#pragma vector=TIMER1_A1_VECTOR
__interrupt void TIMER1_A1_ISR(void)
{
  switch(__even_in_range(TA1IV,14))
  {
    case  0: break;                         	// 無中斷
    case  2: break;                         	// TA1CCR1 CCIFG中斷
    case  4: break;                         	// TA1CCR2 CCIFG中斷
    case  6: break;                        	// TA1CCR3 CCIFG中斷
    case  8: break;                        	// TA1CCR4 CCIFG中斷
    case 10: break;                        	// TA1CCR5 CCIFG中斷
    case 12: break;                      	// TA1CCR6 CCIFG中斷
    case 14: P1OUT ^= 0x01;              	// TAIFG中斷
             break;
    default: break;
  }
}
    
           
#include 
     
      
/*
 * 使得P1.2(TA0CCR1)和P1.3(TA0CCR2)和P1.4(TA0CCR3)和P1.5(TA0CCR4)分别輸出占空比為20和%40和%60和%80的波形
 * 頻率為980000/TA0CCR0=400hz
 * 可以用作操控電機
 */
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;            // 關閉看門狗
  P1DIR |= BIT2+BIT3+BIT4+BIT5;        // P1.2和P1.3設為輸出
  P1SEL |= BIT2+BIT3+BIT4+BIT5;        // P1.2和P1.3引腳功能選為定時器輸出
  TA0CCR0 = 2500;                  	// PWM周期定義
  TA0CCTL1 = OUTMOD_7;               	// CCR1比較輸出模式7:複位/置位
  TA0CCR1 = 500;                       	// CCR1 PWM 占空比定義
  TA0CCTL2 = OUTMOD_7;                	// CCR2 比較輸出模式7:複位/置位
  TA0CCR2 = 1000;                       	// CCR2 PWM 占空比定義
  TA0CCTL3 = OUTMOD_7;               	// CCR1比較輸出模式7:複位/置位
  TA0CCR3 = 1500;                       	// CCR1 PWM 占空比定義
  TA0CCTL4 = OUTMOD_7;                	// CCR2 比較輸出模式7:複位/置位
  TA0CCR4 = 2000;                       	// CCR2 PWM 占空比定義
  TA0CTL = TASSEL_2 + MC_1 + TACLR;	// ACLK,增計數模式,清除TAR計數器
  __bis_SR_register(LPM3_bits);    	// 進入LPM3
}
     
           

        定時器A1,A2,B與之類似不再複述了,以上基本是定時器的原理和使用方法。                                                                                                                                                     ——達達的馬蹄                                                                                                                                                     ——2015-8-21

繼續閱讀