一、什麼是GPIO GPIO全稱為General Purpose Input Output,中文理解為通用輸入輸出埠。它指的是編程可控制的引腳,即可以控制引腳是作為輸入來用,還是輸出功能,又或者是交給片上外設使用(復用)。 二、GPIO結構框圖 理解GPIO硬體電路的實現,有助於編程的理解。下圖是 ...
一、什麼是GPIO
GPIO全稱為General Purpose Input Output,中文理解為通用輸入輸出埠。它指的是編程可控制的引腳,即可以控制引腳是作為輸入來用,還是輸出功能,又或者是交給片上外設使用(復用)。
二、GPIO結構框圖
理解GPIO硬體電路的實現,有助於編程的理解。下圖是官方手冊給出的GPIO框圖:
此框圖中只有最右端的I/O pin是板上外露可見的,其他部分均在晶元內部。該框圖結構被分為兩個部分,其一是輸出結構,主要由引腳(I/O pin)、保護二極體(protection diode)、雙MOS管(P-MOS+N-MOS)、輸出控制(output control)、輸出數據寄存器(output data register)、位置位/複位寄存器(bit set/reset register)組成 ;其二是輸入結構,由引腳、保護二極體、雙開關(on/off)、TTL肖特基觸發器(TTL Schmitt trigger)、輸入數據寄存器(input data register)組成。
1.保護二極體
兩個二極體構成了雙向限幅電路。當外部輸入電壓大於VDD時,上方二極體導通(全文皆忽略二極體和MOS管導通壓降),使得電壓限制在VDD左右;當外部輸入電壓低於VSS,下方二極體導通,電壓限制在VSS左右。然而這樣的保護並不能使引腳直接驅動大功率器件,例如電機,就需要外加驅動電路。
2.雙開關
這個雙開關電路與上拉、下拉和浮空模式有關,當處於上拉模式時上方開關閉合,下方斷開,除非引腳的外部輸入為低電平,否則輸入到肖特基觸發器的電平都是高電平;當處於下拉模式時上方開關斷開,下方閉合,除非引腳的外部輸入為高電平,否則輸入到肖特基觸發器的電平都是低電平;當處於浮空模式時開關全部斷開,電平預設為高阻態,輸入的電平完全取決於外部輸入。上下拉多用於按鍵檢測,而浮空則常用於ADC檢測。
3.肖特基觸發器
該觸發器主要是將模擬電壓轉為0/1數字信號,上圖中模擬輸入(Analog input)就取自觸發器之前,而輸入數據寄存器則取自觸發器之後的數字信號。
4.輸入數據寄存器
這個寄存器用來存儲各個引腳電平狀態,可通過讀取該寄存器內容,來獲取任意引腳狀態。
5.位置位/複位寄存器
通過讀寫該寄存器,可以間接地更改輸出數據寄存器的值。
6.輸出數據寄存器
可以直接讀寫該寄存器,來更改各個引腳的輸出狀態,當寄存器值保持不變時,每個引腳的電平也就不發生變化。
7.雙MOS管
雙MOS管組成一個推輓輸出(push-pull)電路,當輸出寄存器中值為1時,經過反相器,兩管的共柵極輸入低電平,則PMOS導通,NMOS截止,引腳輸出高電平;當輸出寄存器中值為0時,經過反相器,兩管的共柵極輸入高電平,則NMOS導通,PMOS截止,引腳輸出低電平。當PMOS被禁用時,電路變為開漏輸出,引腳仍可輸出低電平,但無法正常輸出高電平,取而代之的是高阻態。如果此時想要輸出高電平,則必須接上拉電阻。開漏輸出僅在一些特殊場合下使用,更多的是推輓輸出。
三、GPIO寄存器
1.APB2外設時鐘使能寄存器(RCC_APB2ENR)
RCC_APB2ENR並不屬於GPIO的寄存器組,但是它控制著GPIO的引腳時鐘使能,晶元上電後,所有外設時鐘預設是關閉的,所以在使用GPIO前要先打開埠時鐘使能。該寄存器內容如下,我們只關心IOPxEN位,置1則開啟時鐘。
2.埠配置低位寄存器(GPIOx_CRL)
該寄存器可配置低8個GPIO引腳的工作模式:模擬輸入、浮空輸入、上拉\下拉輸入、通用推輓輸出、通用開漏輸出、復用推輓輸出、復用開漏輸出。復用輸入模式沒有單獨的配置,只要將引腳配置為浮空/上拉/下拉輸入模式,由片上外設驅動即可。CRL還可以在輸出模式下配置工作頻率,頻率越大,功耗越高。註意每個引腳模式配置占4bit。對於上拉\下拉輸入來說,是上拉還是下拉取決於ODR寄存器配置的值。
3.埠配置高位寄存器(GPIOx_CRH)
該寄存器同GPIOx_CRL,只是它控制的是高8個GPIO引腳的工作模式。
4.輸入數據寄存器(GPIOx_IDR)
該寄存器存儲了當前引腳的狀態,無論GPIO在哪種工作模式下,都可以讀取該寄存器,但在模擬輸入模式下,寄存器的值一直為0。
5.輸出數據寄存器(GPIOx_ODR)
在通用輸出模式下,該寄存器可用來控制電平高低;在復用推輓輸出模式下,可讀取ODR獲取引腳狀態(在復用開漏輸出模式下,可讀取IDR獲取引腳狀態)。在上拉或下拉輸入模式下,ODR可決定是上拉還是下拉。
6.位置位/複位寄存器(GPIOx_BSRR)
通過該寄存器,可以單獨控制某個引腳的電平變化。因為向這個寄存器寫0的結果是無操作,寫1是置位或者複位,所以訪問該寄存器可以直接用=號;而ODR寄存器寫0則表示給低電平,寫1表示給高電平,為了不影響其他引腳,寫入必須用&=和|=號。另外還有個寄存器叫GPIOx_BRR,同該寄存器差不多,只不過BRR只能複位,高16位是保留的。
四、GPIO編程
GPIO最常用的就是通用推輓輸出和上拉/下拉輸入這兩種模式。一下程式實現功能為:
PA0為按鍵輸入,按下為低電平。PC13是led控制引腳,低電平點亮LED。當按下按鍵時,LED亮;鬆開按鍵時,LED滅。
程式代碼如下,根據GPIO原理,編程順序一般是:先開啟時鐘使能,配置引腳工作模式,最後給引腳電平信號。
int main(void) { uint32_t key_value; //開啟GPIO外設時鐘使能 //PORTA,第三位置1 RCC->APB2ENR |= (1<<2); //PORTC,第五位置1 RCC->APB2ENR |= (1<<4); //GPIO輸入輸出模式配置 //清零PA0控制位 GPIOA->CRL &= ~((uint32_t)(0x0F)<<(4*0)); //設置PA0為上拉輸入 GPIOA->CRL |= (uint32_t)(0x08)<<(4*0); GPIOA->ODR |= (uint32_t)(0x01)<<0; //清零PC13控制位 GPIOC->CRH &= ~((uint32_t)(0x0F)<<(4*5)); //設置PC13為推免輸出 GPIOC->CRH |= (uint32_t)(0x01)<<(4*5); while(1){ //獲取PA0電平狀態,key_value==1表示按鍵沒有按下 key_value = (GPIOA->IDR & (uint32_t)(0x01)) == (uint32_t)(0x01); //改變PC13電平 if (key_value==0) //PC13低電平輸出 GPIOC->ODR &= ~((uint32_t)(0x01)<<13); else //PC13高電平輸出 GPIOC->ODR |= (uint32_t)(0x01)<<13; } }