IO端口位:如PA5/PC10/PE7等
IO端口位可以配置為8種模式,給人眼花繚亂、不知所措的感覺。如何才能正確掌握端口位的配置,成為懸在每一位嵌入式初級工程師心上的難題。接下來,我們就試圖破除阻礙我們繼續前進的這塊石頭。
雖然IO端口位在單片機內部分為輸入通道和輸出通道,但對外共用一個通道。為什么要設計為共用呢?因為可以節約硬件資源、簡化硬件設計。不過,雖然是共用,但在任意時刻,輸入和輸出只能二選一。這是很好理解的:一條只有一車寬的馬路,面對面行駛的兩輛車必然沖突。所以,當端口位在輸出模式時,讀取輸入數據寄存器,實際上讀的是輸出的內容;當端口位在輸入模式時,讀取輸出數據寄存器,實際上讀的是上次輸出的內容。

圖1 IO端口硬件電路
為了避免混淆和沖突,在使用IO端口位時,輸入時刻請配置為輸入模式,輸出時刻請配置為輸出模式。為了更好地理解輸入模式和輸出模式之間的區別,下面我們結合圖1進行講解。
輸出模式
輸出模式其實只有兩種:推挽輸出模式和開漏輸出模式(使用復用功能就配置為復用輸出模式,區別在於輸出源的不同)。
配置IO端口位為推挽輸出模式。當我們輸入1到“輸出控制”單元,則“輸出控制”單元就輸出A為1,B為1,從而使PMOS導通,NMOS截止,IO端口位就和VDD導通,從而輸出1;當我們輸入0到“輸出控制”單元,則“輸出控制”單元就輸出A為0,B為0,從而使PMOS截止,NMOS導通,IO端口位就和GND導通,從而輸出0。(至於“輸出控制”單元內部原理,我們不需要知道)
配置IO端口位為開漏輸出模式。“輸出控制”單元始終輸出A為0,也就是PMOS始終截止。當我們輸入1到“輸出控制”單元,則“輸出控制”單元就輸出B為1,從而使NMOS截止,IO端口位浮空,狀態不定;當我們輸入0到“輸出控制”單元,則“輸出控制”單元就輸出B為0,從而使NMOS導通,IO端口位就和GND導通,從而輸出0。所以,開漏輸出模式下,只能輸出低電平,反而是輸入1到“輸出控制”單元使IO口浮空時,就可以讀取外部輸入了。很奇怪,輸出模式反而成為輸入模式了。
因此,配置IO端口位為開漏輸出模式時,我們一般要外接上拉電阻。上拉電阻和上拉PMOS是有區別的:上拉電阻誕生了所謂的“准雙向口”(所以讀取外部輸入狀態要先寫1)。
參考圖1並想象外部上拉電阻,我們重新分析配置IO端口位為開漏輸出模式時的輸出情況。“輸出控制”單元始終輸出A為0,也就是PMOS始終截止。當我們輸入1到“輸出控制”單元,則“輸出控制”單元就輸出B為1,從而使NMOS截止,IO端口位被上拉電阻上拉到VDD,從而輸出1(根據阻值大小分為弱上拉和強上拉);當我們輸入0到“輸出控制”單元,則“輸出控制”單元就輸出B為0,從而使NMOS導通,IO端口位就和GND導通,從而輸出0(注意,強上拉再強也強不過直連導通,所以不會上拉到VDD)。很好,開漏輸出模式也能輸出0和1了。此外,如果要把IO端口位作為准雙向口使用,就必須先寫1使NMOS截止。
最后呢,我不建議將其作為准雙向口,不規范,也沒必要,如果要輸入就配置為輸入模式唄。好的,下面我們再說說輸入模式。
輸入模式
除了模擬輸入一般作為ADC輸入使用,其余三個大多數時候通用哦。上拉輸入和下拉輸入正如前面所說,強拉再強也強不過直連導通,所以都是可以正常獲取外部的輸入狀態。采用上拉和下拉的好處是可以避免出現不定狀態,防止外部干擾。在浮空輸入模式下,IO端口位的輸入阻抗很高,不過易受干擾。至於浮空輸入模式有什么用,后續還需要學習補充。

STM32F103上拉/下拉輸入模式
GPIOMode_TypeDef中關於上拉/下拉輸入模式的兩個枚舉常量的定義如下
GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48,
這兩個的低位都是1000,高位一個是0010一個是0100,在GPIO的初始化函數最后進行如下區分
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) GPIOx->BRR = (((uint32_t)0x01) << pinpos); /* Reset the corresponding ODR bit */ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU) GPIOx->BSRR = (((uint32_t)0x01) << pinpos); /* Set the corresponding ODR bit */
說明高位是用來區分設置的模式是IPU還是IPD,從而用來初始化IO端口的輸出用的。
那么,為什么要有上拉/下拉輸入模式呢?
如果沒有上拉/下拉輸入模式而選擇浮空輸入,那么就要由外設決定電平,但是這有局限性:外設不能有高阻態。因為浮空輸入時IO口電平不穩定、受外界影響較大。比如按鍵通常在松開時就處於浮空狀態。而上拉/下拉提供了一個強抗干擾模式,比如低電平有效,就可以設置上拉輸入模式,這樣就在沒有觸發電平的時候,IO口維持一個高電平,就可以抵抗較強的干擾!
