本文來自http://blog.csdn.net/hellogv/ ,引用必須註明出處!
最近要做MSP430上的開發,一上手就要做IO類比UART這種難度的玩意,幸好網上已經有很多現成的MSP430的軟串口實現例子,本文代碼大部分參考
>http://www.microcontrol.cn/430base.htm上的《MSP430的Timer_A實現類比串口功能常式》,並且成功移植到MSP430FG439之上,不過移植的過程有點匪夷所思。。。。由於才學430沒幾天,所以花了一周才調試出IO類比UART。。。。
接下來就貼上100%能在MSP430FG439上使用的代碼(即使是同一Family的不同型號,也會有區別):
//利用定時器A 作串列口傳輸速率發生器用,利用捕捉比較功能實現非同步串列通訊。<br />//晶片型號:MSP430FG439 P1.0---TXD P1.1---RXD<br />//Timer_A TACLK=ACLK<br />//傳輸速率為 2400BIT/S TBIT1=14 TBIT0_5=6<br />//框架格式:(0)XXXXXXXX(1),0為起始位,1為結束位,XXXXXXXXX為8位元據<br />#include <msp430xG43x.h><br />#define TBIT1 14; //TBIT1 為1 位時間<br />#define TBIT0_5 6; //TBIT0_5 為半位時間<br />#define TXD BIT0 //使用P1.0作為發送,特殊功能腳,用CCI0A做比較輸出<br />#define RXD BIT1 //使用P1.1作為接收,特殊功能腳,用CCI0B做捕獲輸入<br />unsigned int TR_COUNT; //發收計數器<br />unsigned int T_DATA=0x00; //發送緩衝器<br />unsigned int R_DATA=0x00; //接收緩衝器<br />void init(void); //初始化<br />void txd (unsigned char byte); //發送一位元組資料<br />void rxd(void); //接收準備子程式<br />// ******************************************************<br />// 主函數<br />// *****************************************************<br />main()<br />{<br />init();<br />txd(0XFF);//由於發的第一幀會有錯,所以先發送無用幀<br />for(int i=0;i<255;i++)//發送0~255的資料<br /> txd(i);<br />while(1)<br />{<br /> rxd(); //準備接收<br /> LPM3; //進入休眠狀態,收到資料後在喚醒<br /> txd(R_DATA); //把收到的資料重發<br />}<br />}<br />// ******************************************************<br />// 初始化函數<br />// *****************************************************<br />void init(void)<br />{<br /> WDTCTL=WDTPW+WDTHOLD; //停止WDT<br /> P1DIR |= TXD; //TXD管腳為輸出<br /> P1SEL |= (RXD+TXD); //RXD和TXD都為特殊功能腳<br /> CCTL0|=OUT; //CCR0 OUT 設1<br /> TACTL|=TASSEL_1+MC_2; //設定時器A 時鐘源ACLK,設定時器為連續模式<br /> _EINT(); //開中斷允許<br />}<br />//******************************************************<br />//發送一位元組資料子程式<br />//輸入參量:unsigned char 類型位元組<br />// *****************************************************<br />void txd(unsigned char byte)<br />{<br /> T_DATA=255-byte; //關鍵點之一:這裡與其它MSP430的軟串口常式不同<br /> CCR0=TAR; //將TAR 時間存入CCR0,確定第一位 長度。<br /> CCR0=CCR0+TBIT1; //將每1 位時間周期加入CCR0。<br /> //uart框架格式:(0)xxxxxxxx(1)<br /> T_DATA=T_DATA<<1; //左移一位<br /> T_DATA|=BIT0; //最後一位為1<br /> TR_COUNT=10; //發送計數器。<br /> CCTL0=OUTMOD0+CCIE+OUTMOD2; //重新設定CCTL0(CCIS1-0=00)<br /> //捕獲/比較模組輸出模式1,充許模組中斷。<br /> while(CCIE&CCTL0); //等待CCIE 是否為0?為0 則表示發送完資料。<br />}<br />// *****************************************************<br />//接收準備子程式<br />//依賴TA0 中斷來接收一位元組資料。<br />// *****************************************************<br />void rxd(void)<br />{<br /> TR_COUNT=8; //接收資料位元 位元<br /> //關鍵點之一:其它MSP430的軟串口都是用下降沿(CM1),實踐中我發現接收的問題就出在這裡,所以我用CM0上升沿<br /> CCTL0 = SCS + CCIS0 + OUTMOD0 + CM0 + CAP + CCIE;<br /> // 比較捕獲為輸出模式+比較捕獲模組為中斷允許+"上升沿捕獲"+設定為捕獲模式<br /> //+選擇CCI0B 為捕獲源+同步捕獲<br />}<br />//*******************************************************************************<br />#pragma vector=TIMERA0_VECTOR //TIMER_A 中斷函數<br />__interrupt void cc10int(void)<br />{<br /> CCR0=CCR0+TBIT1; //重裝下一位時間(目前時間+1 位時間)<br /> //---------------------------接收處理常式段<br /> if(CCTL0 & CCIS0) //是處於接收中還是發送中?<br /> {<br /> if(CCTL0&CAP) //是捕獲模式還是比較模式?<br /> {<br /> CCTL0&=~CAP; //是-開始捕獲,將捕獲功能改為比較功能<br /> CCR0=CCR0+TBIT0_5; //開始捕獲位再加半位時間<br /> }<br /> else<br /> {<br /> R_DATA=R_DATA>>1; //處於比較功能,將前面 那位向低位移.<br /> if(CCTL0&SCCI) //這句等效於(P1IN&RXD)==1,如果RXD管腳是高電平<br /> {<br /> R_DATA|=BIT7; //則R_DATA的最高位置1<br /> }<br /> TR_COUNT--; //計數器減1<br /> if(TR_COUNT==0) //是否接收完8 位?<br /> {<br /> R_DATA=255-R_DATA; //關鍵點之一,這裡也要用255減一次<br /> //*****************************<br /> CCTL0&=~CCIE; //是接收完,捕獲/ 比較塊停止中斷充許<br /> LPM3_EXIT; //退出低功率模式(一般,在進入LPM3 時才使用)<br /> }<br /> }<br /> } //接收結束<br /> //----------------------------------------------------------------<br /> else //開始發送程式段<br /> {<br /> if(TR_COUNT==0)<br /> CCTL0&=~CCIE; //關捕獲/比較塊中斷,發送結束.<br /> else<br /> {<br /> if(T_DATA&0x0001) //狀態寄存器C 位是1,還是0?<br /> CCTL0&=~OUTMOD2; //狀態寄存器C 位為0,發送0.<br /> else<br /> CCTL0|=OUTMOD2; //狀態寄存器C 位為1,發送1.<br /> T_DATA=T_DATA>>1; //將位元組資料向右移一位<br /> --TR_COUNT; //位計數器減1.<br /> }<br /> }<br />}<br />
由於網上的MSP430常式都幾乎一致(都是出自TI的常式),並且大體思路沒有錯誤(不同型號之間的設定會有變化),所以接下來介紹一下初學者移植時也許遇到的問題:
1.這裡用了有特殊功能的IO腳,所以一定要對照晶片資料來確定自己所用的430對應功能在哪個IO上;
2.重點:要清楚串口幀的格式,這裡用到的是10位:(0)XXXXXXXX(1),0開頭,1結尾。
很多移植上的問題都是由此引起:
(1)由於發送時,從低位開始,即從1先開始發送,0最後發送,所以XXXXXXX要掉轉一次(T_DATA=255-byte;);
(2)由於未知其他寄存器對TXD的影響,發送首幀時也許會出錯,所以真正判斷是否發送成功要從第二針開始(txd(0XFF););
(3)接收的時候,也容易受到框架格式的影響。。。。網上的常式都是用下降沿(CM1),但RXD腳收到幀的第一位卻是1,最後一位是0(正如前面所說的低位先發),所以改為CM0上升沿就可以收到了,收到的次序是1XXXXXXX0,XXXXXXX也要掉轉一次(R_DATA=255-R_DATA;)才能還原來源資料。