STM32第十章-SPI通訊應用


  上一章我們講到了IIC通訊,這一章來說一說SPI通信,同樣的很多模塊也用到了SPI通信,比如0.96寸的OLED模塊。玩過單片機的小夥伴都知道OLED有4針的也有7針的,4針的就是IIC通信,7針的就是SPI通信。

一、 SPI 簡介

  SPI 是英語 Serial Peripheral interface 的縮寫,顧名思義就是串行外圍設備接口。是 Motorola首先在其 MC68HCXX 系列處理器上定義的。SPI 接口主要應用在 EEPROM,FLASH,實時時鐘,AD 轉換器,還有數字信號處理器和數字信號解碼器之間。SPI是一種高速的,全雙工,同步的通信總線,並且在芯片的管腳上只佔用四根線,節約了芯片的管腳,同時爲 PCB 的佈局上節省空間,提供方便,正是出於這種簡單易用的特性,現在越來越多的芯片集成了這種通信協議,STM32 也有 SPI 接口。SPI通訊使用 3 條總線及片選線,3條總線分別爲 SCK、MOSI、MISO、SS。
在這裏插入圖片描述
  (1) SCK (Serial Clock):時鐘信號線,用於通訊數據同步。它由通訊主機STM32產生,決定了通訊的速率,不同的設備支持的最高時鐘頻率不一樣,如STM32的SPI 時鐘頻率最大爲fpclk /2,兩個設備之間通訊時,通訊速率受限於低速設備。
  (2) MOSI (Master Output, Slave Input):主設備STM32輸出/從設備輸入引腳。STM32的數據從這條信號線輸出,從機由這條信號線讀入STM32發送的數據,即這條線上數據的方向爲STM32到從機。
  (3) MISO(Master Input,,Slave Output):主設備STM32輸入/從設備輸出引腳。STM32從這條信號線讀入數據,從機的數據由這條信號線輸出到STM32,即在這條線上數據的方向爲從機到STM32。
  (4) SS( Slave Select):片選信號線,也稱爲 NSS、CS。當有多個SPI 從設備與 SPI 主機STM32相連時,設備的其它信號線 SCK、MOSI及 MISO同時並聯到相同的 SPI總線上,即無論有多少個從設備,都共同只使用這 3 條總線;而每個從設備都有獨立的這一條 NSS 信號線,本信號線獨佔主機的一個引腳,即有多少個從設備,就有多少條片選信號線。I2C 協議中通過設備地址來尋址、選中總線上的某個設備並與其進行通訊;而 SPI 協議中沒有設備地址,它使用 NSS 信號線來尋址,當主機要選擇從設備時,把該從設備的 NSS 信號線設置爲低電平,該從設備即被選中,即片選有效,接着主機開始與被選中的從設備進行 SPI 通訊。所以SPI通訊以 NSS 線置低電平爲開始信號,以 NSS 線被拉高作爲結束信號。

二、 具體代碼編寫

1.SPI引腳初始化

  我們使用 STM32 的 SPI1 的主模式,第一步就要是能 SPI1 的時鐘,SPI1 的時鐘通過 APB2ENR 的第12位來設置。其次要設置 SPI1 的相關引腳爲複用輸出,這樣纔會連接到 SPI1 上否則這些 IO 口還是默認的狀態,也就是標準輸入輸出口。這裏我們使用的是 PA5、PA6、PA7 這 3 個,所以設置這三個爲複用 IO。

void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;    
RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );	 
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);
}

2.設置SPI1工作模式

  接下來我們要初始化 SPI1,這在庫函數中是通過 SPI_Init 函數來實現的,和STM32的其他外設一樣同樣需要配置這些參數,使用中我們不需要關心這些具體的設置。設置 SPI1 爲主機模式,設置數據格式爲 8 位,然設置 SCK 時鐘極性及採樣方式。並設置 SPI1 的時鐘頻率(最大 18Mhz),以及數據的格式(MSB 在前還是LSB 在前)。這在庫函數中是通過 SPI_Init 函數來實現的。

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(SPI1, &SPI_InitStructure); //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器 

3.使能SPI1

初始化完成之後接下來是要使能 SPI1 通信了,在使能 SPI1 之後,我們就可以開始 SPI 通訊了。

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

4.使用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最近接收的數據					    
}

  本函數中不包含 SPI 起始和停止信號,只是收發的主要過程,所以在調用本函數前後要做好起始和停止信號的操作;
  循環調用庫函數SPI_I2S_GetFlagStatus 檢測事件,若檢測到事件,則進入通訊的下一階段,若未檢測到事件則停留在此處一直檢測,當檢測200次都還沒等待到事件則認爲通訊失敗,退出通訊;
  通過檢測TXE標誌,獲取發送緩衝區的狀態,若發送緩衝區爲空,則表示可能存在的上一個數據已經發送完畢;等待至發送緩衝區爲空後,調用庫函數 SPI_I2S_SendData 把要發送的數據“TxData”寫入到 SPI的數據寄存器 DR,寫入 SPI數據寄存器的數據會存儲到發送緩衝區,由 SPI外設發送出去;
  寫入完畢後通過循環200次等待RXNE 事件,即接收緩衝區非空事件。由於 SPI 雙線全雙工模式下MOSI 與 MISO 數據傳輸是同步的,當接收緩衝區非空時,表示上面的數據發送完畢,且接收緩衝區也收到新的數據;
  等待至接收緩衝區非空時,通過調用庫函數 SPI_I2S_ReceiveData 讀取 SPI 的數據寄存器 DR,就可以獲取接收緩衝區中的新數據了。代碼中使用關鍵字“return”把接收到的這個數據作爲SPI_SendByte 函數的返回值。
  以上的步驟我們就搞定了SPI 的基本收發單元,還需要了解如何對FLASH 芯片進行讀寫。FLASH 芯片自定義了很多指令,我們通過控制 STM32 利用 SPI 總線向 FLASH 芯片發送指令,FLASH芯片收到後就會執行相應的操作。而這些指令,對主機端(STM32)來說,只是它遵守最基本的 SPI 通訊協議發送出的數據,但在設備端(FLASH 芯片)把這些數據解釋成不同的意義,所以才成爲指令。查看FLASH 芯片的數據手冊可瞭解各種它定義的各種指令的功能及指令格式。這裏我就不過多的將寫了。在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章