一:端口配置 1:P1DIR 設置為1,相應管腳為輸出。設置為0.相應管腳 為輸入狀態。 2:P1IE 設置為1,相應管腳具有中斷功能。設置為0, 相應管腳沒有中斷功能。 3:P1IES 設置為1,選擇下降沿觸發方式,設置為0,選 擇上升沿觸發方式。 4:P1IFG P1端口的中斷標志寄存器,如果P1端口當某 個管腳設置成中斷管腳,當有中斷觸發時,想應比特為1 ; 如果沒有中斷觸發,相應比特為0. 5: P1IN P1端口輸入寄存器,在輸入模式下,讀取該寄 存器相應管腳上的數據。 6: P1OUT P1端口的輸出去寄存器,在輸出模式下,如 果該寄存器相應比特設置為1時,相應管腳輸出高電平; 如果該寄存器相應比特為0時,相應管腳輸出低電平。 7: P1SEL寄存器 P1端口功能選擇寄存器,該寄存器主要 控制P1端口的I/O管腳作為一般I/O還是外圍模塊的功能 端口,該寄存器的相應比特為1時候,相應管腳為外圍功能 模塊,當該寄存器為0時,相應管腳為一般I/O管腳。 二 LaunchPad 寫程序的必要頭文件和格式: /*=================================================== #include"msp430g2553.h" Void main() { WDTCTL=WDTPW+WDTHOLD;//關閉看門狗。 //WDTPW 是看門狗的密碼,寫錯了會導致系統復位。 **(程序) } =====================================================*/ 三 點亮LED 僅僅是對IO 口的輸入輸出操作。與51 很不相同。 P1DIR|=BIT0;//設置P1.0 為輸出方向。===P1DIR|=0x01; //{P1DIR=BIT0;是設置P1.0 為輸出,其他全部為輸入方向。} //注意:LaunchPad 中很多操作是與,或,非等操作組成,時刻注意。 P1OUT|=BIT0;//這條指令就是設置P1.0 輸出為高電平。 這樣,就點亮了LED(接在P1.0 上的LED); 具體程序: #include"msp430g2553.h" Void main() { WDTCTL=WDTPW+WDTHOLD; P1DIR|=BIT0; P1OUT|=BIT0; While(1); } 四: 閃爍LED LaunchPad 上面自帶有2 個LED,一個接在P1.0 上,一個接在P1.6 上。 我們用2 個交替閃爍。 #include"msp430g2553.h" Void main();第一個字母大寫 { WDTCTL=WDTPW+WDTHOLD; P1DIR|=BIT0+BIT6;//設置P1.0 和P1.6 為輸出 P1OUT|=BIT0;//線讓LED0 亮。 While(1) { Unsigned int i=50000; While(i--); P1OUT^=0x41;//對P1.0 和P1.6 取反,所以LED0 和LED1 會交替閃爍。 } } 五:中斷系統 LaunchPad 的中斷系統功能相當強大,51 只有5 個中斷源,2 個定時,2 個外部, 一個串行口。但是LaunchPad 的中斷源幾乎是所有的引腳和所用的定時器。 在這里,最重要的就是中斷向量的判斷了。 定時器一般都是: vector=TIMER0_A0_VECTOR vector=TIMER0_A1_VECTOR vector=TIMER1_A0_VECTOR vector=TIMER1_A1_VECTOR 引腳中斷的向量: vector=PORT1_VECTOR; P1 口的中斷向量。 判斷是哪個引腳的話,有2 種辦法: 舉例子:P1.3 和P1.4 都是中斷的輸入引腳。現在進了中斷,我如何判斷是那個引 腳引起的呢? 第一種方法: vector=PORT1_VECTOR __interruput void Port1 (void) { If(P1IFG&BIT3);判斷的是P1.3 產生的中斷。 { ;要執行的函數。 P1IFG=0x00;//清0 中斷標志位。 } If(P1IFG&BIT4) { ;P1.4 產生的中端,執行相應的函數。 P1IFG=0x00; } } 第二種方法: vector=PORT1_VECTOR __interruput void Port1 (void) { P1IFG&=BIT3+BIT4;//因為只用到了P1.0 和P1.4,其他的中斷標志全部清零。 (或者:P1IFG=P1IFG&0x18) Switch(P1IFG) { Case 0x08: vector=3;break; //P1.3 產生的中斷 Case 0x10:vector=4;break;//P1.4 產生的中斷 } } 切記:進入中斷函數后要做的第一件事是,清除中斷標志。 例程: #include<msp430g2553.h> Void main(void)
{ WDTCTL=WDTPW+WDTHOLD; P1DIR|=BIT0; // 設置P1.0輸出 P1IES |=BIT3; // 設置從高到底跳變觸發 P1IFG&=~BIT3// 清除中斷標志位 P1IE |=BIT3 // 使P1.3能中斷 _BIS_SR(LPM_bits+GIE);// 啟動LMP4節能模式 } #proagma vector=PORT1_VECTOR _interrupt void Port_1(void) { If(P1IFG&BIT3) { P1OUT^=BIT0; P1IFG&=~BIT3; } } 程序一開始 1 WDTCTL=WDTPW+WDTHOLD; HOLD住看門狗 2 P1DIR|=BIT0;將P1.0 設置為輸出口。lunchpad上的P1.O接有一個LED. 3. 接下來到P1IES |= BIT3; 在上一節中已經介紹了,P1IES 寄存器是中斷沿選擇寄存器。這里是選擇位下降沿觸發中斷。 4. P1IFG &= ~BIT3; 為清除中斷標志,保證程序正常運行,當然此句可以不寫,這里只是做為例子 5. P1IE |= BIT3; 在上一節中已經介紹了,P1IE寄存器是使能中斷事件發生的寄存器。 - _BIS_SR(LPM4_bits + GIE);這里使程序進入最低功耗(LPM4)狀態。靠中斷來觸發喚醒CPU,在文章開始已經介紹有,假如在中斷函數中沒有寫有退出低功耗狀態的指令,程序會在進入低功耗的下一句中卡死,不再運行下去。另外_BIS_SR(GIE); 為打開總中斷的意思。
- 接下來到中斷函數的編寫。以此為例,詳細介紹中斷函數的編寫。如上所示,中斷函數編寫的規則為
#pragma vector= 中斷向量源 __interrupt void 函數名(void) |
|
摁住“Ctrl + 左鍵”點擊PORT1_VECTOR即可查看到所有的“中斷向量” 在上面的中斷向量中,加黑的位中斷向量源,寫入中斷函數編寫語法規則里面即可。而函數名則可以任意編寫。比如我要編寫一個有定時器1,CCR0寄存器溢出產生的中斷,則可以這樣編寫 #pragma vector= TIMER1_A0_VECTOR __interrupt void T1A0Int(void) { //程序代碼。。。 } |
假如是多IO輸入中斷,則如下所寫。 vector=PORT1_VECTOR __interrupt void Port1() { |
| //以下為參考處理程序,不使用的端口應當刪除其對于中斷源的判斷。 if((P1IFG&BIT0) == BIT0) { P2OUT&=~BIT0; //處理P1IN.0中斷 P1IFG &= ~BIT0; //清除中斷標志 //以下填充用戶代碼 } else if((P1IFG&BIT1) ==BIT1) { P2OUT&=~BIT1; //處理P1IN.1中斷 P1IFG &= ~BIT1; //清除中斷標志 //以下填充用戶代碼 } else if((P1IFG&BIT2) ==BIT2) { P2OUT&=~BIT2; //處理P1IN.2中斷 P1IFG &= ~BIT2; //清除中斷標志 //以下填充用戶代碼 } else if((P1IFG&BIT3) ==BIT3) { //處理P1IN.3中斷 P1IFG &= ~BIT3; //清除中斷標志 //以下填充用戶代碼 } else if((P1IFG&BIT4) ==BIT4) { P2OUT&=~BIT4; //處理P1IN.4中斷 P1IFG &= ~BIT4; //清除中斷標志 //以下填充用戶代碼 } else if((P1IFG&BIT5) ==BIT5) { //處理P1IN.5中斷 P1IFG &= ~BIT5; //清除中斷標志 //以下填充用戶代碼 } else if((P1IFG&BIT6) ==BIT6) { //處理P1IN.6中斷 P1IFG &= ~BIT6; //清除中斷標志 //以下填充用戶代碼 } else { //處理P1IN.7中斷 P1IFG &= ~BIT7; //清除中斷標志 //以下填充用戶代碼 } LPM3_EXIT; //退出中斷后退出低功耗模式。若退出中斷后要保留低功耗模式,將本句屏蔽 } |
|
六 定時器模塊 文先,介紹幾個英文縮寫的意思以及一些注意的地方。 1. Timer0/1 定時器0/1,在User's Guide中用的是TimerA/B,所指的也是Timer0/1 。G2553Datasheet中用的是Timer0/1 ,本文以G2553Datasheet為準。全文以Timer0為例,Timer1類同。 2. TAxR(x = 0/1)定時器x對應的計數器,這是一個只讀寄存器。硬件自動驅動計數。 - EQUy(y = 0/1/2)計數事件發生寄存器,當TAxR = TAxCCRy時EQUy置1
定時器簡介 MSPG2553共有兩個定時器,Timer0、Timer1,他們都是十六位的定時、計數器,內含三個捕獲、比較寄存器。兩個定時器均支持多個捕獲、PWM輸出、間歇性計時,定時器包含多個中斷源,可以是計數溢出中斷、捕獲中斷等等。 定時器包含: 同步十六位定時,計數器運行模式。 時鐘源從MCLK、SMCLK、ACLK任意選擇 三個比較,捕獲寄存器。 中斷向量寄存器能快速解碼的所有定時器中斷 Timer0組成框圖 下面簡要介紹一下該硬件框圖的意思,從左上角看,首先是一個時鐘源選擇寄存器TASSELx,通過該寄存器選擇定時器的時鐘源,選擇了時鐘源后有一個分頻器Divider,相應的設置寄存器是IDx,再過來就到一個定時器的核心部分,一個16位的定時器TAR。其右側有一個定時器的計數模塊,MCx寄存器用來設置計數模式。接下來,TAR正下方有三個橫線,右側標有CCR0、CCR1、CCR2,意思是CCR1、CCR0的框圖和下方CCR2的框圖是一樣的。此處省略不寫。在CCR中,左上角為一個捕獲源選擇寄存器。可以從CCI2A、CCI2B、GND或者VCC選擇捕獲源,選擇捕獲源后有一個選擇捕獲模式寄存器Capture Mode,然后過來有一個捕獲溢出狀態寄存器COV,SCS同步/異步捕獲模式選擇位,然后連接到捕獲比較寄存器。下方為模式選擇寄存器,具體設置可以查看相應的寄存器設置。 這里僅是大概介紹一下Timer0的寄存器,具體的設置使用還看參考相應的寄存器并結合例程慢慢學習理解。 定時器運行方式 下面簡要重點介紹定時器計數模塊的四種模式以及7種輸出模式。 Timer0有一個在不斷計數的只讀寄存器TA0R。計數器的計數模式共有四種, 停止模式(Stop mode)、連續增計數模式(Up mode)、遞增計數模式(continuous mode)、增減計數模式(Up/down mode)。由上圖可知,這四種模式可以通過MCx寄存器進行設置。 以上四種模式可以由下圖可以很好理解。 1. Stop模式計數器不工作。 2. 連續計數模式為計數器從零開始連續增計數一直到0xFFFF即65535,然后又重新從零開始計數。 3. 遞增計數模式與連續計數模式僅有一點點區別,遞增模式為計數器連續增加到TA0CCR0(即圖中的CCR0)中的值后又重新從零開始計數。TA0CCR0的值時可以在程序中直接賦值的。 4. 遞增遞減模式也很好理解,計數器從零開始計數到CCR0后又自動減數,到零后又增計數,就像三角波一樣。 每一個捕獲比較模塊都有一個輸出單元,這個輸出單元專門用來產生以下如PWM的波形信號,每一個輸出單元都可以通過配置OUTMOD寄存器的值來設定八種信號輸出模式, 接下來再介紹一下定時器的捕獲/比較功能,具體應查看技術手冊。 捕獲模式 捕獲模式可以用來速度計算或時間測量.CCIxA ,CCIxB的捕獲源可以連接到外部引腳或者內部信號,可以設定CCIDx,CMx,位讓寄存器捕獲上升,下降,或者兩個信號的邊緣.輸入信號的電平可以通過CCI位的讀取. 當設置寄存器CAP=1時,使能捕獲模塊. 比較模式 比較模式設置CAP = 0的情況向,比較模式用于產生PWM信號。或者在指定時間里輸出終端信號,當TAxR計數到TACCRx時 建立起CCIFG位 中斷事件發生標志位EQUx=1 EQUx的隱含改變將影響輸出模式 輸入信號CCI被鎖上SCCI
2. 遞增計數模式下的輸出 * **************************************************************** / / ****************************************************************** * TACTL寄存器,Timer_A 控制寄存器 * TASSEL_x:TA時鐘源選擇寄存器 * 00 TACLK * 01 ACLK * 10 SMCLK * 11 INCLK * IDx: 時鐘源分頻寄存器。為輸入時鐘分頻選擇 * 00 /1 * 01 /2 * 10 /4 * 11 /8 * * ************************************************************** / * 定時計數模塊 =四中模式+7種輸出方式 / ***************************************************************** * * MCx: 計數模式寄存器 模式控制,當TA不用于節省功耗時,將MCx=00h * 00 停止模式:定時器停止 * 01 增模式 :定時器計數到TACCR0 * 10 連續模式:定時器計數到0FFFFh * 11 增減模式:定時器計數到TACCR0 然后減到000h * * TACLR: 定時器清零。置位時會復位TAR,時鐘分頻和計數方向。 * TACLR位會自動復位并讀出值為零。 * * TAIE: TA中斷允許。改為允許TAIFG中斷請求 * 0 中斷禁止 * 1 中斷允許 * TAIFG: TA中斷標志位 * 0 無中斷掛起 * 1 中斷掛起 * ************************************************************** / / ***************************************************************** * * * TACCTLx,捕獲比較控制寄存器 * CMx: 捕獲模式 * 00 不捕獲 * 01 上升沿捕獲 * 10 下降沿捕獲 * 11 上升和下降同時捕 * CCISx: 捕獲比較選擇,改為選擇TACCRx的輸入信號 * 00 CCIxA * 01 CCIxB * 10 GND * 11 VCC * SCS: 同步捕獲源,改為用于將捕獲通信和同步時鐘 * 0 異步捕獲 * 1 同步捕獲 * SCCI:同步的捕獲/比較輸入,所選擇的輸入信號由EQUx信號所存, * 并可通過該位讀取 * CAP: 捕獲模式 * 0 比較模式 * 1 捕獲模式 *OUTMODx:輸出模式位,對TACCR0無效 * 000 OUT 位的值 * 001 置位 * 010 翻轉/復位 * 011 復位/復位 * 100 翻轉 * 101 復位 * 110 翻轉/置位 * 111 復位/置位 * CCIE: 捕獲比較中斷允許位 * 0 中斷禁止 * 1 中斷允許 * CCI: 捕獲比較輸入 * OUT: 對于輸出模式0,該位直接控制輸出狀態 * COV: 捕獲溢出位。該位表示一個捕獲溢出發生,由軟件復位 * CCIFG:捕獲比較中斷標志位 * 0 沒有中斷掛起 * 1 有中斷掛起 * ***************************************************************/ #include <msp430g2553.h> unsigned int A=10, B=20 ; void main (void) { WDTCTL = WDTPW + WDTHOLD; TACTL|=TASSEL_2+TACLR+MC_1+ID_3; // SMCLK時鐘 ;定時器清零;增模式 8分頻 CCTL0=CCIE; //捕獲中斷允許 CCR0=B; //TACCR0 裝載值 CCTL1=OUTMOD_7; //輸出模式復位 CCR1=A; // BCSCTL1 P1DIR=BIT6; P1SEL=BIT6; // _EINT(); //使能所有中斷 while(1); } /*#pragma vector=TIMER0_A0_VECTOR __interrupt void ta0_isr(void) { unsigned int i; for(i=0;i<num;i++) pwm=i; }*/ 定時器中斷 這里以定時器0為例,定時器1同。 定時器的中斷可有定時器TA0CCR0溢出產生,也可由TA0CCRx(x =1/2)溢出產生、捕獲/比較事件發生引起的中斷,前者有一個專用的中斷向量,TIMER0_A0_VECTOR,而后者用的TIMER0_A1_VECTOR,至于是哪一個中斷時間發生,還要根據標志位來判斷。 下面以官方例程LaunchPad Lab2為例介紹定時器A的操作。 例一 #include <msp430g2553.h> void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { while(1); // If calibration constants erased, trap CPU!! } BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO P1DIR = 0x40; // P1.6 output (green LED) P1OUT = 0; // LED off IFG1 &= ~OFIFG; // Clear OSCFault flag BCSCTL1 |= DIVA_3; // ACLK = VLO/8 BCSCTL2 |= SELM_3 + DIVM_3 + DIVS_3; // MCLK = DCO/8, SMCLK = DCO/8 // Configure TimerA TACTL = TASSEL_1 + MC_1 + TAIE; // Source: ACLK, UP mode CCR0 = 5100; //Timer count 5100 CCR1 = 2000; //Timer count 100 CCTL0 = CCIE; //CCR0 interrupt enabled CCTL1 = CCIE; //CCR1 interrupt enabled _BIS_SR(GIE); for(;;); } // Timer A0 interrupt service routine #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A0 (void) { P1OUT |= BIT6; // P1.6 output High } // Timer A1 Interrupt Vector (TA0IV) handler #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A1(void) { switch( TA0IV ) { case 2: P1OUT &= ~BIT6; // P1.6 output Low |
|
程序一開始關閉看門狗,if語句作為時鐘校準的范例,可以刪去。BCSCTL3 |= LFXT1S_2; 選擇超低頻時鐘源。然后設定輸出口,清除中斷標志,時鐘源分頻設定,接下里組建定時器A,即定時器0,在詳細介紹代碼之前,首先看頭文件關于定時器相關寄存器的設定。 例二 下面舉一個無需中斷服務函數、硬件自動實現產生兩路PWM的例子。 代碼很簡單,初始化一下即可。 #include<msp430g2553.h> void Set_TimerB_PWM(void) { //使用系統初始化時的默認時鐘1MHz,定時器B專門用于產生PWM 波形。 TA1CTL = TASSEL_2 + MC_1 + TACLR;//使用系統次主機SMCKL、增計數模式、清楚定時器B時鐘 TA1CCR0 = 5001 - 1;//在1MHz的主頻率下,1*10^6/5000=200Hz的中斷頻率 TA1CCR1 = 3751 - 2;//當寄存器TACCR1的值小于3750時,輸出口保持高電平。5000*3/4=3750,此路產生3:1的PWM波形。 TA1CCR2 = 1251 - 2;//當寄存器TACCR1的值小于1250時,輸出口保持高電平。5000*1/4=1250,產生1:3的PWM波 TA1CCTL1 = OUTMOD_7;//輸出模式7,計數器計數到5000計數器自動置位,無需中斷服務子函數。 TA1CCTL2 = OUTMOD_7;//輸出模式7,計數器計數到5000計數器自動置位,無需中斷服務子函數。 P2SEL |= BIT1 + BIT5;//只有這兩路可選(為什么是這兩路?在G2553Datasheet中有特別指明)。做第二功能使用(PWM輸出) P1DIR |= BIT6; //電機控制口CTL//這里與本例無關 P1OUT &= ~BIT6; //start with 0 -->IN2,4為1,滅//這里與本例無關 } |
初始化時鐘后直接調用該函數即可。 我這里使用的是定時器B(即Timer1)。詳細的介紹見以上備注。 七 時鐘配置 時鐘源:
外部晶體振蕩器 超低頻率振蕩器(VLO) 數字控制振蕩器(DCO)
時鐘信號:
ACLK :Auxiliary clock.輔助時鐘。 MCLK :Master clock主時鐘。 SMCLK :Second Master clock次主機時鐘。 內部晶體振蕩器產生時鐘后經過DCOR、SCG0、RSELx、DCO等各個寄存器為MCLK、SMCLK提供時鐘源 內部時鐘還有一個超低頻率內置晶體振蕩器(VLO)在上圖的最上方。可作為低頻時鐘源。 另外一個部分是系統的外部時鐘,外部晶振經過LFXT等各個寄存器設置后可以為MCLK、ACLK提供時鐘源。 上圖中SELM、SELS為時鐘源選擇寄存器。 上圖中DIVA、DIVM、DIVS都是分頻器,時鐘源可以經過1/2/4/8分頻后為CPU提供時鐘,以降低功耗。
ADC10的時鐘部分框圖
Timer_A的結構框圖 Timer_A不能選擇MCLK作為Timer_A的時鐘
CPU是處理器的核心部分,它使用的時鐘始終是MCLK。 上電后,系統默認使用的主系統時鐘MCLK和子系統時鐘SMCLK是同為DCOCLK產生的1MHz時鐘,而輔助時鐘ACLK則為內部VLOCLK產生的12KHz時鐘 MSP430低功耗模式 單片機中,功耗最低的單片機要MSP430單片機,這是做手持設備最優選擇,MSP430中,用到5種低功耗,LPM0,LPM1,LPM2,LPM3,LPM4,這五種低功耗各種解釋如下 : LPM0:CPU停止工作,MCLK時鐘停止,SMCLK、ACLK時鐘還在工作。 LPM1:CPU停止工作,MCLK時鐘停止,在活動模式如果DCO沒有作為MCLK和SMCLK時鐘時,則直流發生器被禁止,否則就保持活動狀態,SMCLK、ACLK時鐘依然還在工作。 LPM2:CPU停止工作,MCLK、SMCLK時鐘停止工作,如果DCO沒有作為MCLK、SMCLK,自動被禁止直流發生器保持有效,ACLK還處于工作中。 LPM3:CPU停止工作,MCLK、SMCLK時鐘停止工作,DCO時鐘也停止工作,僅ACLK時鐘還處于工作狀態。 LPM4:CPU停止工作,MCLK、SMCLK時鐘停止工作,DCO時鐘也停止工作,ACLK也停止工作。此時功耗最低。 一般情況下,處理器進入低功耗模式后,由中斷來喚醒,外部中斷或內部中斷。 如果想進入低功耗1,則程序可以為:_BIS_SR(LPM1_bits + GIE);退出低功耗1,則程序可以為:LPM1_EXIT; 進入其他低功耗和退出低功耗一樣。 低功耗執行的一個過程:程序從main函數入口開始執行程序,當遇到進入低功耗程序時,如:_BIS_SR(LPM1_bits + GIE);此時相當于下面的程序處于停止狀態不再執行,當有一個中斷來到,則會進入中斷處理程序,自動退出低功耗,如果在中斷中沒有沒有退出低功耗,當中斷服務程序執行完成后,又會重新進入低功耗。
完整的Word格式文檔51黑下載地址:
|