1. SPI,是一種高速的,全雙工,同步的通訊總線,而且在芯片的管腳上只佔用四根線:SCLK,MISO,MOSI,CSweb
2. SPI結構簡圖:緩存
能夠看出,SPI主從設備兩端都有一個位移寄存器,數據在位移寄存器上經過逐位移動來實現同步雙工通訊,在主機發送數據的同時也會收到從機發來的數據。相似一個循環。(圖片很差編輯,將就着看),須要注意的是傳輸過程是經過主機寫入一個須要發送的數據來開始的。函數
若是隻進行寫操做,主機只需忽略接收到的字節;反之,若主機要讀取從機的一個字節,就必須發送一個空字節來引起從機的傳輸。發送結束能夠設置中斷。ui
3. 時鐘極性(POL)和相位(PHA),經過配置極性及相位爲0或1,可配置成爲4種不一樣的傳輸時序:極性爲0,時鐘空閒爲低電平,反之爲高;相位爲0,據在第一個時鐘跳變沿被採集,爲1的話在第二個跳變沿被採集。如圖:spa
4. SPI 時鐘最多能夠到 18Mhz,支持 DMA,能夠配置爲 SPI 協議或者 I2S (一種音頻傳輸總線,集成電路內置音頻總線)。3d
5. NSS引腳:主從模式選擇,簡單瞭解,用到時再具體瞭解。code
7. 數據幀格式:可軟件設置MSB或LSB哪一個在先(SPI_CR1寄存器中LSBFIRST位),也可設置輸入輸出數據幀是8位或者16位(SPI_CR1寄存器DFF位)。orm
8. 狀態標誌位:① 發送緩衝器空閒標誌(TXE),爲1時代表發送緩衝爲空,可寫入數據,寫入後自動置0;blog
② 接受緩衝器非空(RXNE),爲1表示接收緩衝器中有有效接收數據,讀數據自動置0;圖片
③ Busy位,由硬件管理。
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);
9. SPI中斷:
10. 時鐘配置最大爲(Fpclk/2),這裏的PCLK爲PCLK1(SPI爲APB1的外設),PCLK1最大爲系統時鐘的1/2。
(貼一個剛纔百度的:SYSCLK 系統時鐘,最大72MHzHCLK :AHB總線時鐘,由系統時鐘SYSCLK 分頻獲得,通常不分頻,等於系統鍾通過總線橋AHB--APB,經過設置分頻,可由HCLK獲得 PCLK1與PCLK2時鐘不過PCLK2時鐘最高可達72MHz,而PCLK1最大36MHz。PCLK2對應APB2外設。PCLK1對應APB1外設。)
下次整理一下關於時鐘配置!!!
11. CRC校驗(可配置中斷):在發送模式下CRC位可被做爲最後一個值發送;
全雙工模式下對接收到的最後一個字節自動進行CRC校驗。
12. SPI通常配置步驟:
配置相關引腳的複用功能,使能SPIx時鐘。調用函數:void GPIO_Init();
初始化SPIx,設置SPIx工做模式。調用函數:void SPI_Init();
使能SPIx。調用函數:void SPI_Cmd();
SPI傳輸數據。調用函數:void SPI_I2S_SendData();uint16_t SPI_I2S_ReceiveData();
查看SPI傳輸狀態。調用函數:SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE
13. 相關代碼(以STM32F103x爲例):
1 #include "spi.h" 2 3 void SPI2_Init(void) 4 { 5 GPIO_InitTypeDef GPIO_InitStructure; 6 SPI_InitTypeDef SPI_InitStructure; 7 8 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB時鐘使能 9 RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPI2時鐘使能 10 11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; 12 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15¸複用推輓輸出 13 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 14 GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 15 16 GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉 17 18 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //設置SPI單向或者雙向的數據模式:雙向雙線全雙工 19 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //設置SPI工做模式爲主SPI 20 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //設置SPI數據幀大小爲8位 21 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //時鐘空閒爲高電平 22 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //時鐘極性爲1,第二個跳變沿採集數據 23 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信號由軟件或者硬件管理,軟件經過SSI位 24 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定義波特率預分頻值位256 25 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定數據傳輸從最高位開始 26 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計算的多項式,因該是說7位數據以後校驗,標記下,我去找找再補回來 27 SPI_Init(SPI2, &SPI_InitStructure); //根據指定參數初始化SPI 28 29 SPI_Cmd(SPI2, ENABLE); //使能SPI 30 31 SPI2_ReadWriteByte(0xff);//啓動傳輸發送0xff,可隨意賦值 32 33 34 } 35 //SPI 速度設置函數 36 //SpeedSet: 37 //SPI_BaudRatePrescaler_2 2分頻 38 //SPI_BaudRatePrescaler_8 8分頻 39 //SPI_BaudRatePrescaler_16 16分頻 40 //SPI_BaudRatePrescaler_256 256分頻 41 42 void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler) 43 { 44 assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler)); 45 SPI2->CR1&=0XFFC7; 46 SPI2->CR1|=SPI_BaudRatePrescaler; //根據傳入參數設置分頻係數 47 SPI_Cmd(SPI2,ENABLE); 48 49 } 50 51 //SPIx 讀寫一個字節 52 //TxData:要寫入的字節 53 //返回值:要讀取的字節 54 u8 SPI2_ReadWriteByte(u8 TxData) 55 { 56 u8 retry=0; 57 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //檢查發送緩衝器空標誌位是否爲1 58 { 59 retry++; 60 if(retry>200)return 0; 61 } 62 SPI_I2S_SendData(SPI2, TxData); //經過SPI2發送一個數據 63 retry=0; 64 65 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //檢查接收緩存是否非空 66 { 67 retry++; 68 if(retry>200)return 0; 69 } 70 return SPI_I2S_ReceiveData(SPI2); //返回經過SPIx最近接收的數據 71 }
14. 好啦好啦,祝你們都能作個美夢~~~Goodnight....