1. 程式人生 > >stm32學習筆記 F1系列SPI

stm32學習筆記 F1系列SPI

SPI介面簡介
SPI 是英語Serial Peripheral interface的縮寫,顧名思義就是序列外
圍裝置介面。是Motorola首先在其MC68HCXX系列處理器上定義的。
SPI,是一種高速的,全雙工,同步的通訊匯流排,並且在晶片的管腳上只佔
用四根線,節約了晶片的管腳,同時為PCB的佈局上節省空間,提供方便,
主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字訊號處理器
和數字訊號解碼器之間。

SPI介面一般使用4條線通訊:
MISO 主裝置資料輸入,從裝置資料輸出。
MOSI 主裝置資料輸出,從裝置資料輸入。
SCLK時鐘訊號,由主裝置產生。
CS從裝置片選訊號,由主裝置控制。

注:STM32 SPI介面可配置為支援SPI協議或者支援I2S音訊協議,預設是SPI模式。可以通過軟體切換到I2S方式。 
 
SPI工作原理總結:
1>硬體上為4根線。
2>主機和從機都有一個序列移位暫存器,主機通過向它的SPI序列暫存器寫入一個位元組來發起一次傳輸。
3>序列移位暫存器通過MOSI訊號線將位元組傳送給從機,從機也將自己的序列移位暫存器中的內容通過MISO訊號線返回給主機。這樣,兩個移位暫存器中的內容就被交換。
4>外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的位元組;反之,若主機要讀取從機的一個位元組,就必須傳送一個空位元組來引發從機的傳輸。

常用暫存器:
SPI控制暫存器1(SPI_CR1)
SPI控制暫存器2(SPI_CR2)
SPI狀態暫存器(SPI_SR)
SPI資料暫存器(SPI_DR)
SPI_I2S配置暫存器(SPI_I2S_CFGR)
SPI_I2S預分頻暫存器(SPI_I2SPR)

SPI相關庫函式:
void SPI_I2S_DeInit(SPI_TypeDef* SPIx);
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
typedef struct
{
uint16_t SPI_Direction;
uint16_t SPI_Mode;
uint16_t SPI_DataSize;
uint16_t SPI_CPOL;
uint16_t SPI_CPHA;
uint16_t SPI_NSS;
uint16_t SPI_BaudRatePrescaler;
uint16_t SPI_FirstBit;
uint16_t SPI_CRCPolynomial;
}SPI_InitTypeDef;
第一個引數 SPI_Direction 是用來設定 SPI 的通訊方式,可以選擇為半雙工,全雙工,以及序列發和序列收方式,這裡我們選擇全雙工模式PI_Direction_2Lines_FullDuplex。
第二個引數 SPI_Mode 用來設定 SPI 的主從模式,這裡我們設定為主機模式 SPI_Mode_Master,當然有需要你也可以選擇為從機模式 SPI_Mode_Slave。
第三個引數 SPI_DataSiz 為 8 位還是 16 位幀格式選擇項,這裡我們是 8 位傳輸,選擇SPI_DataSize_8b。
第四個引數 SPI_CPOL 用來設定時鐘極性,我們設定串行同步時鐘的空閒狀態為高電平所以我們選擇 SPI_CPOL_High。
第五個引數 SPI_CPHA 用來設定時鐘相位,也就是選擇在串行同步時鐘的第幾個跳變沿(上升或下降)資料被取樣,可以為第一個或者第二個條邊沿採集,這裡我們選擇第二個跳變沿,所以選擇 SPI_CPHA_2Edge
第六個引數 SPI_NSS 設定 NSS 訊號由硬體(NSS 管腳)還是軟體控制,這裡我們通過軟體控制 NSS 關鍵,而不是硬體自動控制,所以選擇 SPI_NSS_Soft。
第七個引數 SPI_BaudRatePrescaler 很關鍵,就是設定 SPI 波特率預分頻值也就是決定 SPI 的時鐘的引數,從不分頻道 256 分頻 8 個可選值,初始化的時候我們選擇 256 分頻值SPI_BaudRatePrescaler_256, 傳輸速度為 36M/256=140.625KHz。
第八個引數 SPI_FirstBit 設定資料傳輸順序是 MSB 位在前還是 LSB 位在前,這裡我們選擇SPI_FirstBit_MSB 高位在前。

第九個引數 SPI_CRCPolynomial 是用來設定 CRC 校驗多項式,提高通訊可靠性,大於 1 即可。

void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize);
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);

程式配置過程:
①配置相關引腳的複用功能,使能SPIx時鐘
    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
②初始化SPIx,設定SPIx工作模式
    void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
③使能SPIx
    void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
④SPI傳輸資料
    void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
    uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;
⑤檢視SPI傳輸狀態
   SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);