上一章所講的UART通信屬于異步通信,比如計算機發送數據給單片機,計算機只負責把數據通過TXD發送出來,接收數據是單片機自己的事情。而IIC和SPI都屬于同步通信,收發雙方需要一條時鐘線來控制收發雙方的通信節奏。
從應用上來講,UART通信多用于板間通信,比如單片機和計算機,這個設備和另外一個設備之間的通信。而IIC和SPI多用于板內通信,比如使用IIC進行單片機和EEPROM的通信,比如使用SPI進行單片機和FLASH之間的通信。
16.1 IIC總線協議
在硬件上,IIC總線是由時鐘總線SCL和數據總線SDA兩條線構成,其中SCL為時鐘線,SDA為數據線,如圖6-1所示。總線上可以同時連接多個器件,所有器件的SCL都連到一起,所有SDA都連到一起。
6-1 IIC總線時序圖
起始信號:IIC通信的起始信號的定義是SCL為高電平期間,SDA由高電平變化到低電平產生的一個下降沿,表示一次通信過程的開始,如圖6-2中的Start部分所示。
數據傳輸:IIC通信是高位在前,低位在后。IIC通信要求當SCL在低電平的時候,SDA允許變化,也就是說,發送方必須先保持SCL是低電平,才可以改變數據線SDA,輸出要發送的當前數據的一個位;而當SCL在高電平的時候,SDA絕對不可以變化,因為這個時候,接收方要來讀取當前SDA的電平信號是0還是1,因此要保證SDA的穩定,如圖6-1中的每一位數據的變化,都是在SCL的低電平位置。8位數據位后邊跟著的是一位應答位,應答位我們后邊還要具體介紹。
停止信號:IIC通信停止信號的定義是SCL為高電平期間,SDA由低電平向高電平變化產生一個上升沿,表示一次通信過程的結束,如圖6-1中的Stop部分所示。
26.2 IIC尋址模式
上一節介紹的是IIC每一位信號的時序流程,而IIC通信在字節級的傳輸中,也有固定的時序要求。IIC通信的起始信號(Start)后,首先要發送一個從機的地址,這個地址一共有7位,緊跟著的第8位是數據方向位(R/W),“0”表示接下來要發送數據(寫),“1”表示接下來是請求數據(讀)。
Kingst-32F1板子上的EEPROM器件型號是24C02,在24C02的數據手冊3.6節中可查到,24C02的7位地址中,其中高4位是固定的0b1010,而低3位的地址取決于具體電路的設計,由芯片上的A2、A1、A0這3個引腳的實際電平決定。IIC總線器件是開漏引腳,因此外部要添加上拉電阻,保證總線空閑時為高電平。來看一下24C02的電路圖,如圖6-2所示。
從圖6-2可以看出來,A2、A1、A0都是接的GND,也就是說都是0,因此24C02的7位地址實際上是二進制的0b1010000,也就是0x50。
IIC通信分為標準模式100kbit/s、快速模式400kbit/s和高速模式3.4Mbit/s。因為所有的IIC器件都支持標準模式,但卻未必支持另外兩種速度,所以作為通用的IIC程序我們選擇100k這個速率來實現,也就是說實際程序產生的時序必須小于等于100k的時序參數,有特殊速度需求的器件再針對性寫高速通信程序。
IIC引腳屬于開漏并聯結構,并且STM32的GPIO端口引腳設置為開漏輸出時,可以直接從輸入數據寄存器獲取I/O電平狀態,因此將IIC引腳配置為開漏輸出模式。由于IIC總線空閑時默認為高,初始化時還需要設置引腳輸出高電平,不過設置引腳輸出高電平并不是在初始化之后,而應該放在初始化之前。這是因為STM32在上電復位時I/O口為高阻狀態,復位結束后,GPIO端口引腳默認為浮空輸入,由于上拉電阻的存在,IIC引腳被拉高;當程序執行到IIC初始化時又被配置為開漏輸出模式,由于GPIO端口輸出數據寄存器初始值默認全為0,初始化后I/O口輸出低電平,如果初始化之后再設置引腳輸出高電平,勢必會在I/O口上產生一個低電平的毛刺。如果在IIC引腳初始化之前先設置輸出數據寄存器相應位為高,初始化IIC引腳后,I/O口會直接輸出高電平,避免毛刺信號。
以下是IIC總線的驅動程序:
26.3 初識EEPROM
在實際的應用中,保存在單片機RAM中的數據,掉電后就丟失了,保存在單片機內部FLASH中的數據,又不能隨意改變。但是在某些場合,我們需要記錄下某些數據,而它們還需要時常改變或更新,并且掉電之后數據還不能丟失,比如我們的家用電表度數,電視機里邊的頻道記憶,一般都是使用EEPROM來保存數據,特點就是掉電后不丟失。Kingst-32F1板子上使用的這個器件是24C02,是一個容量大小是2Kbits,也就是256個字節的EEPROM。一般情況下,EEPROM擁有30萬到100萬次的擦除壽命,也就是它可以反復寫入30-100萬次,而讀取次數是無限的。
24C02是一個基于IIC通信協議的器件,因此從現在開始,IIC和EEPROM就要合體了。但要分清楚,IIC是一個通信協議,它擁有嚴密的通信時序邏輯要求,而EEPROM是掉電后數據不丟失的一種存儲器件的統稱,24C02就屬于EEPROM,只不過24C02采樣了IIC協議的接口與單片機相連而已,二者并沒有必然的聯系,EEPROM可以用其它接口,IIC也可以用在其它很多器件上。
46.4 EEPROM單字節讀寫操作時序
STM32F103系列單片機本身自帶硬件IIC模塊,可以類似USART通信那樣,通過配置實現數據的收發。本書對IIC協議的介紹針對的是絕大多數的應用場合,實際上IIC的配置過程比較復雜,比如要充分考慮沖突和仲裁等處理方式,但是那些處理方式在絕大多數場合用不到。STM32F103系列自帶的IIC協議模塊設計的過于復雜,對于實際應用來講實用性不強,因此實際應用IIC時,還是用IO口直接模擬協議。本書原則就是實際開發采用何種用法,就重點介紹何種用法,下面用實例來實現一下EEPROM讀寫的基本流程。
1、EEPROM寫數據流程
第一步,首先是IIC的起始信號,接著跟上首字節,也就是前邊講的IIC的器件地址,并且在讀寫方向上選擇“寫”操作。
第二步,發送數據的存儲地址。24C02一共256個字節的存儲空間,地址從0x00~0xFF,想把數據存儲在哪個位置此刻寫的就是哪個地址。
第三步,發送要存儲的數據,注意在寫數據的過程中,EEPROM每個字節會回應一個“應答位0”,來通知用戶寫EEPROM數據成功,如果沒有回應答位,說明寫入不成功。單字節寫時序如圖6-3所示。
圖6-3 IIC Byte Write時序圖
2、EEPROM讀數據流程
第一步,首先是IIC的起始信號,接著跟上首字節,也就是前邊講的IIC的器件地址,并且在讀寫方向上選擇“寫”操作。這個地方可能有讀者會詫異,明明是讀數據為何方向也要選“寫”呢?剛才說過了,24C02一共有256個地址,選擇寫操作是為了把所要讀的數據的存儲地址先寫進去,告訴EEPROM將要讀取哪個地址的數據。這就如同打電話,先撥總機號碼(EEPROM器件地址),而后還要繼續撥分機號碼(數據地址),而撥分機號碼這個動作,主機仍然是發送方,方向依然是“寫”。
第二步,發送要讀取的數據的地址,注意是地址而非存在EEPROM中的數據,通知EEPROM要哪個分機的信息。
第三步,重新發送IIC起始信號和器件地址,并且在方向位選擇“讀”操作。
這三步當中,每一個字節實際上都是在“寫”,所以每一個字節EEPROM都會回應一個“應答位0”。
第四步,讀取從器件發回的數據,讀一個字節,如果還想繼續讀下一個字節,就發送一個“應答位ACK(0)”,如果不想讀了,告訴EEPROM,不想要數據了,別再發數據了,那就發送一個“非應答位NAK(1)”。
每讀一個字節,地址會自動加1,那如果想繼續往下讀,給EEPROM一個ACK(0)低電平,那再繼續給SCL完整的時序,EEPROM會繼續往外送數據。如果不想讀了,要告訴EEPROM不要數據了,直接發送一個NAK(1)高電平。24C02讀數據時序如圖6-4所示。
圖6-4 IIC Read時序圖
利用EEPROM單字節讀寫功能設計了一個記錄開發板復位次數的小程序。由于EEPROM中的數據很容易被擦除或者改寫,為了保證記錄數據的準確性,需要對讀出的數據進行校驗。這里向大家介紹一種簡單又實用的校驗方法:將復位次數保存在EEPROM地址0x00中,并對復位次數按位取反后保存在地址0x01中。開發板每次復位后先去讀取地址0x00和0x01中的數據,對其進行異或運算,如果運算結果為0xFF,表明數據正確,將地址0x00中的數據加1后,重新寫入到EEPROM中,并通過數碼管顯示讀出的數據;否則記錄的數據被改寫,從0開始重新記錄復位次數。由于板載數碼管僅能顯示兩位數,記錄的最大次數為99,超過99重新開始記錄。具體代碼如下:
56.5 EEPROM多字節讀寫操作時序
讀取EEPROM很簡單,EEPROM根據時序直接把數據送出來,但是寫EEPROM卻沒有這么簡單了。給EEPROM發送數據后,先保存在EEPROM的緩存,EEPROM必須要把緩存中的數據搬移到“非易失”的區域,才能達到掉電不丟失的效果。而往非易失區域寫需要一定的時間,每種器件不完全一樣,ATMEL公司的24C02的這個寫入時間最長不超過5ms。在往非易失區域寫的過程,EEPROM是不會再響應用戶訪問的,不僅接收不到用戶的數據,即使用I^2^C標準的尋址模式去尋址,EEPROM都不會應答,就如同這個總線上沒有這個器件一樣。數據寫入非易失區域完畢后,EEPROM再次恢復正常,可以正常讀寫了。
在向EEPROM連續寫入多個字節的數據時,如果每寫一個字節都要等待幾ms的話,整體上的寫入效率就太低了。因此EEPROM的廠商就想了一個辦法,把EEPROM分頁管理。24C01、24C02這兩個型號是8個字節一個頁,24C04、24C08、24C16是16個字節一頁。Kingst-32F1開發板上用的型號是24C02,一共是256個字節,8個字節一頁,那么就一共有32頁。
分配好頁之后,如果在同一個頁內連續寫入幾個字節后,最后再發送停止位的時序。EEPROM檢測到這個停止位后,會一次性把這一頁的數據寫到非易失區域,就不需要寫一個字節檢測一次了,并且頁寫入的時間也不會超過5ms。如果寫入的數據跨頁了,寫完一頁之后要發送一個停止位,然后等待并且檢測EEPROM的空閑模式,一直等到把上一頁數據完全寫到非易失區域后,再進行下一頁的寫入,這樣就可以在很大程度上提高數據的寫入效率,頁寫時序如圖6-5所示。
圖6-5 EEPROM頁寫時序
本節利用EEPROM多字節讀寫功能設計了一個通過串口發送指令控制EEPROM讀寫數據的例程。該例程只需要下載一次程序,就能通過串口調試助手實現對EEPROM任意地址的讀寫操作,避免重復編程控制EEPROM讀寫數據的方式,具有很高是實用意義。與第五章串口實用例程類似,通過串口調試助手發送控制指令,單片機檢測到指令后做出相應動作。
EEPROM讀數據指令格式:“e2read 地址 字節長度”,其中地址范圍為0~255,e2read、地址、字節長度之間由空格隔開,比如從地址1開始讀取5字節數據:e2read 1 5。單片機收到指令后執行多字節讀操作,通過串口助手返回讀出的數據。
EEPROM寫數據指令格式:“e2write 地址 數據”,地址范圍為0~255,e2write、地址、數據之間同樣由空格隔開,比如從地址1開始寫入hello:e2write 1 hello。單片機收到指令后執行多字節寫操作,寫入成功后通過串口助手返回“e2write done.”
如果發送指令格式錯誤,返回“bad parameter.”,如果發送指令錯誤,將返回發送的指令。
-
單片機
+關注
關注
6032文章
44525瀏覽量
633260 -
SPI
+關注
關注
17文章
1701瀏覽量
91345 -
EEPROM
+關注
關注
9文章
1010瀏覽量
81413 -
IIC
+關注
關注
11文章
300瀏覽量
38277 -
uart
+關注
關注
22文章
1228瀏覽量
101199
發布評論請先 登錄
相關推薦
評論