其實關(guān)于GPIO模式,手冊有非常詳細的說明,可見好好查看Datasheet有多么重要!!
首先關(guān)于stm32的GPIO口有輸入輸出之分,這點與51單片機使用的雙向IO口有區(qū)別,這就需要根據(jù)我們具體是輸入還是輸出配置為相應(yīng)的輸入輸出模式。輸入就是輸入模式,輸出就是輸出模式,兩者不能混用。
下面這段話是手冊這么描述GPIO口的:
通用I/O(GPIO)
復(fù)位期間和剛復(fù)位后,復(fù)用功能未開啟,I/O端口被配置成浮空輸入模式(CNFx[1:0]=01b,
MODEx[1:0]=00b)。
復(fù)位后,JTAG引腳被置于輸入上拉或下拉模式:
─PA15:JTDI置于上拉模式
─PA14:JTCK置于下拉模式
─PA13:JTMS置于上拉模式
─PB4:JNTRST置于上拉模式
當作為輸出配置時,寫到輸出數(shù)據(jù)寄存器上的值(GPIOx_ODR)輸出到相應(yīng)的I/O引腳??梢砸酝?br/>挽模式或開漏模式(當輸出0時,只有N-MOS被打開)使用輸出驅(qū)動器。
輸入數(shù)據(jù)寄存器(GPIOx_IDR)在每個APB2時鐘周期捕捉I/O引腳上的數(shù)據(jù)。
所有GPIO引腳有一個內(nèi)部弱上拉和弱下拉,當配置為輸入時,它們可以被激活也可以被斷開
從上面的描述我們知道,單片機復(fù)位后默認是浮空輸入模式,但是JTAG的引腳會被設(shè)置為輸入上拉或者下拉模式。輸出模式下是輸出寄存器ODR的輸出到對應(yīng)IO口實現(xiàn)高低電平。
輸入配置
當I/O端口配置為輸入時:
● 輸出緩沖器被禁止
● 施密特觸發(fā)輸入被激活
● 根據(jù)輸入配置(上拉,下拉或浮動)的不同,弱上拉和下拉電阻被連接
● 出現(xiàn)在I/O腳上的數(shù)據(jù)在每個APB2時鐘被采樣到輸入數(shù)據(jù)寄存器
● 對輸入數(shù)據(jù)寄存器的讀訪問可得到I/O狀態(tài)
參見手冊關(guān)于輸入配置這幾點很重要。
1)當作為輸入時,輸出數(shù)據(jù)寄存器與IO口之間是斷開的,這也就意味著我們在輸入狀態(tài)下即使操作輸出數(shù)據(jù)寄存器對IO口也沒有影響。比如我們用庫函數(shù)各種直接或間接改變輸出數(shù)據(jù)寄存器的操作都是無效的。比如我們設(shè)置在初始化某IO為上拉輸入后,又將該IO口輸出為0,將這輸出為0的操作是完全無效不起作用的!比如你設(shè)置為輸入去用萬用表測IO口就很可笑的操作?。?/p>
2)IO口的數(shù)據(jù)在每個APB2時鐘被采樣到輸入數(shù)據(jù)寄存器,這就意味著我們比如當前模式為輸入模式,那么在72M系統(tǒng)時鐘下,約每13ns會更新一次輸入數(shù)據(jù)。比如我們在寫某些通信接口時序,在設(shè)置為輸入模式下就要留個心看看是否數(shù)據(jù)能否在讀命令下是否13ns該通信方式是否有效數(shù)據(jù)已經(jīng)到達保證讀取 的是準確值,是否需加延時(針對通信數(shù)據(jù)更新慢的情況)。
3)注意我們設(shè)置為浮空、上拉還是下拉輸入,在沒有接外設(shè)的情況下,這些狀態(tài)才是確定的。比如我們說浮空模式下,輸入值不確定可能為0可能為1,上拉輸入時輸入數(shù)據(jù)寄存器為1,下拉輸入時輸入數(shù)據(jù)寄存器值為0均是針對前提是在未接任何外設(shè)情況下來說的!我們測開發(fā)板一定要先確定引腳是否有外設(shè)影響!
4)STM32為弱上拉和弱下拉,也就是上拉電阻阻值很大,未接外設(shè)時輸入數(shù)據(jù)寄存器為1,這樣有利于檢測低電平輸入;同理,下拉輸入未接外設(shè)輸入數(shù)據(jù)寄存器為0,有利于我們檢測高電平輸入。而對于外設(shè)電平可高可低的輸入,我們設(shè)置為浮空輸入即可。
5)輸入數(shù)據(jù)寄存器為只讀,在硬件仿真時值是屏蔽表示不可修改,但是值是準確的!需要注意的是,硬件仿真輸入模式下去查看輸入寄存器IDR沒意義,輸出模式下去查看輸出數(shù)據(jù)寄存器ODR也沒意義。
輸出配置
當I/O端口被配置為輸出時:
● 輸出緩沖器被激活
─開漏模式:輸出寄存器上的’0’激活N-MOS,而輸出寄存器上的’1’將端口置于高阻狀態(tài)(PMOS從不被激活)。
─推挽模式:輸出寄存器上的’0’激活N-MOS,而輸出寄存器上的’1’將激活P-MOS。
● 施密特觸發(fā)輸入被激活
● 弱上拉和下拉電阻被禁止
● 出現(xiàn)在I/O腳上的數(shù)據(jù)在每個APB2時鐘被采樣到輸入數(shù)據(jù)寄存器
● 在開漏模式時,對輸入數(shù)據(jù)寄存器的讀訪問可得到I/O狀態(tài)
● 在推挽式模式時,對輸出數(shù)據(jù)寄存器的讀訪問得到最后一次寫的值。
參見手冊關(guān)于輸出配置這段話我們需要注意這幾點:
1)在輸出模式下,輸入寄存器與IO口之間并未屏蔽,并且在開漏輸出模式下,我們讀輸入數(shù)據(jù)寄存器的操作可以真實的讀取我們輸入口的狀態(tài)(盡管不建議輸出模式和輸入混用,但是具有這樣的性質(zhì)是要注意的)
2)開漏輸出的特點如果要控制外設(shè),則必須外接上拉電阻,因為其自身不具備輸出高電平的能力,只能輸出低電平,當然這種需外接上拉電阻的模式也實現(xiàn)我們可輸出我們想要的任意“高電平”,比如5V外接5V上拉即可;而推挽輸出則可輸出可高可低電平。(欲了解見下文)
單片機I/O口推挽與開漏輸出詳解:
推挽輸出:可以輸出高,低電平,連接數(shù)字器件;推挽結(jié)構(gòu)一般是指兩個三極管分別受兩互補信號的控制,總是在一個三極管導(dǎo)通的時候另一個截止.
開漏輸出:輸出端相當于三極管的集電極. 要得到高電平狀態(tài)需要上拉電阻才行. 適合于做電流型的驅(qū)動,其吸收電流的能力相對強(一般20ma以內(nèi)).
我們先來說說集電極開路輸出的結(jié)構(gòu)。集電極開路輸出的結(jié)構(gòu)如圖1所示,右邊的那個三極管集電極什么都不接,所以叫做集電極開路(左邊的三極管為反相之用,使輸入為“0”時,輸出也為“0”)。對于圖1,當左端的輸入為“0”時,前面的三極管截止(即集電極C跟發(fā)射極E之間相當于斷開),所以5V電源通過1K電阻加到右邊的三極管上,右邊的三極管導(dǎo)通(即相當于一個開關(guān)閉合);當左端的輸入為“1”時,前面的三極管導(dǎo)通,而后面的三極管截止(相當于開關(guān)斷開)。
我們將圖1簡化成圖2的樣子。圖2中的開關(guān)受軟件控制,“1”時斷開,“0”時閉合。很明顯可以看出,當開關(guān)閉合時,輸出直接接地,所以輸出電平為0。而當開關(guān)斷開時,則輸出端懸空了,即高阻態(tài)。這時電平狀態(tài)未知,如果后面一個電阻負載(即使很輕的負載)到地,那么輸出端的電平就被這個負載拉到低電平了,所以這個電路是不能輸出高電平的。
再看圖三。圖三中那個1K的電阻即是上拉電阻。如果開關(guān)閉合,則有電流從1K電阻及開關(guān)上流過,但由于開關(guān)閉其它三個口帶內(nèi)部上拉),當我們要使用輸入功能時,只要將輸出口設(shè)置為1即可,這樣就相當于那個開關(guān)斷開,而對于P0口來說,就是高阻態(tài)了。
對于漏極開路(OD)輸出,跟集電極開路輸出是十分類似的。將上面的三極管換成場效應(yīng)管即可。這樣集電極就變成了漏極,OC就變成了OD,原理分析是一樣的。
另一種輸出結(jié)構(gòu)是推挽輸出。推挽輸出的結(jié)構(gòu)就是把上面的上拉電阻也換成一個開關(guān),當要輸出高電平時,上面的開關(guān)通,下面的開關(guān)斷;而要輸出低電平時,則剛好相反。比起OC或者OD來說,這樣的推挽結(jié)構(gòu)高、低電平驅(qū)動能力都很強。如果兩個輸出不同電平的輸出口接在一起的話,就會產(chǎn)生很大的電流,有可能將輸出口燒壞。而上面說的OC或OD輸出則不會有這樣的情況,因為上拉電阻提供的電流比較小。如果是推挽輸出的要設(shè)置為高阻態(tài)時,則兩個開關(guān)必須同時斷開(或者在輸出口上使用一個傳輸門),這樣可作為輸入狀態(tài),AVR單片機的一些IO口就是這種結(jié)構(gòu)。
開漏電路特點及應(yīng)用
在電路設(shè)計時我們常常遇到開漏(open drain)和開集(open collector)的概念。
所謂開漏電路概念中提到的“漏”就是指MOSFET的漏極。同理,開集電路中的“集”就是指三極管的集電極。開漏電路就是指以MOSFET的漏極為輸出的電路。一般的用法是會在漏極外部的電路添加上拉電阻。完整的開漏電路應(yīng)該由開漏器件和開漏上拉電阻組成。如圖1所示:
組成開漏形式的電路有以下幾個特點:
1. 利用外部電路的驅(qū)動能力,減少IC內(nèi)部的驅(qū)動(或驅(qū)動比芯片電源電壓高的負載)。當IC內(nèi)部MOSFET導(dǎo)通時,驅(qū)動電流是從外部的VCC流經(jīng)R pull-up ,MOSFET到GND。IC內(nèi)部僅需很下的柵極驅(qū)動電流。如圖1。
2. 可以將多個開漏輸出的Pin,連接到一條線上。形成 “與邏輯” 關(guān)系。如圖1,當PIN_A、PIN_B、PIN_C任意一個變低后,開漏線上的邏輯就為0了。這也是I2C,SMBus等總線判斷總線占用狀態(tài)的原理。如果作為輸出必須接上拉電阻。接容性負載時,下降延是芯片內(nèi)的晶體管,是有源驅(qū)動,速度較快;上升延是無源的外接電阻,速度慢。如果要求速度高電阻選擇要小,功耗會大。所以負載電阻的選擇要兼顧功耗和速度。
3. 可以利用改變上拉電源的電壓,改變傳輸電平。如圖2, IC的邏輯電平由電源Vcc1決定,而輸出高電平則由Vcc2(上拉電阻的電源電壓)決定。這樣我們就可以用低電平邏輯控制輸出高電平邏輯了(這樣你就可以進行任意電平的轉(zhuǎn)換)。(例如加上上拉電阻就可以提供TTL/CMOS電平輸出等。)
4. 開漏Pin不連接外部的上拉電阻,則只能輸出低電平(因此對于經(jīng)典的51單片機的P0口而言,要想做輸入輸出功能必須加外部上拉