SMT32常見通信協議

串行通信的幾個名詞:

全雙工:數據線有2條,分別用來發送和接收。
半雙工:數據線只有1條,用來發送和接收,分時復用。
同步:時鐘線1條,在時鐘信號的控制下傳輸數據。

(1)IIC

IIC(Inter-Integrated Circuit)總線是一種由 PHILIPS 公司開發的兩線式串行總線,用于連接微控制器及其外圍設備。它是由數據線 SDA 和時鐘 SCL 構成的串行總線,SDA 可發送和接收數據,因此是一種半雙工通信。

I2C 總線在傳送數據過程中共有三種類型信號, 它們分別是:開始信號、結束信號和應答信號。
  開始信號:SCL 為高電平時,SDA 由高電平向低電平跳變,開始傳送數據。
  結束信號:SCL 為高電平時,SDA 由低電平向高電平跳變,結束傳送數據。
  應答信號:接收數據的 IC 在接收到 8bit 數據后,向發送數據的 IC 發出特定的低電平脈沖,表示已收到數據。CPU 向受控單元發出一個信號后,等待受控單元發出一個應答信號,CPU 接收到應答信號后,根據實際情況作出是否繼續傳遞信號的判斷。若未收到應答信號,由判斷為受控單元出現故障。
  這些信號中,起始信號是必需的,結束信號和應答信號,都可以不要。

①空閑狀態

IIC總線的SDA和SCL兩條信號線同時處于高電平,稱為總線的空閑狀態。兩條信號線各自的上拉電阻把電平拉高。

②開始信號和結束信號

開始信號:SCL 為高電平時,SDA 由高電平向低電平跳變,開始傳送數據。
結束信號:SCL 為高電平時,SDA 由低電平向高電平跳變,結束傳送數據。


③應答信號

發送器每發送一個字節,就在時鐘脈沖9期間釋放數據線,由接收器反饋一個應答信號。應答信號為低電平時,規定為有效應答位(ACK簡稱應答位),表示接收器已經成功地接收了該字節;應答信號為高電平時,規定為非應答位(NACK),一般表示接收器接收該字節沒有成功。對于反饋有效應答位ACK的要求是,接收器在第九個時鐘脈沖之前的低電平期間將SDA線拉低,確保在該時鐘的高電平期間為穩定的低電平。
如果接收器是主控器(即單片機接收數據),則在它收到最后一個字節后,發送一個NACK信號,以通知被控發送器結束數據發送,并釋放SDA線,以便主控接收器發送一個停止信號P。

④數據傳輸

數據的有效性:SCL為高電平期間,SDA必須保持穩定(1或0),即數據在SCL的上升沿到來之前要準備好,在SCL的下降沿到來之前要穩定。
在IIC總線上傳送的每一位數據都有一個時鐘脈沖信號相對應,即在SCL串行時鐘的配合下,在SDA上逐位地串行傳送每一位數據。數據位的傳輸是邊沿觸發。

程序代碼

參考實驗23 IIC代碼。

//單片機向IIC設備上寫數據

IIC_Start(); 

IIC_Send_Byte(0XA0);       //一般要先發送IIC設備的地址、工作模式等等
IIC_Wait_Ack();  //等待IIC設備發出ACK
IIC_Send_Byte(0X11);   //寫數據,IIC_Send_Byte()和IIC_Wait_Ack()成對出現
IIC_Wait_Ack(); 

IIC_Stop();//產生一個停止條件       
//單片機從IIC設備上讀取數據

IIC_Start(); 

IIC_Send_Byte(0XA0);       //一般還需要先對設備的地址、工作模式進行配置。可能用到幾組的IIC_Send_Byte()和IIC_Wait_Ack()。
IIC_Wait_Ack();  //等待IIC設備響應

X = IIC_Read_Byte(0);  //單片機接收一個字節,單片機發出ACK信號
Y = IIC_Read_Byte(1);   //單片機接收一個字節,單片機發出NACK信號
//ACK信號還是NACK信號,要參照IIC設備的datasheet
IIC_Stop();//產生一個停止條件   
(2)SPI

SPI 是英語 Serial Peripheral interface 的縮寫,顧名思義就是串行外圍設備接口。
SPI,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節約了芯片的管腳,同時為 PCB 的布局上節省空間,提供方便。
SPI 接口一般使用 4 條線通信:
MISO 主設備數據輸入,從設備數據輸出。
MOSI 主設備數據輸出,從設備數據輸入。
SCLK 時鐘信號,由主設備產生。
CS 從設備片選信號,由主設備控制。



主機和從機都有一個串行移位寄存器,主機通過向它的 SPI 串行寄存器寫入一個字節來發起一次傳輸。寄存器通過 MOSI 信號線將字節傳送給從機,從機也將自己的移位寄存器中的內容通過 MISO 信號線返回給主機。這樣,兩個移位寄存器中的內容就被交換。外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的字節;反之,若主機要讀取從機的一個字節,就必須發送一個空字節來引發從機的傳輸。

SPI 總線四種工作方式 SPI 模塊為了和外設進行數據交換,根據外設工作要求,其輸出串行同步時鐘極性和相位可以進行配置,時鐘極性(CPOL)對傳輸協議沒有重大的影響。如果 CPOL=0,串行同步時鐘的空閑狀態為低電平;如果 CPOL=1,串行同步時鐘的空閑狀態為高電平。時鐘相位(CPHA)能夠配置用于選擇兩種不同的傳輸協議之一進行數據傳輸。如果CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)數據被采樣;如果 CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)數據被采樣。SPI 主模塊和與之通信的外設備時鐘相位和極性應該一致。


這里我們使用的是 PB13、14、15 這 3 個(SCK.、MISO、MOSI,CS 使用軟件管理方式),所以設置這三個為復用 IO。


硬件連接圖

①配置相關引腳的復用功能,使能SPIx時鐘。

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB時鐘使能 
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上拉

實際經驗,在MISO中,也可以仍然用推挽復用輸出,而不用浮空、上拉輸入。
②初始化SPIx,設置SPI工作模式

SPI_InitTypeDef  SPI_InitStructure;

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //設置SPI單向或者雙向的數據模式:SPI設置為雙線雙向全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;       //設置SPI工作模式:設置為主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;       //設置SPI的數據大小:SPI發送接收8位幀結構
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;     //串行同步時鐘的空閑狀態為高電平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //串行同步時鐘的第二個跳變沿(上升或下降)數據被采樣
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;       //NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內部NSS信號有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;        //定義波特率預分頻的值:波特率預分頻值為256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //指定數據傳輸從MSB位還是LSB位開始:數據傳輸從MSB位開始
SPI_InitStructure.SPI_CRCPolynomial = 7;    //CRC值計算的多項式

SPI_Init(SPI2, &SPI_InitStructure);  //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器

結構體成員變量比較多,這里我們挑取幾個重要的成員變量講解一下:
第一個參數 SPI_Direction 是用來設置 SPI 的通信方式,可以選擇為半雙工,全雙工,以及串行發和串行收方式,這里我們選擇全雙工模式 SPI_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 即可。
③使能SPIx

SPI_Cmd(SPI2, ENABLE); //使能SPI外設

④然后就能通過SPI進行讀寫操作,狀態位判斷。

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ; 
SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);   // 發送完成標志位
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容