簡介
SPI是一種高速的,全雙工,同步的通信總線,並且在芯片的管腳上只佔用四根線,以主從方式工作,這種模式通常有一個主設備和一個或多個從設備,需要至少4根線,事實上3根也可以(單向傳輸時)。也是所有基於SPI的設備共有的,它們是SDI(數據輸入),SDO(數據輸出),SCK(時鐘),CS(片選)。
SDO --主設備數據輸出,從設備數據輸入
SDI --主設備數據輸入,從設備數據輸出
SCLK --時鐘信號,由主設備產生
CS --從設備使能信號,由主設備控制
工作過程:
1、主機啓動發送過程,送出時鐘脈衝信號
2、主移位寄存器的數據通過SDO移入到從移位寄存器,同時從移位寄存器中的數據通過SDI移人到主移位寄存器中
3、8(16)個時鐘脈衝過後,時鐘停頓,主移位寄存器中的8(16)位數據全部移人到從移位寄存器中,隨即又被自動裝入從接收緩衝器中,從機接收緩衝器滿標誌位(BF)和中斷標誌位(SSPIF)置“1”。同理,從移位寄存器中的8位數據全部移入到主寄存器中,隨即又被自動裝入到主接收緩衝器中.主接收緩衝器滿標誌位(BF)和中斷標誌位(SSPIF)置“1”
4、主CPU檢測到主接收緩衝器的滿標誌位或者中斷標誌位置1後,就可以讀取接收緩衝器中的數據。同樣,從CPU檢測到 從接收緩衝器滿標誌位或中斷標誌位置1後,就可以讀取接收緩衝器中的數據。
SPI有四種不同的數據傳輸時序,由CPOL和CPHL決定,CPOL是用來決定SCK時鐘信號空閒時的電平,CPHA是用來決定採樣時刻的:
CPOL=0,表示當SCLK=0時處於空閒態,所以有效狀態就是SCLK處於高電平時
CPOL=1,表示當SCLK=1時處於空閒態,所以有效狀態就是SCLK處於低電平時
CPHA=0,表示數據採樣是在第1個邊沿,數據發送在第2個邊沿
CPHA=1,表示數據採樣是在第2個邊沿,數據發送在第1個邊沿
STM32 SPI相關結構體:
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;
STM32的配置步驟:
1、配置相關引腳的複用功能,使能SPIx時鐘。 調用函數:void GPIO_Init();
2、初始化SPIx相關參數,設置SPIx工作模式。 調用函數:void SPI_Init();
3、使能SPIx。 調用函數:void SPI_Cmd();
4、SPI傳輸數據。 調用函數:void SPI_I2S_SendData();uint16_t SPI_I2S_ReceiveData();
5、查看SPI傳輸狀態。調用函數:SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//GPIOB時鐘使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE );//SPI2時鐘使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15複用推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15置位
//設置SPI單向或者雙向的數據模式:SPI設置爲雙線雙向全雙工
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //設置SPI工作模式:設置爲主SPI
//設置SPI的數據大小:SPI發送接收8位幀結構
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步時鐘的空閒狀態爲高電平
//串行同步時鐘的第二個跳變沿(上升或下降)數據被採樣
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
//NSS信號由硬件(NSS管腳)還是軟件(SSI位)管理:內部NSS信號有SSI位控制
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
//定義波特率預分頻的值:波特率預分頻值爲256
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
//指定數據傳輸從MSB位還是LSB位開始:數據傳輸從MSB位開始
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計算的多項式
SPI_Init(SPI2, &SPI_InitStructure); //根據SPI_InitStruct初始化外設SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外設
SPI2_ReadWriteByte(0xff);//啓動傳輸
}
//SPIx 讀寫一個字節,TxData:要寫入的字節,返回值:讀取到的字節
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
//檢查指定的SPI標誌位設置與否:發送緩存空標誌位
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200) return 0;
}
SPI_I2S_SendData(SPI2, TxData); //通過外設SPIx發送一個數據
retry=0;
//檢查指定的SPI標誌位設置與否:接受緩存非空標誌位
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry>200) return 0;
}
return SPI_I2S_ReceiveData(SPI2); //返回通過SPIx最近接收的數據
}