本章將介紹CW32的IIC接口,并最終點(diǎn)亮一塊OLED屏幕,如果你對如何編寫各種模塊的驅(qū)動代碼束手無策,那本系列教程的IIC章節(jié)或許能讓你受益匪淺。
Inter-Integrated Circuit Bus,集成電路總線,簡稱IIC總線。這是一種半雙工同步總線協(xié)議,這個(gè)分類很好地概括了IIC總線的特點(diǎn):
1.作為總線協(xié)議,可以在一根“信息主干道”上接入多個(gè)通信節(jié)點(diǎn)(也就是通信設(shè)備);
2.同一時(shí)間只能有一個(gè)通信節(jié)點(diǎn)能夠在總線上講話;
3.同步傳輸意味著這種傳輸方式至少需要一根時(shí)鐘線;
IIC總線使用2根線來傳輸信號:時(shí)鐘線和數(shù)據(jù)線,相比于其他的總線協(xié)議,這種傳輸方式更節(jié)省IO資源,由于多數(shù)情況下IIC僅用于同一塊集成電路板上不同模塊之間的通信,所以它并不能傳輸很長的距離,速度也不是那么快,但硬件布線簡單,且同一塊電路板都會使用同一個(gè)電源的正負(fù)極,因此IIC總線相當(dāng)實(shí)用。
本文不會詳細(xì)介紹IIC總線的時(shí)序,這里只對其通信流程進(jìn)行概括,并著重介紹數(shù)據(jù)鏈路層的相關(guān)內(nèi)容。從流程上看,IIC總線協(xié)議的通信過程大致如下。
假設(shè)有A、B兩個(gè)設(shè)備,他們使用IIC總線協(xié)議來傳遞信息,協(xié)議規(guī)定至少要有一個(gè)設(shè)備作為主機(jī),其他設(shè)備作為從機(jī),IIC是同步通信,協(xié)議規(guī)定主機(jī)來提供時(shí)鐘,因此只有主機(jī)可以主動發(fā)起一次通信。假設(shè)現(xiàn)在A需要向B傳遞一個(gè)信息DATA,那過程就是這樣:
1.設(shè)備A發(fā)出消息“全體目光向我看齊,我宣布個(gè)事,我要開始講話了”;
2.設(shè)備A發(fā)出的“公告”會被B看到,B作為從機(jī)就會聽A接下來要說什么,從A發(fā)出“公告”開始,A就會占用總線,此時(shí)其他設(shè)備都無法在數(shù)據(jù)線上發(fā)出消息。
3.設(shè)備A需要繼續(xù)喊話,這第二次喊話,A就需要告知總線上的設(shè)備自己到底要找誰發(fā)消息,是廣播給所有人(就像全校演講那樣),還是逮住某個(gè)設(shè)備“私聊”,IIC總線使用從機(jī)地址來區(qū)分廣播和“私聊”,如果第二次喊話的內(nèi)容是廣播模式專有的“地址碼”(0x00),總線上的所有從機(jī)都會接收后續(xù)發(fā)出的數(shù)據(jù);如果第二次喊話的內(nèi)容是設(shè)備B專有的“地址碼”(一個(gè)7bit大小的數(shù)字),那這次喊話就是針對設(shè)備B的,其他的設(shè)備會發(fā)現(xiàn)點(diǎn)名私聊沒找到自己,也就會放棄對后續(xù)數(shù)據(jù)的接收。
4.假設(shè)設(shè)備A用二次喊話找到設(shè)備B進(jìn)行私聊,待B回應(yīng)一個(gè)應(yīng)答信號(ACK)之后,A就可以開始數(shù)據(jù)的傳輸,每當(dāng)B接收到A傳輸?shù)臄?shù)據(jù),B就會給A發(fā)出一個(gè)應(yīng)答信號,這個(gè)過程會持續(xù)到A完成所有數(shù)據(jù)的傳輸并發(fā)出停止信號為止——“我的話講完了,你可以掛電話了“。
如果在A不斷向B傳輸數(shù)據(jù)的過程中,B覺得自己腦子要炸了,數(shù)據(jù)太多了,需要時(shí)間消化,B可以在回發(fā)應(yīng)答信號的時(shí)候發(fā)一個(gè)“我收不了了!“(NACK),A在接收到這個(gè)信號之后,就知道B已經(jīng)接收到極限了,A就不會再發(fā)數(shù)據(jù)。之后A可以選擇開始新一輪的數(shù)據(jù)傳輸(回到過程1發(fā)起一個(gè)新的”喊話“)或者發(fā)出停止信號來直接關(guān)閉這次通信。
我們會發(fā)現(xiàn)上述過程存在很多分支選項(xiàng),整個(gè)過程就像上課一樣,“老師講課學(xué)生都聽著“、”老師點(diǎn)名某個(gè)學(xué)生回答問題“,下面我們就從具體的格式上來把上述的抽象過程給對應(yīng)上。
格式上看,任何一次完整的IIC通信需要傳輸?shù)臄?shù)據(jù)都是如下的結(jié)構(gòu):
“起始信號+從機(jī)地址|讀寫類型+ACK+數(shù)據(jù)0+ACK+數(shù)據(jù)1+ACK+數(shù)據(jù)2+……+數(shù)據(jù)N+ACK+停止信號”
起始信號=我要開始喊話了;
從機(jī)地址|讀寫類型=我要找誰講話|我要傳達(dá)or索要信息;
ACK=收到!;
數(shù)據(jù)N=需要傳達(dá)or索要的信息;
停止信號:我的話講完了;
肯定有小伙伴想問:“那IIC總線通過什么方式來表示這些信號呢?“,這些內(nèi)容屬于物理層,感興趣的小伙伴可以自行百度。
前半部分主要講解了IIC總線的過程,下面介紹具體到代碼上,單片機(jī)的IIC接口應(yīng)該如何去使用。
首先登場的還是喜聞樂見的IO和時(shí)鐘配置,需要注意的是,這里的IO輸出模式需要配置為開漏輸出,因?yàn)镮IC接口需要從IO口收發(fā)數(shù)據(jù),讀寫都在這一個(gè)IO上,開漏輸出就能滿足同時(shí)讀寫的需求。
對于IIC的配置其實(shí)相對來說比較簡單,配置好波特率(公式在結(jié)構(gòu)體的注釋里面寫好了),使能外設(shè),設(shè)置好應(yīng)答規(guī)則,最后開啟IIC外設(shè)即可。
接著就是比較重要的部分了,IIC接口的收發(fā)并不是全自動的,因?yàn)橐粋€(gè)完整的通信不僅包括發(fā)數(shù)據(jù)(地址、數(shù)據(jù)什么的),還包含收數(shù)據(jù)(啥也不干也得接收ACK信號),所以IIC通信的每個(gè)部分基本上都是收發(fā)易位的過程,IIC外設(shè)并不會自動完成這個(gè)復(fù)雜的過程,每個(gè)部分的信號是否發(fā)送、以及發(fā)送的情況都需要開發(fā)者自己去查看(開發(fā)者:改為手動操作,全部讓我來?。?。
編者寫了幾個(gè)帶自檢功能的IIC函數(shù),這幾個(gè)簡單的函數(shù)可以滿足驅(qū)動OLED的需求。
編寫這四個(gè)函數(shù)可以方便我們后續(xù)對OLED驅(qū)動的開發(fā),現(xiàn)在我要詳細(xì)說明一下這四個(gè)函數(shù)的內(nèi)在邏輯。
首先是起始信號,我們可以看到發(fā)起始信號的函數(shù)顯示打開了一個(gè)開關(guān),等待某個(gè)標(biāo)志成立之后又關(guān)掉了那個(gè)開關(guān),這里結(jié)合手冊進(jìn)行說明。IIC協(xié)議中,起始信號是“SCL維持高電平,SDA線電平拉低”這一現(xiàn)象,手冊中也有詳細(xì)描述:
又由于CW32的IIC接口并不會在起始信號發(fā)出之后自動停發(fā)起始信號,因此如果不在監(jiān)測到起始信號發(fā)出之后關(guān)閉起始信號的發(fā)送,那么數(shù)據(jù)傳輸就無法開始,IIC設(shè)備會一直發(fā)送RESTART信號來占用總線,通信就會失敗。
對于總線的狀態(tài)——“我發(fā)的信號到底成功發(fā)出去沒有呢?”,CW32提供了IIC狀態(tài)碼來指示總線狀態(tài),根據(jù)IIC設(shè)備不同的工作模式,一共會有26種總線狀態(tài),我們并不會用到全部的狀態(tài),但可能用到的狀態(tài)都可以放到枚舉類型里面,就像這樣:
以起始信號發(fā)送函數(shù)為例,其返回值就是已發(fā)送起始信號的狀態(tài)碼(0x08),如果起始信號發(fā)送失敗,死循環(huán)就無法跳出,程序死機(jī)(雖然實(shí)際上不應(yīng)該這么寫,此處只做演示,編者就小小地偷一下懶)。
視線來到發(fā)送從機(jī)地址和讀寫指令的函數(shù),就像本文前半部分講的一樣,喊話宣言之后需要指名道姓自己需要私聊的對象。從機(jī)地址本身只有7bit,占據(jù)整個(gè)字節(jié)的高7位,0號bit位表示這一次通信是為了傳達(dá)信息還是索取信息,0位為0則傳達(dá)(也就是寫),為1則索?。ㄒ簿褪亲x)。當(dāng)成功發(fā)送從機(jī)地址這一個(gè)字節(jié)之后,IIC狀態(tài)碼也會改變,對比狀態(tài)碼之后即可確認(rèn)從機(jī)地址字節(jié)發(fā)送成功并收到了從機(jī)的ACK信號,這表示從機(jī)確認(rèn)收到了這個(gè)字節(jié)的消息。
發(fā)送數(shù)據(jù)的函數(shù)和發(fā)送從機(jī)地址的函數(shù)很相似,只不過整個(gè)字節(jié)都表示數(shù)據(jù),并沒有什么獨(dú)特的含義。
最后就是發(fā)送停止信號的函數(shù),與起始信號不同,停止信號成功發(fā)出之后,總線會進(jìn)入空閑狀態(tài),并且停止信號使能位會被硬件自動清零。
捋清邏輯之后,我就要說明一個(gè)非常重要的細(xì)節(jié),仔細(xì)觀察會發(fā)現(xiàn),所有的IIC信號發(fā)送函數(shù)都有一個(gè)清除中斷標(biāo)志的操作,這里明明不是中斷,為什么要寫這個(gè)語句呢?因?yàn)镃W32的IIC接口,其發(fā)送數(shù)據(jù)的觸發(fā)條件,就是中斷標(biāo)志位被清除。根據(jù)手冊的描述,只要IIC狀態(tài)碼改變,中斷標(biāo)志位就會被硬件置位,在開啟中斷的情況下,程序會進(jìn)入中斷服務(wù)函數(shù),如果不開啟中斷,程序的執(zhí)行順序不會改變,這個(gè)標(biāo)志位也就只是一個(gè)發(fā)送開關(guān)。
這個(gè)發(fā)送邏輯某種程度上很反直覺,因?yàn)榇蟛糠值?a target="_blank">通信接口,都是拿“數(shù)據(jù)緩沖區(qū)被寫入數(shù)據(jù)”來觸發(fā)發(fā)送行為的,而此處的send函數(shù),均不具備發(fā)送功能,與其叫send_data,不如叫set_data更合適,他們的作用只是把數(shù)據(jù)裝載到IIC的數(shù)據(jù)寄存器,因此如果想要發(fā)送,就需要在清除中斷標(biāo)志位之前將數(shù)據(jù)寫入數(shù)據(jù)寄存器。手冊上也詳細(xì)描述了這一點(diǎn):
這樣一來,IIC通信就具備基本的發(fā)送功能了,對于常見的EEPROM讀寫,CW32的IIC庫提供了連續(xù)讀寫的函數(shù),開發(fā)者可以直接使用:
個(gè)人評價(jià):大部分人在需要使用IIC的時(shí)候,都會直接移植軟件模擬的IIC接口,但是在更多的地方,我還是推薦使用硬件IIC,尤其是需要使用IIC大量讀寫數(shù)據(jù)的場合。而CW32的IIC接口,在不考慮發(fā)送觸發(fā)與中斷綁定這一反直覺因素的情況下,其內(nèi)部的處理邏輯相比其他MCU的IIC接口,還是頗具優(yōu)勢的(讀者可以自行對比STM32的IIC接口,STM32的IIC讀寫邏輯不能完全手動操作,效率不夠高),尤其是每次發(fā)送之后,不必要立刻進(jìn)行下一個(gè)字節(jié)的發(fā)送,只要IIC總線還保持在建立狀態(tài),開發(fā)者可以在之后一段時(shí)間內(nèi)的任意時(shí)刻發(fā)送下一個(gè)字節(jié),這直接省去了等待發(fā)送完成的時(shí)間(當(dāng)然本文并沒有采取這種寫法),提高了程序整體的運(yùn)行效率。
-
接口
+關(guān)注
關(guān)注
33文章
8873瀏覽量
152936 -
總線
+關(guān)注
關(guān)注
10文章
2935瀏覽量
89128 -
IIC
+關(guān)注
關(guān)注
11文章
304瀏覽量
39007
發(fā)布評論請先 登錄
相關(guān)推薦

【應(yīng)用筆記】CW32 自舉程序中使用的 ISP 協(xié)議
cw32和stm32的區(qū)別
cw32和gd32的區(qū)別
應(yīng)用筆記-CW32 自舉程序中使用的 ISP 協(xié)議
【有那么點(diǎn)詳細(xì)的CW32學(xué)習(xí)筆記】通用異步收發(fā)器—發(fā)送篇

【有那么點(diǎn)詳細(xì)的CW32學(xué)習(xí)筆記】IIC接口-主機(jī)發(fā)送

【有那么點(diǎn)詳細(xì)的CW32學(xué)習(xí)筆記】IIC接口-OLED驅(qū)動

評論