stm32的引腳有兩種用途:GPIO(general purpose io)和AFIO(alternate function io)
對(duì)于一些引腳(視芯片而定),這兩種用途都沒(méi)有,如在64腳產(chǎn)品中,OSC_IN/OSC_OUT與作為GPIO端口的PD0/PD1共用一樣的引腳,而在100、144引腳產(chǎn)品中,這四個(gè)功能各有引腳與之對(duì)應(yīng),不互相沖突,所以O(shè)SC_IN/OSC_OUT既不作GPIO也不作AFIO,當(dāng)然,這樣的引腳不是討論重點(diǎn)。
1、引腳的配置
不論是作GPIO還是做AFIO,都要對(duì)引腳進(jìn)行配置。在固件庫(kù)函數(shù)中,用GPIO_Init()函數(shù)對(duì)引腳進(jìn)行配置,并不是說(shuō)這個(gè)函數(shù)帶了“GPIO”字樣就是要當(dāng)做GPIO來(lái)用,而是把它納入GPIO的范疇來(lái)討論。
所謂配置,就是引腳上的片上資源連接方式,如上拉電阻、密特觸發(fā)等等。關(guān)于配置的問(wèn)題,請(qǐng)見(jiàn)http://www.cnblogs.com/king-77024128/articles/1999395.html?1?3。理解了配置,也就能明白配置與模式的區(qū)別。
特別得,在下文中將會(huì)專門討論一下輸出配置中的推挽與開(kāi)漏。
2、復(fù)用功能
復(fù)用功能有兩種:沒(méi)有重映像、重映像(包括部分重映像、完全重映像),使用引腳用作AFIO功能,同樣需要對(duì)其進(jìn)行配置。
這三句話來(lái)自參考手冊(cè),但我對(duì)第一句和注意有疑問(wèn),第三節(jié)講。如果把端口配置成復(fù)用輸出功能,則引腳和輸出寄存器斷開(kāi),并和片上外設(shè)的輸出信號(hào)連接。輸入配置則與GPIO沒(méi)有區(qū)別。
為什么輸出模式有專門的復(fù)用模式而輸入則沒(méi)有呢。因?yàn)檩敵鍪怯尚酒瑑?nèi)部電路驅(qū)動(dòng)的,必須選擇這個(gè)驅(qū)動(dòng)來(lái)自哪一個(gè)外設(shè),是GPIO還是復(fù)用此管腳的其他外設(shè),也就是選擇該管腳在內(nèi)部是與哪個(gè)外設(shè)相連的,不說(shuō)明這個(gè)就會(huì)發(fā)生信號(hào)的錯(cuò)亂。而輸入則不同了,輸入信號(hào)是由芯片外的信號(hào)驅(qū)動(dòng)的,雖然該信號(hào)進(jìn)入芯片內(nèi)部后可能有不同的去向,但不需要對(duì)此進(jìn)行配置,因?yàn)椴粫?huì)發(fā)生信號(hào)的沖突,最壞的情況就是多驅(qū)動(dòng)了個(gè)寄存器而已。事實(shí)上,當(dāng)將引腳作為GPIO輸入時(shí),相應(yīng)的AFIO外設(shè)是處在關(guān)閉的狀態(tài),并不會(huì)耗電;當(dāng)引腳作為AFIO的輸入時(shí),可能GPIO是讀不進(jìn)來(lái)的,這是我猜的,沒(méi)有驗(yàn)證,能不能讀進(jìn)來(lái)無(wú)所謂的,不必糾結(jié)于此。
若選擇了復(fù)用,則默認(rèn)是沒(méi)有重映像的,可以直接使用外設(shè),不需要再軟件做設(shè)置。
但若要重映射,則需要簡(jiǎn)單設(shè)置一下,
先要配置重映射后對(duì)應(yīng)的管腳,可參看參考手冊(cè)或數(shù)據(jù)手冊(cè)引腳定義章節(jié),開(kāi)AFIO時(shí)鐘,使能重映射。例如重映射USART1,全部代碼如下:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*對(duì)寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX進(jìn)行讀寫(xiě)操作前,即重映射和選擇外部中斷線前,應(yīng)當(dāng)首先打開(kāi)AFIO的時(shí)鐘*/
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
這就完成了IO口的配置和重映射,下邊再配置相關(guān)的外設(shè)(USART1)就可以使用了。
外部中斷線也是可以映射的,并且需要開(kāi)AFIO時(shí)鐘,不用GPIO_PinRemap函數(shù),用GPIO_EXTILineConfig重映射引腳到中斷線。其實(shí)與其說(shuō)是映射,不如說(shuō)是選擇,選擇引腳連接到外部中斷線。
重映射不是任意的,只能重映射到指定的管腳。
3、關(guān)于第二節(jié)講到那個(gè)疑問(wèn),為甚么不能配置成模擬輸入?模擬輸入與浮空什么區(qū)別?
答案是可以配置成模擬輸入,官方3.5版固件庫(kù)例子和alientek例程都是將ADC輸入引腳配置成GPIO_Mode_AIN
那么配置成浮空行么,還能ADC么?
//例程
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//修改
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
實(shí)驗(yàn)證明,這兩種配置都能實(shí)現(xiàn)ADC。那么USART的Tx應(yīng)配置成GPIO_Mode_IN_FLOATING,如果配置成GPIO_Mode_AIN,還能接受數(shù)據(jù)么?金牛板實(shí)驗(yàn)結(jié)果是不能,ST不我欺也。總之:
可以將引腳配置成模擬輸入,使用相應(yīng)的復(fù)用功能;
浮空與模擬這兩種配置是不同的。
關(guān)于第二節(jié)里那個(gè)“注意“,我也不知道是什么意思。我猜測(cè)是這樣的:打開(kāi)某外設(shè),這個(gè)外設(shè)將某引腳當(dāng)做輸入,我們偏偏把這個(gè)引腳配置為GPIO輸出,這樣可以操作GPIO來(lái)”欺騙“這個(gè)外設(shè),這種用法應(yīng)該是很微妙的。
4、推挽與開(kāi)漏
不僅僅stm32有這種配置,實(shí)際上,這兩種已經(jīng)廣泛應(yīng)用在很多場(chǎng)合。
推挽,又叫做推拉,是個(gè)很形象的名字,一般是指兩個(gè)三極管(MOS管)分別受兩互補(bǔ)信號(hào)(或者一個(gè)信號(hào),但是用互補(bǔ)對(duì)管)的控制,總是在一個(gè)三極管導(dǎo)通的時(shí)候另一個(gè)截止,這樣的電路被稱為推挽式(互補(bǔ)式):
這種電路在放大中通常被用作輸出級(jí),在STM32中,推挽配置就是這種,如圖:
在相應(yīng)位置1時(shí),P-MOS導(dǎo),通N-MOS截止,輸出電壓為VDD;在相應(yīng)位置0時(shí),N-MOS導(dǎo)通,P-MOS截止,輸出電壓為VSS,這就是所謂的推挽。是比較簡(jiǎn)單的。
而所謂的開(kāi)漏(對(duì)三極管而言是開(kāi)集,一樣的原理),則要巧妙一些。所謂開(kāi)漏電路概念中提到的“漏”就是指MOS FET的漏極。同理,開(kāi)集電路中的“集”就是指三極管的集電極。開(kāi)漏電路就是指以MOS FET的漏極為輸出的電路。一般的用法是會(huì)在漏極外部的電路添加上拉電阻。完整的開(kāi)漏電路應(yīng)該由開(kāi)漏器件和開(kāi)漏上拉電阻組成。
對(duì)于stm32,開(kāi)漏就是失能了P-MOS,這樣,當(dāng)相應(yīng)位置1時(shí),引腳實(shí)際上是處在了浮空的狀態(tài),而通過(guò)外接的上拉電阻,將其拉高。
這么做有如下的好處:
1、可以將多個(gè)開(kāi)漏輸出的引腳,連接到一條線上。形成“與邏輯”關(guān)系。當(dāng)多個(gè)引腳任意一個(gè)變低后,開(kāi)漏線上的邏輯就為0了。這也是I2C,SMBus等總線判斷總線占用狀態(tài)的原理。在我的文章“stm32模擬iic——引腳配置、代碼”中,還會(huì)提到這個(gè)問(wèn)題。
2、 可以利用改變上拉電源的電壓,改變傳輸電平。這樣我們就可以用低電平邏輯控制輸出高電平邏輯了。想想當(dāng)初認(rèn)為stm32輸出3.3v電壓帶不動(dòng)IRF540,就直接斷定要重新選型,是錯(cuò)誤的想法,只要將推挽輸出變?yōu)殚_(kāi)漏,再加上上拉到5v的電阻,就能解決這個(gè)問(wèn)題。
順便一提,上拉電阻的阻值決定了邏輯電平轉(zhuǎn)換的沿的速度。阻值越大,速度越低功耗越小。反之亦然。