MSP430程序库五SPI同步串行通信
SPI總線系統是一種同步串行外設接口;是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節約了芯片的管腳,同時為PCB的布局上節省空間,提供方便,正是出于這種簡單易用的特性,現在越來越多的芯片集成了這種通信協議。 許多的芯片都用這種協議通信:EEPROM、Flash、實時時鐘、AD轉換器、數字信號處理器等:MSP430的USART模塊不僅能夠實現異步模式(見:MSP430程序庫<二>UART異步串口),而且支持同步串行通信(即SPI模式);其SPI支持3線、4線操作,支持主機模式和從機模式,字符長度可以7位或8位等。由于要用AD7708芯片完成AD采樣,AD7708是通過SPI與其它設備通信的;本程序比較簡化,只完成了主機模式的初始化。
SPI:SPI是Motorola首先在其MC68HCXX系列處理器上定義的,它是一種同步的高速串行通信協議,有關SPI協議的詳細內容,參考:SPI_互動百科。
MSP430對SPI的支持:當msp430USART模塊控制器UxCTL的位SYNC置位時,USART模塊工作于同步模式,對于149即工作于SPI模式,若是169,USART0可以支持I2C,可以通過另一控制位I2C控制,I2C位0則工作于SPI。在SPI模式下,允許單片機以確定的速率發送和接收7位或8位數據。
同步通信與異步通信類似;同步通信和異步通信寄存器資源一致,具體寄存器的不同位之間的功能存在差異;具體寄存器內容參見TI提供的用戶指南。
USART模塊的SPI操作可以是3線和4線,其信號如下:
SIMO:從進主出,主機模式下,數據輸出;從機模式下,數據輸入。
SOMI:從出主進,主機模式下,數據輸入;從機模式下,數據輸出。
UCLK:USART SPI模式時鐘,信號有主機輸出,從機輸入。
STE:從機模式發送接收允許控制腳,用于4線模式,控制多主從系統中多個從機,避免發生沖突。具體方式如下(圖截自 用戶指南):
四線主機模式:STE為高電平,SIMO和UCLK操作正常;STE為低電平,SIMO和UCLK被置為輸入方向,主機控制權讓出。
四線從機模式:STE為高電平,從機的發送和接收無效,且把SOMI置為輸入方向;STE為低電平,發送接收正常,SOMI也為正常輸出。
USART模塊串行時鐘極性和相位設置:
USART的時鐘UCLK的極性和相位由位于UxTCTL寄存器的CKPH和CKPL位控制,具體如下圖:在程序中,我分別稱之為,時鐘模式0、時鐘模式1、時鐘模式2、時鐘模式3。
USART的波特率產生,SPI不同于異步通信:異步通信由UxBR1\UxBR0\UxMCTL三個寄存器控制,以產生標準頻率;而同步模式,主從設備用同一個時鐘,不再需要產生標準時鐘,故而不再用UxMCTL寄存器,設其值為0.
其他的,與異步通信基本一致,這里不再細說。具體參考用戶指南。
程序和異步通信方式類似:首先是初始化函數,然后是讀取數據、寫入數據函數。此程序采用和我之前的UART程序庫類似的結構,寫入數據后進入低功耗等待中斷,判斷標志位進行寫入數據和讀取數據。
這里函數只實現430的主機模式,如需從機模式可以仿照我的程序,進行簡化實現。
由于,我即將使用的SPI設備(AD7708)不是字符型設備,這里不再實現寫入字符串函數,也不再移植printf和scanf函數,如若需要可以自己添加,printf和scanf的移植參考:MSP430程序庫<四>printf和scanf函數移植
初始化函數:SpiMasterInit,實現主機模式的初始化工作,函數內容如下:
char SpiMasterInit(long baud,char dataBits,char mode,char clkMode) {long int brclk; //波特率發生器時鐘頻率UxCTL |= SWRST; //初始//反饋選擇位,為1,發送的數被自己接收,用于測試,正常使用時注釋掉//UxCTL |= LISTEN;UxCTL |= SYNC + MM; //SPI 主機模式//時鐘源設置UxTCTL &=~ (SSEL0+SSEL1); //清除之前的時鐘設置if(baud<=16364) //{UxTCTL |= SSEL0; //ACLK,降低功耗brclk = 32768; //波特率發生器時鐘頻率=ACLK(32768)}else{UxTCTL |= SSEL1; //SMCLK,保證速度brclk = 1000000; //波特率發生器時鐘頻率=SMCLK(1MHz)}//------------------------設置波特率------------------------- if(baud < 300||baud > 115200) //波特率超出范圍{return 0;}//設置波特率寄存器int fen = brclk / baud; //分頻系數if(fen<2)return (0); //分頻系數必須大于2else{UxBR0 = fen / 256;UxBR1 = fen % 256;}//------------------------設置數據位------------------------- switch(dataBits){case 7:case'7': UxCTL &=~ CHAR; break; //7位數據case 8:case'8': UxCTL |= CHAR; break; //8位數據default : return(0); //參數錯誤} //------------------------設置模式--------------------------- switch(mode){case 3:case'3': UxTCTL |= STC; USPI3ON; break; //三線模式case 4:case'4': UxTCTL &=~ STC; USPI4ON; break; //四線模式default : return(0); //參數錯誤}//------------------------設置UCLK模式----------------------- switch(clkMode){case 0:case'0': UxTCTL &=~ CKPH; UxTCTL &=~ CKPL; break; //模式0case 1:case'1': UxTCTL &=~ CKPH; UxTCTL |= CKPL; break; //模式1case 2:case'2': UxTCTL |= CKPH; UxTCTL &=~ CKPL; break; //模式2case 3:case'3': UxTCTL |= CKPH; UxTCTL |= CKPL; break; //模式3default : return(0); //參數錯誤}UxME |= USPIEx; //模塊使能UCTL0 &= ~SWRST; // Initialize USART state machineUxIE |= URXIEx + UTXIEx; // Enable USART0 RX interrupt return(1); //設置成功 }程序注釋已經比較詳細,這里不再細說;如果要改為從機模式,把時鐘設置和波特率設置去掉應該就可以了。
發送函數和接收函數:
void SpiWriteDat(char c) { while (TxFlag==0) SpiLpm(); // 等待上一字節發完,并休眠TxFlag=0; //UxTXBUF=c; } char SpiReadDat() { while (RxFlag==0) SpiLpm(); // 收到一字節?RxFlag=0;return(UxRXBUF); }發送和接收函數和異步通信里面的幾乎一樣,如果標志位為0,則等待改變為1,然后寫入或讀出;標志位在中斷函數里被更改;中斷函數如下:
#pragma vector=USARTxRX_VECTOR __interrupt void UartRx() {RxFlag=1;__low_power_mode_off_on_exit(); } #pragma vector=USARTxTX_VECTOR __interrupt void UartTx () {TxFlag=1;__low_power_mode_off_on_exit(); }中斷里面僅僅置標志位后,就退出低功耗;退出后即寫入或者讀取數據。
讀取或寫入函數調用的SpiLpm函數:
void SpiLpm() {if(UxTCTL&SSEL0) LPM3; //若以ACLK 作時鐘,進入LPM3休眠(僅打開ACLK)else LPM0; //若以SMCLK作時鐘,進入LPM0休眠(不關閉SMCLK) }根據不同情況進入低功耗,如果單片機其他地方不允許進入低功耗,可以更改這個函數。
程序部分就這么多了。需要的函數在頭文件里面聲明,方便使用。
程序使用方式和之前的程序庫相同,加入c文件,包含h文件,調用初始化函數后即可掉用程序庫中的函數。
#include "msp430x16x.h" //430寄存器頭文件 #include "Spi.h" //串口通訊程序庫頭文件void main() {// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;ClkInit();// 主機模式,波特率25000,8位數據位,三線模式,時鐘模式0(具體見spi.c)SpiMasterInit(25000,8,3,0);_EINT(); while(1) //串口測試{SpiWriteDat(0X20);char a = SpiReadDat();} }這里只是一個簡單的使用示例,詳細的使用,將會在下一篇給出,下一篇:MSP430程序庫<六>通過SPI操作AD7708;將會使用今天的程序庫,完成SPI的通信部分。
注意事項:
SPI是全雙工通信,每次寫入(發送)8位/7位數據的同時,430的SPI主模塊都會在發送后半個時鐘周期讀取采樣的0/1信號,存入接收緩沖寄存器,所以,每次的寫入,均有數據讀取,但不一定是從設備發送回來的,這個地方在使用430主機模式的時候必須注意,很容易出錯(我也是在調試AD7708的時候才注意到這個地方的);SPI的函數已經添加SpiWriteData函數,這個函數會在發送的同時返回發送完成半個時鐘周期后的接收到的數據,方便使用;不建議使用前面的發送和讀取函數,很容易出錯;建議使用剛添加的這個函數,程序庫已經更新,可以重新下載。函數SpiWriteData:
char SpiWriteData(char c) {SpiWriteDat(c);return SpiReadDat(); }發送后讀取即可,程序比較簡單。
新的示例程序:
void main() {// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;ClkInit();// 主機模式,波特率25000,8位數據位,三線模式,時鐘模式0(具體見spi.c)SpiMasterInit(25000,8,3,0);_EINT(); while(1) //串口測試{SpiWriteData(0X20); //只寫入char a = SpiWriteData(0xff); //只讀取} }詳細示例,參參考下一篇:MSP430程序庫<六>通過SPI操作AD7708
SPI的通信部分完成,有什么不足,歡迎討論。謝啦!
附件:程序庫
作者:給我一杯酒
出處:http://Engin.cnblogs.com/
本文版權歸作者和博客園共有,歡迎轉載,轉載保留此段文字并且注明出處;謝謝。
轉載于:https://www.cnblogs.com/Engin/archive/2011/08/09/2133036.html
總結
以上是生活随笔為你收集整理的MSP430程序库五SPI同步串行通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: textarea中的换行符
- 下一篇: oracle构造过程实例