當前位置:首頁>職場>spi通信時序圖詳解(spi四種工作模式時序圖)
發布時間:2024-01-24閱讀(12)
?SPI(Serial peripheral interface)即串行外圍設備接口,是由Motorola首先在其MC68HCxx系列單片機上定義的,基于高速全雙工總線的通訊協議。(又是高速,而且全雙工,確實強大)被廣泛應用于ADC、LCD等設備與MCU之間。
??跟前面學習I2C、USART一樣,學習一種協議,還是從兩個層面分析:物理層和協議層。
1. SPI物理層
SPI通訊需要使用4條線:3條總線和1條片選
圖1
??SPI還是遵循主從模式,3條總線分別是SCK、MOSI和MISO,片選線為nSS(低電平有效),SPI協議適用于一主多從的工作場景:
圖2
(1) nSS(Slave Select):片選信號線,用于選中SPI從設備。每個從設備獨立擁有這條nSS信號線,占據主機的一個引腳。設備的其他總線是并聯到SPI主機的,即無論多少個從設備,都共同使用這3條總線。當從設備上的nSS引腳被置拉低時表明該從設備被主機選中。
(2) SCK(Serial Clock):時鐘信號線,通訊數據同步用。時鐘信號由通訊主機產生,它決定了SPI的通訊速率。
(3) MOSI(Master Ouput Slave Input):主機(數據)輸出/從設備(數據)輸入引腳,即這條信號線上傳輸從主機到從機的數據。
(4) MISO(Master Input Slave Ouput):主機(數據)輸入/從設備(數據)輸出引腳,即這條信號線上傳輸從機從到主機的數據主從機通過兩條信號線來傳輸數據,那么自然是全雙工通訊的了。之前的I2C通訊,數據只在一條SDA線上傳輸,主從機數據交互只能采用半雙工。
2. SPI協議層
圖3
??如上為SPI通訊時序圖,nSS、SCK、MOSI信號均由主機產生,MISO信號由從機產生。在nSS為低電平的前提下,MOSI和MISO信號才有效,在每個時鐘周期MOSI和MISO傳輸一位數據。
跟I2C通訊類似,SPI通訊也需要通訊的起始/結束信號,有效數據和同步時鐘。
2.1 通訊的起始/結束信號
??圖中的nSS信號由高電平變為低電平即為SPI通訊的起始信號,反過來,nSS信號由低電平變為高電平即為SPI通訊的結束信號。這個可比I2C簡單得多吧。當從機檢測到自身的nSS引腳被拉低時就知道自己被主機選中,準備和主機進行通訊。
2.2 有效數據的采集
??SPI通訊的數據采集是個相對復雜的環節,先不說其他,以上圖為例:
圖中紅色框框即為有效數據被采集的時間點,”CPOL = 0″所在的脈沖信號表示的是用于進行數據同步的SCK,MOSI和MISO線上的數據在每個SCK時鐘周期傳輸一位數據,注意,數據的輸入/輸出是可以同時進行的。
??由圖可見,在SCK為奇數(更正:這里應該是偶數)邊沿(在這里該邊沿為下降沿)時,數據得到有效采樣,也就是說,在這個時刻,MISO和MOSI的數據有效,高電平表示數據1,低電平表示數據0,在其它時刻數據并無效,可以理解為為下一次MISO和MOSI的數據傳輸做準備。
??數據在傳輸中,高位在先還是低位在先,SPI協議并無明確規定,但是數據要在主從機中正確傳輸,自然雙方要先約定好,一般會采用高位在先(MSB)方式傳輸。
??這里需要再提及的概念是時鐘極性(CPOL)和時鐘相位(CPHA)。
??時鐘極性(CPOL)指通訊設備處于空閑狀態(SPI開始通訊前、nSS線無效)時,SCK的狀態。
CPOL = 0:SCK在空閑時為低電平
CPOL = 1:SCK在空閑時為高電平
1 | CPOL = 0:SCK在空閑時為低電平2 | CPOL = 1:SCK在空閑時為高電平??時鐘相位(CPHA)指數據的采樣時刻位于SCK的偶數邊沿采樣還是奇數邊沿采樣。
CPHA = 0:在SCK的奇數邊沿采樣
CPHA = 1:在SCK的偶數邊沿采樣
1 | CPHA = 0:在SCK的奇數邊沿采樣2 |CPHA = 1:在SCK的偶數邊沿采樣??那么這樣說來,SPI的采樣時刻并非由上升沿/下降沿決定的。注意的是,在數據采樣時刻,MOSI和MOSI的電平為有效電平,數據不能在這個時刻進行切換,在非采樣時刻MOSI和MISO上的信號才能切換。
??完整的時序圖如下:
圖4
圖5
??所以說,SPI有4中工作模式:
圖6
更正:工作模式3的CPOL應為1。
注意要讓主機和從機需要在相同的工作模式下,這樣才可以實現正常通訊。
下面介紹用STM32庫函數實SPI通訊代碼。
#ifndef __SPI_H#define __SPI_H#include "stm32f10x.h"/* ?¨ò?è???±?á? */void SPI2_Config(void);void SPI2_SetSpeed(uint8_t Speed);uint8_t SPI2_WriteReadData(uint8_t dat);void SPI1_Config(void);void SPI1_SetSpeed(uint8_t speed);uint8_t SPI1_WriteReadData(uint8_t dat);/***************************************************************************** Function Name : SPI1_Config* Description : 3?ê??ˉSPI2* Input : None* Output : None* Return : None****************************************************************************/void SPI1_Config(void){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure; /* SPIμ?IO?úoíSPIíaéè′ò?aê±?ó */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* SPIμ?IO?úéè?? */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //PA5.6.7é?à-/***************************************************************************//************************* éè??SPIμ?2?êy ***********************************//***************************************************************************/SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//????è???1¤SPI?£ê?SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //?÷?ú?£ê?SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8??SPISPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //ê±?óDü????μ???SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //?úμú?t??ê±?ó2é?ˉêy?YSPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //Nssê1ó?èí?t????/* ????2¨ì??ê?¤·??μ?a256 */SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//′ó×??????aê?′?ê?SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Cmd(SPI1, ENABLE);SPI_Init(SPI1, &SPI_InitStructure);} /***************************************************************************** Function Name : SPI2_Config* Description : 3?ê??ˉSPI2* Input : None* Output : None* Return : None****************************************************************************/void SPI2_Config(void){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure; /* SPIμ?IO?úoíSPIíaéè′ò?aê±?ó */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); /* SPIμ?IO?úéè?? */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);/***************************************************************************//************************* éè??SPIμ?2?êy ***********************************//***************************************************************************/SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//????è???1¤SPI?£ê?SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //?÷?ú?£ê?SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8??SPISPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //ê±?óDü????μ???SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //?úμú?t??ê±?ó2é?ˉêy?YSPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //Nssê1ó?èí?t????/* ????2¨ì??ê?¤·??μ?a256 */SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//′ó×??????aê?′?ê?SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Cmd(SPI2, ENABLE);SPI_Init(SPI2, &SPI_InitStructure);} /***************************************************************************** Function Name : SPI1_SetSpeed* Description : éè??SPI1μ?′?ê??ù?è?£* Input : ?ù?è2¨ì??ê·??μ* Output : None* Return : None****************************************************************************/void SPI1_SetSpeed(uint8_t speed){SPI1->CR1 &= 0xFFC7; SPI1->CR1 |= speed;SPI_Cmd(SPI1, ENABLE);}/***************************************************************************** Function Name : SPI2_SetSpeed* Description : éè??SPI2μ?·??μêy£?ò???±?SPI2μ??ù?è.* Input : Speed£o·??μêy* Output : None* Return : None****************************************************************************/void SPI2_SetSpeed(uint8_t Speed){SPI2->CR1 &= 0xFFC7; SPI2->CR1 |= Speed;SPI_Cmd(SPI2,ENABLE); }/***************************************************************************** Function Name : SPI1_WriteReadData* Description : ê1ó?SPI1D′è?ò???×??úêy?Yí?ê±?áè?ò???×??úêy?Y?£* Input : dat£oòaD′μ?8??êy?Y* Output : None* Return : ?áè?μ?μ?8??êy?Y****************************************************************************/uint8_t SPI1_WriteReadData(uint8_t dat){uint16_t i = 0; /* μ±·¢?í?o3??÷?? */ while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){i++;if(i > 10000){return 0xFF;}} /* ·¢?íêy?Y */ SPI_I2S_SendData(SPI1, dat);/* μè′y?óê??o3??÷?a·??? */while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); /* ???áè?μ?μ?êy?μ·μ?? */ return SPI_I2S_ReceiveData(SPI1);}/***************************************************************************** Function Name : SPI2_WriteReadData* Description : ê1ó?SPI2D′è?ò???×??úêy?Yí?ê±?áè?ò???×??úêy?Y?£* Input : dat£oD′è?μ?êy?Y* Output : None* Return : ?áè?μ?μ?êy?Y* * ?áè?ê§°ü·μ??0xFF****************************************************************************/uint8_t SPI2_WriteReadData(uint8_t dat){uint16_t i = 0; /* μ±·¢?í?o3??÷?? */ while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){i++;if(i > 10000){return 0xFF;}} /* ·¢?íêy?Y */ SPI_I2S_SendData(SPI2, dat);/* μè′y?óê??o3??÷?a·??? */while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); /* ???áè?μ?μ?êy?μ·μ?? */ return SPI_I2S_ReceiveData(SPI2);}
歡迎分享轉載→http://m.avcorse.com/read-252362.html
下一篇:紅娘是哪一部作品中的人物
Copyright ? 2024 有趣生活 All Rights Reserve吉ICP備19000289號-5 TXT地圖HTML地圖XML地圖