1. 程式人生 > >spi通訊協議

spi通訊協議

學微控制器必須要掌握的集中序列通訊協議中spi就是其中之一。

下面主要是講解下個人對於spi通訊時序圖以及通訊協議的理解(有說錯的請大指出,小弟也是剛學的有很多不懂)。

下面進入正題:

 SPI簡介

SPI就是序列外圍裝置介面,它是一種高速的,全雙工,同步的通訊匯流排,並且在晶片的管腳上只佔用四根線,這四根線的定義分別是:

 MISO:主裝置資料輸入,從裝置資料輸出;

 MOSI:主裝置資料輸出,從裝置資料輸入;

 SCLK:時鐘訊號,由主裝置產生;

 CS:從裝置片選訊號,由主裝置控制

SPI為了和外設進行資料交換,根據外設工作要求(具體得看外設spi讀寫時序圖,有時序圖編寫驅動程式碼

),其輸出串行同步時鐘極性和相位可以進行配置,時鐘極性(CPOL)對傳輸協議沒有重大的影響。如果CPOL=0,串行同步時鐘的空閒狀態為低電平;如果CPOL=1,串行同步時鐘的空閒狀態為高電平。時鐘相位(CPHA)能夠配置用於選擇兩種不同的傳輸協議之一進行資料傳輸。如果CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)資料被取樣;如果CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)資料被取樣。

spi內部結構圖:

SPI匯流排資料傳輸時序圖如下圖:

總結:spi通訊為4線全雙工,spi通訊由於時鐘極性(CPOL)時鐘相位(CPHA)的不同可以配置為4種模式。完成一位資料傳輸是在一個週期兩個跳變沿內完成的,一個跳變沿取樣(可以理解為:內部移位暫存器讀取io值),一個跳變沿資料輸出(可以理解為:內部移位暫存器將最高位移動到io口上)。

具體移動過程參考此帖子:http://bbs.elecfans.com/jishu_441914_1_1.html

時鐘前沿輸出:

 

時鐘後沿取樣:

就這樣一個週期完成一位資料的交換。

stm32spi主模式下資料的傳送與接收:

資料傳送過程
當寫入資料至傳送緩衝器時,傳送過程開始。
在傳送第一個資料位時,資料字被並行地(通過內部匯流排)傳入移位暫存器,而後序列地移出到MOSI腳上; MSB在先還是LSB在先,取決於SPI_CR1暫存器中的LSBFIRST位的設定。資料從傳送緩衝器傳輸到移位暫存器時TXE標誌將被置位,如果設定了SPI_CR1暫存器中的TXEIE位,將產生中斷。
資料接收過程


對於接收器來說,當資料傳輸完成時:
● 傳送移位暫存器裡的資料到接收緩衝器,並且RXNE標誌被置位。
● 如果設定了SPI_CR2暫存器中的RXNEIE位,則產生中斷。
在最後取樣時鐘沿, RXNE位被設定,在移位暫存器中接收到的資料字被傳送到接收緩衝器。讀SPI_DR暫存器時, SPI裝置返回接收緩衝器中的資料。讀SPI_DR暫存器將清除RXNE位。
一旦傳輸開始,如果下一個將傳送的資料被放進了傳送緩衝器,就可以維持一個連續的傳輸流。在試圖寫傳送緩衝器之前,需確認TXE標誌應該為’1’。

總結;  傳送端:資料---DR暫存器---->緩衝區----->移位暫存器------>一位一位的傳送到主機輸出口

接收端:讀取miso口資料(從機發來)到移位暫存器---->讀取8位後放入緩衝區-----DR暫存器

程式的讀寫資料都是對緩衝區操作的。傳送緩衝暫存器為空TXE=1,接收緩衝暫存器不為空RXNE=1,所以spi讀寫資料過程:

傳送資料時:判斷髮送緩衝暫存器是否為空為空則傳送,

接收資料時:判斷接收緩衝暫存器是否非空,是則讀取資料。

例如:

u8 SPI1_ReadWriteByte(u8 TxData)
{
       u8 retry=0;
       while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //檢查指定的 SPI
                                                                                                                          //標誌位設定與否:傳送快取空標誌位
{
        retry++;
       if(retry>200)

       return 0;
 }
       SPI_I2S_SendData(SPI1, TxData); //通過外設 SPIx 傳送一個數據
       retry=0;
       while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//檢查指定的
                                                                                                                         SPI 標誌位設定與否:接受快取非空標誌位
{
        retry++;
        if(retry>200)return 0;
}
         return SPI_I2S_ReceiveData(SPI1); //返回通過 SPIx 最近接收的資料
}
stm32 spi初始化過程:

配置步驟
1. 通過SPI_CR1暫存器的BR[2:0]位定義序列時鐘波特率。
2. 選擇CPOL和CPHA位,定義資料傳輸和序列時鐘間的相位關係(見圖212)。
3. 設定DFF位來定義8位或16位資料幀格式。
4. 配置SPI_CR1暫存器的LSBFIRST位定義幀格式。
5. 如果需要NSS引腳工作在輸入模式,硬體模式下,在整個資料幀傳輸期間應把NSS腳連線
到高電平;在軟體模式下,需設定SPI_CR1暫存器的SSM位和SSI位。如果NSS引腳工作
在輸出模式,則只需設定SSOE位。
6. 必須設定MSTR位和SPE位(只當NSS腳被連到高電平,這些位才能保持置位)。
在這個配置中, MOSI引腳是資料輸出,而MISO引腳是資料輸入。
例如:

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //設定 SPI 全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //設定 SPI 工作模式:設定為主 SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8 位幀結構
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//選擇了序列時鐘的穩態:時鐘懸空高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //資料捕獲於第二個時鐘沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS 訊號由硬體管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //預分頻 256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //資料傳輸從 MSB 位開始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值計算的多項式
SPI_Init(SPI1, &SPI_InitStructure); //②根據指定的引數初始化外設 SPIx 暫存器
SPI_Cmd(SPI1, ENABLE); //③使能 SPI 外設