硬件介紹:
SPI:SPI是Motorola首先在其MC68HCXX系列處理器上定義的,它是一種同步的高速串行通信協(xié)議,有關(guān)SPI協(xié)議的詳細(xì)內(nèi)容,參考:SPI_互動(dòng)百科。
MSP430對SPI的支持:當(dāng)msp430USART模塊控制器UxCTL的位SYNC置位時(shí),USART模塊工作于同步模式,對于149即工作于SPI模式,若是169,USART0可以支持I2C,可以通過另一控制位I2C控制,I2C位0則工作于SPI。在SPI模式下,允許單片機(jī)以確定的速率發(fā)送和接收7位或8位數(shù)據(jù)。
同步通信與異步通信類似;同步通信和異步通信寄存器資源一致,具體寄存器的不同位之間的功能存在差異;具體寄存器內(nèi)容參見TI提供的用戶指南。
USART模塊的SPI操作可以是3線和4線,其信號如下:
SIMO:從進(jìn)主出,主機(jī)模式下,數(shù)據(jù)輸出;從機(jī)模式下,數(shù)據(jù)輸入。
SOMI:從出主進(jìn),主機(jī)模式下,數(shù)據(jù)輸入;從機(jī)模式下,數(shù)據(jù)輸出。
UCLK:USART SPI模式時(shí)鐘,信號有主機(jī)輸出,從機(jī)輸入。
STE:從機(jī)模式發(fā)送接收允許控制腳,用于4線模式,控制多主從系統(tǒng)中多個(gè)從機(jī),避免發(fā)生沖突。具體方式如下(圖截自 用戶指南):四線主機(jī)模式:STE為高電平,SIMO和UCLK操作正常;STE為低電平,SIMO和UCLK被置為輸入方向,主機(jī)控制權(quán)讓出。
四線從機(jī)模式:STE為高電平,從機(jī)的發(fā)送和接收無效,且把SOMI置為輸入方向;STE為低電平,發(fā)送接收正常,SOMI也為正常輸出。USART模塊串行時(shí)鐘極性和相位設(shè)置:
USART的時(shí)鐘UCLK的極性和相位由位于UxTCTL寄存器的CKPH和CKPL位控制,具體如下圖:在程序中,我分別稱之為,時(shí)鐘模式0、時(shí)鐘模式1、時(shí)鐘模式2、時(shí)鐘模式3。
USART的波特率產(chǎn)生,SPI不同于異步通信:異步通信由UxBR1UxBR0UxMCTL三個(gè)寄存器控制,以產(chǎn)生標(biāo)準(zhǔn)頻率;而同步模式,主從設(shè)備用同一個(gè)時(shí)鐘,不再需要產(chǎn)生標(biāo)準(zhǔn)時(shí)鐘,故而不再用UxMCTL寄存器,設(shè)其值為0.
其他的,與異步通信基本一致,這里不再細(xì)說。具體參考用戶指南。
程序?qū)崿F(xiàn):
程序和異步通信方式類似:首先是初始化函數(shù),然后是讀取數(shù)據(jù)、寫入數(shù)據(jù)函數(shù)。此程序采用和我之前的UART程序庫類似的結(jié)構(gòu),寫入數(shù)據(jù)后進(jìn)入低功耗等待中斷,判斷標(biāo)志位進(jìn)行寫入數(shù)據(jù)和讀取數(shù)據(jù)。
這里函數(shù)只實(shí)現(xiàn)430的主機(jī)模式,如需從機(jī)模式可以仿照我的程序,進(jìn)行簡化實(shí)現(xiàn)。
由于,我即將使用的SPI設(shè)備(AD7708)不是字符型設(shè)備,這里不再實(shí)現(xiàn)寫入字符串函數(shù),也不再移植printf和scanf函數(shù),如若需要可以自己添加,printf和scanf的移植參考:MSP430程序庫<四>printf和scanf函數(shù)移植
初始化函數(shù):SpiMasterInit,實(shí)現(xiàn)主機(jī)模式的初始化工作,函數(shù)內(nèi)容如下:
char SpiMasterInit(long baud,char dataBits,char mode,char clkMode)
{
long int brclk; //波特率發(fā)生器時(shí)鐘頻率
UxCTL |= SWRST; //初始
//反饋選擇位,為1,發(fā)送的數(shù)被自己接收,用于測試,正常使用時(shí)注釋掉
//UxCTL |= LISTEN;
UxCTL |= SYNC + MM; //SPI 主機(jī)模式
//時(shí)鐘源設(shè)置
UxTCTL &=~ (SSEL0+SSEL1); //清除之前的時(shí)鐘設(shè)置
if(baud<=16364) //
{
UxTCTL |= SSEL0; //ACLK,降低功耗
brclk = 32768; //波特率發(fā)生器時(shí)鐘頻率=ACLK(32768)
}
else
{
UxTCTL |= SSEL1; //SMCLK,保證速度
brclk = 1000000; //波特率發(fā)生器時(shí)鐘頻率=SMCLK(1MHz)
}
//------------------------設(shè)置波特率-------------------------
if(baud < 300||baud > 115200) //波特率超出范圍
{
return 0;
}
//設(shè)置波特率寄存器
int fen = brclk / baud; //分頻系數(shù)
if(fen<2)return (0); //分頻系數(shù)必須大于2
else
{
UxBR0 = fen / 256;
UxBR1 = fen % 256;
}
//------------------------設(shè)置數(shù)據(jù)位-------------------------
switch(dataBits)
{
case 7:case'7': UxCTL &=~ CHAR; break; //7位數(shù)據(jù)
case 8:case'8': UxCTL |= CHAR; break; //8位數(shù)據(jù)
default : return(0); //參數(shù)錯(cuò)誤
}
//------------------------設(shè)置模式---------------------------
switch(mode)
{
case 3:case'3': UxTCTL |= STC; USPI3ON; break; //三線模式
case 4:case'4': UxTCTL &=~ STC; USPI4ON; break; //四線模式
default : return(0); //參數(shù)錯(cuò)誤
}
//------------------------設(shè)置UCLK模式-----------------------
switch(clkMode)
{
case 0:case'0': UxTCTL &=~ CKPH; UxTCTL &=~ CKPL; break; //模式0
case 1:case'1': UxTCTL &=~ CKPH; UxTCTL |= CKPL; break; //模式1
case 2:case'2': UxTCTL |= CKPH; UxTCTL &=~ CKPL; break; //模式2
case 3:case'3': UxTCTL |= CKPH; UxTCTL |= CKPL; break; //模式3
default : return(0); //參數(shù)錯(cuò)誤
}
UxME |= USPIEx; //模塊使能
UCTL0 &= ~SWRST; // Initialize USART state machine
UxIE |= URXIEx + UTXIEx; // Enable USART0 RX interrupt
return(1); //設(shè)置成功
}
程序注釋已經(jīng)比較詳細(xì),這里不再細(xì)說;如果要改為從機(jī)模式,把時(shí)鐘設(shè)置和波特率設(shè)置去掉應(yīng)該就可以了。
發(fā)送函數(shù)和接收函數(shù):
void SpiWriteDat(char c)
{
while (TxFlag==0) SpiLpm(); // 等待上一字節(jié)發(fā)完,并休眠
TxFlag=0; //
UxTXBUF=c;
}
char SpiReadDat()
{
while (RxFlag==0) SpiLpm(); // 收到一字節(jié)?
RxFlag=0;
return(UxRXBUF);
}
發(fā)送和接收函數(shù)和異步通信里面的幾乎一樣,如果標(biāo)志位為0,則等待改變?yōu)?,然后寫入或讀出;標(biāo)志位在中斷函數(shù)里被更改;中斷函數(shù)如下:
#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();
}
中斷里面僅僅置標(biāo)志位后,就退出低功耗;退出后即寫入或者讀取數(shù)據(jù)。
讀取或?qū)懭牒瘮?shù)調(diào)用的SpiLpm函數(shù):
void SpiLpm()
{
if(UxTCTL&SSEL0) LPM3; //若以ACLK 作時(shí)鐘,進(jìn)入LPM3休眠(僅打開ACLK)
else LPM0; //若以SMCLK作時(shí)鐘,進(jìn)入LPM0休眠(不關(guān)閉SMCLK)
}
根據(jù)不同情況進(jìn)入低功耗,如果單片機(jī)其他地方不允許進(jìn)入低功耗,可以更改這個(gè)函數(shù)。
程序部分就這么多了。需要的函數(shù)在頭文件里面聲明,方便使用。
使用示例:
程序使用方式和之前的程序庫相同,加入c文件,包含h文件,調(diào)用初始化函數(shù)后即可掉用程序庫中的函數(shù)。
#include "msp430x16x.h" //430寄存器頭文件
#include "Spi.h" //串口通訊程序庫頭文件
void main()
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
ClkInit();
// 主機(jī)模式,波特率25000,8位數(shù)據(jù)位,三線模式,時(shí)鐘模式0(具體見spi.c)
SpiMasterInit(25000,8,3,0);
_EINT();
while(1) //串口測試
{
SpiWriteDat(0X20);
char a = SpiReadDat();
}
}
這里只是一個(gè)簡單的使用示例,詳細(xì)的使用,將會在下一篇給出,下一篇:MSP430程序庫<六>通過SPI操作AD7708;將會使