能將處理器的GPIO(General Purpose Input and Output)內(nèi)部結(jié)構(gòu)和各種模式徹底弄清楚的人并不多,最近在百度上搜索了大量關(guān)于這部分的資料,對于其中很多問題的說法并不統(tǒng)一。本文盡可能的將IO涉及到的所有問題羅列出來,對于有明確答案的問題解釋清楚,對于還存在疑問的地方也將問題提出,供大家討論。
概括地說,IO的功能模式大致可以分為輸入、輸出以及輸入輸出雙向三大類。其中作為基本輸入IO,相對比較簡單,主要涉及的知識點(diǎn)就是高阻態(tài);作為輸出IO,相比于輸入復(fù)雜一些,工作模式主要有開漏(Open Drain)模式和推挽(Push-Pull)模式,這一部分涉及的知識點(diǎn)比較多;對于輸入輸出IO,容易產(chǎn)生疑惑的地方是準(zhǔn)雙向和雙向端口的區(qū)別。
下面就按照這樣的順序依次介紹各個(gè)模式的詳細(xì)情況。
輸入IO
這里所說的輸入IO,指的是只作為輸入,不具有輸出功能。此時(shí)對于input引腳的要求就是高阻(高阻與三態(tài)是同一個(gè)概念)。基本輸入電路的類型大致可以分為3類:基本輸入IO電路、施密特觸發(fā)輸入電路以及弱上拉輸入電路。
先從最基本的基本輸入IO電路說起,其電路如圖 1所示。
圖 1
其中的緩沖器U1是具有控制輸入端,且具有高阻抗特性的三態(tài)緩沖器。通俗地說就是這個(gè)緩沖器對外來說是高阻的,相當(dāng)于在控制輸入端不使能的情況下,物理引腳與內(nèi)部總線之間是完全隔離的,完全不會影響內(nèi)部電路。而控制輸入端的作用就是可以發(fā)出讀Pin狀態(tài)的操作指令。其過程如圖 2所示。
圖 2
這種基本電路的一個(gè)缺點(diǎn)是在讀取外部信號的跳變沿時(shí)會出現(xiàn)抖動,如下圖所示。
圖 3
于是施密特觸發(fā)輸入電路就是解決了上述這種抖動的問題,其經(jīng)過施密特觸發(fā)器后的信號如圖 4所示。
圖 4
對于輸入電路還存在另外一個(gè)問題,就是當(dāng)輸入引腳懸空的時(shí)候,輸入端檢測到的電平是高還是低?當(dāng)輸入信號沒有被驅(qū)動,即懸空(Floating)時(shí),輸入引腳上任何的噪聲都會改變輸入端檢測到的電平,如圖 5所示。
圖 5
為了解決這個(gè)問題,可以在輸入引腳處加一個(gè)弱上拉電阻,如圖 6所示。
圖 6
這樣,當(dāng)輸入引腳懸空時(shí),會被RP上拉到高電平,在內(nèi)部總線上就有確定的狀態(tài)了。
但是這種結(jié)構(gòu)是有一定問題的。首先很明顯的一點(diǎn)是,當(dāng)輸入引腳懸空時(shí)讀到的是1,當(dāng)輸入引腳被高電平驅(qū)動時(shí)讀到的也是1,只有當(dāng)輸入引腳被低電平驅(qū)動時(shí)讀到的才是0。也就是對于讀1采取的方式是"讀取非零"的方式。
另一個(gè)問題是該電路對外呈現(xiàn)的不是高阻,某種意義上說也在向外輸出,當(dāng)外部驅(qū)動電路不同時(shí)可能出現(xiàn)錯(cuò)誤的檢測結(jié)果。例如外部驅(qū)動電路是如圖 7所示的結(jié)構(gòu),該電路結(jié)構(gòu)中通過K打到不同端可以輸出高電平或者低電平。
圖 7
如果將如圖 7所示的電路輸出低電平,連接到帶有弱上拉電阻的輸入引腳,其結(jié)構(gòu)如下所示。
圖 8
由歐姆定律知,測試點(diǎn)處的電平是,于是CPU測得的輸入信號為高,而外部驅(qū)動電路希望輸出的電平為低。這種錯(cuò)誤的原因就在于這種結(jié)構(gòu)的輸入電路并不是真正的高阻,或者說這個(gè)輸入IO其實(shí)也在輸出,而且影響了外部輸入電路。
這種情況的發(fā)生也說明了:信號前后兩級傳遞,為什么需要輸出阻抗小,輸入阻抗大的原因。在這個(gè)例子中,外圍驅(qū)動電路的輸出阻抗很大,達(dá)到了100Kohm;而輸入端的阻抗又不夠大,只有10Kohm,于是就出現(xiàn)了問題。如果輸入端的輸入阻抗真正做到高阻(無窮大),如下所示,就不會出現(xiàn)問題。
圖 9
上面提到的這個(gè)帶弱上拉的輸入電路,也就是在后續(xù)章節(jié)會提到的準(zhǔn)雙向端口的情況。
輸出IO
IO輸出電路最主要的兩種模式分別是推挽輸出(Push-Pull Output)和開漏輸出(Open Drain Output)。
推挽輸出(Push-Pull Output)
推挽輸出的結(jié)構(gòu)是由兩個(gè)三極管或者M(jìn)OS管受到互補(bǔ)信號的控制,兩個(gè)管子始終保持一個(gè)處于截止,另一個(gè)處于導(dǎo)通的狀態(tài)。如圖 10所示。
圖 10
推挽輸出的最大特點(diǎn)是可以真正能真正的輸出高電平和低電平,在兩種電平下都具有驅(qū)動能力。
補(bǔ)充說明:所謂的驅(qū)動能力,就是指輸出電流的能力。對于驅(qū)動大負(fù)載(即負(fù)載內(nèi)阻越小,負(fù)載越大)時(shí),例如IO輸出為5V,驅(qū)動的負(fù)載內(nèi)阻為10ohm,于是根據(jù)歐姆定律可以正常情況下負(fù)載上的電流為0.5A(推算出功率為2.5W)。顯然一般的IO不可能有這么大的驅(qū)動能力,也就是沒有辦法輸出這么大的電流。于是造成的結(jié)果就是輸出電壓會被拉下來,達(dá)不到標(biāo)稱的5V。
當(dāng)然如果只是數(shù)字信號的傳遞,下一級的輸入阻抗理論上最好是高阻,也就是只需要傳電壓,基本沒有電流,也就沒有功率,于是就不需要很大的驅(qū)動能力。
對于推挽輸出,輸出高、低電平時(shí)電流的流向如圖 11所示。所以相比于后面介紹的開漏輸出,輸出高電平時(shí)的驅(qū)動能力強(qiáng)很多。
圖 11
但推挽輸出的一個(gè)缺點(diǎn)是,如果當(dāng)兩個(gè)推挽輸出結(jié)構(gòu)相連在一起,一個(gè)輸出高電平,即上面的MOS導(dǎo)通,下面的MOS閉合時(shí);同時(shí)另一個(gè)輸出低電平,即上面的MOS閉合,下面的MOS導(dǎo)通時(shí)。電流會從第一個(gè)引腳的VCC通過上端MOS再經(jīng)過第二個(gè)引腳的下端MOS直接流向GND。整個(gè)通路上電阻很小,會發(fā)生短路,進(jìn)而可能造成端口的損害。這也是為什么推挽輸出不能實(shí)現(xiàn)" 線與"的原因。
開漏輸出(Open Drain Output)
常說的與推挽輸出相對的就是開漏輸出,對于開漏輸出和推挽輸出的區(qū)別最普遍的說法就是開漏輸出無法真正輸出高電平,即高電平時(shí)沒有驅(qū)動能力,需要借助外部上拉電阻完成對外驅(qū)動。下面就從內(nèi)部結(jié)構(gòu)和原理上說明為什么開漏輸出輸出高電平時(shí)沒有驅(qū)動能力,以及進(jìn)一步比較與推挽輸出的區(qū)別。
首先需要介紹一些開漏輸出和開集輸出。這兩種輸出的原理和特性基本是類似的,區(qū)別在于一個(gè)是使用MOS管,其中的"漏"指的就是MOS管的漏極;另一個(gè)使用三極管,其中的"集"指的就是MOS三極管的集電極。這兩者其實(shí)都是和推挽輸出相對應(yīng)的輸出模式,由于使用MOS管的情況較多,很多時(shí)候就用"開漏輸出"這個(gè)詞代替了開漏輸出和開集輸出。
介紹就先從開集輸出開始,其原理電路結(jié)如圖 12所示。
圖 12
圖 12左邊的電路是開集(OC)輸出最基本的電路,當(dāng)輸入為高電平時(shí),NPN三極管導(dǎo)通,Output被拉到GND,輸出為低電平;當(dāng)輸入為低電平時(shí),NPN三極管閉合,Output相當(dāng)于開路(輸出高阻)。高電平時(shí)輸出高阻(高阻、三態(tài)以及floating說的都是一個(gè)意思),此時(shí)對外沒有任何的驅(qū)動能力。這就是開漏和開集輸出最大的特點(diǎn),如何利用該特點(diǎn)完成各種功能稍后介紹。這個(gè)電路雖然完成了開集輸出的功能,但是會出現(xiàn)input為高,輸出為低;input為低,輸出為高的情況。
圖 12右邊的電路中多使用了一個(gè)三極管完成了"反相"。當(dāng)輸入為高電平時(shí),第一個(gè)三極管導(dǎo)通,此時(shí)第二個(gè)三極管的輸入端會被拉到GND,于是第二個(gè)三極管閉合,輸出高阻;當(dāng)輸入為低電平時(shí),第一個(gè)三極管閉合,此時(shí)第二個(gè)三極管的輸入端會被上拉電阻拉到高電平,于是第二個(gè)三極管導(dǎo)通,輸出被拉到GND。這樣,這個(gè)電路的輸入與輸出是同相的了。
接下來介紹開漏輸出的電路,如圖 13所示。原理與開集輸出基本相同,只是將三極管換成了MOS而已。
圖 13
接著說說開漏、開集輸出的特點(diǎn)以及應(yīng)用,由于兩者相似,后文中若無特殊說明,則用開漏表示開漏和開集輸出電路。
-
開漏輸出最主要的特性就是高電平?jīng)]有驅(qū)動能力,需要借助外部上拉電阻才能真正輸出高電平,其電路如圖 14所示。
圖 14
當(dāng)MOS管閉合時(shí),開漏輸出電路輸出高電平,且連接著負(fù)載時(shí),電流流向是從外部電源,流經(jīng)上來電阻RPU,流進(jìn)負(fù)載,最后進(jìn)入GND。
-
開漏輸出的這一特性一個(gè)明顯的優(yōu)勢就是可以很方便的調(diào)節(jié)輸出的電平,因?yàn)檩敵鲭娖酵耆缮侠娮柽B接的電源電平?jīng)Q定。所以在需要進(jìn)行電平轉(zhuǎn)換的地方,非常適合使用開漏輸出。
- 開漏輸出的這一特性另一個(gè)好處在于可以實(shí)現(xiàn)"線與"功能,所謂的"線與"指的是多個(gè)信號線直接連接在一起,只有當(dāng)所有信號全部為高電平時(shí),合在一起的總線為高電平;只要有任意一個(gè)或者多個(gè)信號為低電平,則總線為低電平。而推挽輸出就不行,如果高電平和低電平連在一起,會出現(xiàn)電流倒灌,損壞器件。
推挽與開漏輸出的區(qū)別
圖 15
雙向IO
很多處理器的引腳可以設(shè)置為雙向端口,雙向端口的要求就是既可以輸出信號,又可以讀回外部信號輸入。要同時(shí)做到這兩點(diǎn)從原理上來說有點(diǎn)困難,首先從處理器的開漏輸出IO口的內(nèi)部結(jié)構(gòu)說起,如圖 16所示。
圖 16
該結(jié)構(gòu)是在圖 13的基礎(chǔ)上,在三極管之前加入了一個(gè)FF,目的是用于控制輸出信號的時(shí)間。比較常見的一個(gè)應(yīng)用場合是多個(gè)IO作為一個(gè)總線時(shí),需要總線上的各個(gè)引腳同時(shí)將數(shù)據(jù)輸出。
對于開漏輸出結(jié)構(gòu),會將FF的輸出Q端連接會輸入驅(qū)動緩沖器,這樣的話執(zhí)行讀操作是讀的并不是外部引腳的狀態(tài),而是自己輸出的狀態(tài)。
雙向開漏IO
但是對圖 16的結(jié)構(gòu)稍作修改,如圖 17所示時(shí),該結(jié)構(gòu)稱為雙向開漏IO的結(jié)構(gòu)。所做的改動是將輸入驅(qū)動緩沖器連接到了PIN上。
圖 17
該結(jié)構(gòu)輸出為"1"時(shí),T1斷開,此時(shí)pin對外呈現(xiàn)高阻,作為輸入引腳沒有任何問題。但是如果該結(jié)構(gòu)輸出"0"時(shí),T1導(dǎo)通,此時(shí)pin對外短路到地,即無論外部輸入什么信號,U2讀回的全部是低。所以對于這樣的結(jié)構(gòu),如果需要作為輸入引腳使用時(shí),必須給U1輸出"1"后才能讀取外部引腳數(shù)據(jù)。
準(zhǔn)雙向開漏IO
很多文獻(xiàn)中還提到了準(zhǔn)雙向端口,其實(shí)準(zhǔn)雙向端口就是圖 17的結(jié)構(gòu)中加了一個(gè)上拉電阻,如圖 18所示。
圖 18
這個(gè)結(jié)構(gòu)與圖 17相比有以下相同與不同之處:
-
作為輸入引腳使用時(shí),也必須先向U1中寫"1",以達(dá)到斷開T1的目的。所以是否需要提前寫"1"并不是雙向IO與準(zhǔn)雙向IO的區(qū)別。兩者做輸入端口時(shí)都需要提前寫"1"。
-
雙向端口作為輸入時(shí)是真正的高阻態(tài),而準(zhǔn)雙向IO作為輸入端口時(shí),輸入阻抗不為高阻,于是有可能出現(xiàn)如本文圖 8所示的問題。
-
準(zhǔn)雙向端口讀取輸入狀態(tài),默認(rèn)為高。也就是判斷外部輸入信號的方法是"非低則為高"。即該結(jié)構(gòu)只能準(zhǔn)確的識別外部的低電平,無法區(qū)分懸空和真正的高。于是只要讀到的不是0,都認(rèn)為外部為1。
推挽輸出作為雙向IO
如果雙向端口中的輸出部分采用的是推挽輸出結(jié)構(gòu),那么作為輸入時(shí)必須將上下兩個(gè)管子全部端口才能成為高阻,作為輸入。
51單片機(jī)的P0端口
在雙向端口的討論中,比較復(fù)雜的就是51單片機(jī)的P0端口了。這里就詳細(xì)討論一下51單片機(jī)的P0端口結(jié)構(gòu)和工作原理。
P0端口的內(nèi)部結(jié)構(gòu)如圖 19所示。
圖 19
內(nèi)部結(jié)構(gòu)比較復(fù)雜,包括以下這些器件:
-
U1:與門。一個(gè)輸入連著控制線,另一個(gè)輸入連接這地址/數(shù)據(jù)信號。由于與門的特性,當(dāng)控制線為1時(shí),與門輸出與地址/數(shù)據(jù)信號的電平保持一致;如果控制線為0,則輸出恒為。于是控制信號線相當(dāng)于與門的使能信號。
-
U2:反相器,輸出信號為地址/數(shù)據(jù)信號的反相信號。
-
U3和U6都是具有控制輸入端且具有高阻抗特性的三態(tài)緩沖器,作用是對于外部呈現(xiàn)高阻態(tài)。當(dāng)控制端使能時(shí)可以將外部信號的電平讀進(jìn)數(shù)據(jù)總線。
-
U4:為鎖存器,目的就是控制引腳輸出信號的時(shí)間。
-
U5:模擬開關(guān),可以控制V2的輸入信號是來自鎖存器U4的Q非輸出還是來自于反相器U2的輸出。
-
V1和V2分別是兩個(gè)MOS管。
了解了各個(gè)獨(dú)立器件之后就開始介紹工作在各個(gè)模式下的工作原理:
P0用于地址/數(shù)據(jù)線時(shí):
在P0作為地址/數(shù)據(jù)線時(shí),是地址、數(shù)據(jù)復(fù)用總線,P0需要輸出地址,同時(shí)需要讀回?cái)?shù)據(jù)信號。
當(dāng)P0需要輸出地址信息時(shí),U1的控制信號為0,模擬開關(guān)U5接到U2反相器的輸出。于是當(dāng)?shù)刂沸盘柧傳來的信號為1,與控制線"1"相與之后輸出到V1的輸入信號為"1",V1截止。地址信號"1"經(jīng)反相之后,通過模擬開關(guān)輸出到V2的輸入端為"0",V2導(dǎo)通,于是情況如圖 20所示,pin輸出"0"。
圖 20
當(dāng)?shù)刂沸盘柧傳來的信號為1,與控制線"1"相與之后輸出到V1的輸入信號為"0",V1導(dǎo)通。地址信號"0"經(jīng)反相之后,通過模擬開關(guān)輸出到V2的輸入端為"1",V2截止,于是情況如圖 21所示,pin輸出"1"。
圖 21
于是在作為地址線輸出時(shí),V1、V2兩個(gè)MOS管均使用了,是推挽輸出。
當(dāng)P0在輸出低8位地址信息后,將變?yōu)閿?shù)據(jù)總線,此時(shí)CPU的操作是控制端輸出0,模擬開關(guān)打到鎖存器的Q非端,且向鎖存器中打入"1"。于是Q非輸出為0,V2截止。同時(shí)控制線為0使得與門輸出為0,V1截止。由于V1和V2都截止,所以此時(shí)pin對外完全呈現(xiàn)高阻,作為輸入端口,外部數(shù)據(jù)通過U6進(jìn)入內(nèi)部總線,情況如圖 22所示。(相當(dāng)于將推挽輸出的兩個(gè)MOS管全部斷開了)此時(shí)由于對外呈現(xiàn)高阻,所以是真正的輸入引腳。這就解釋了為什么說P0是真正的雙線端口。
圖 22
P0用于普通IO時(shí):
在P0作為普通IO并作為輸出時(shí),控制信號為0,使V1始終處于截止?fàn)顟B(tài)。模擬開關(guān)連接到Q非輸出,當(dāng)作為輸出時(shí),鎖存器的輸入端直接輸入0或者1,Q非將反相信號輸入到V2的輸入端。即當(dāng)輸出"0"時(shí),V2輸入端為"1",V2導(dǎo)通,pin輸出"0";當(dāng)輸出"1"時(shí),V2輸入端為"0",V2截止,pin輸出高阻的0。即當(dāng)P0工作在普通IO模式下,輸出為開漏輸出,且內(nèi)部沒有上拉電阻。
在P0作為普通IO并作為輸入時(shí),控制信號為0,使V1始終處于截止?fàn)顟B(tài)。模擬開關(guān)連接到Q非輸出,且CPU自動向鎖存器輸入端寫1,則V2輸入端為0,V2截止。與之前在作為地址/數(shù)據(jù)線,作為輸入時(shí)一樣,也是兩個(gè)MOS管全部斷開,pin直接連接到U6,對外呈現(xiàn)高阻。于是也是真正的輸入引腳。
綜上P0無論工作在哪種模式下都是真正的雙端口IO。
51單片機(jī)的P1~P3端口
51單片機(jī)的其他三個(gè)端口的內(nèi)部結(jié)構(gòu)如圖 23所示,與P0相比簡單了很多,沒有了頂部的MOS管,也沒有了地址/數(shù)據(jù)信號的選項(xiàng)。作為輸出時(shí)是帶有上拉電阻的的開漏輸出,作為輸入時(shí)是有上拉電阻存在的,于是輸入端口對外不是高阻。這就解釋了為什么P1~P3只能是準(zhǔn)雙向端口。
圖 23