1. 程式人生 > >STM32 嵌入式學習入門(2)——STM32的GPIO介紹

STM32 嵌入式學習入門(2)——STM32的GPIO介紹

STM32的GPIO介紹


 GPIO:General Purpose Input Output ,即通用輸入/輸出,簡稱為GPIO。

GPIO應該是學習微控制器、學習嵌入式、學習STM32的第一個知識點了。在介紹GPIO相關的內容前,這裡先總得說一下自己對GPIO的理解。對於初學者,可以把GPIO的作用想象成C語言裡面的做輸入輸出的函式(scanf(); printf(); gets(); puts();等等),在C語言裡面scanf()和printf()這兩個函式是做輸入輸出的,對於幾乎所有的C語言程式,都可以看成是用輸入函式讀取了一些輸入,然後進行程式的邏輯處理,最後通過輸出

函式把程式最後執行的結果顯示出來的過程。

同樣地,這可以類比到嵌入式系統上面。比如循跡小車、避障小車、平衡小車、四旋翼等等,我們其實都可以看成這樣的結構:

1)首先通過外部模組(這裡主要是指各種感測器)讀取系統的相關引數。比如循跡小車,就是利用紅外模組去探測小車當前的行駛狀態,並實時地將小車的行駛狀態傳送給主控制器(STM32)。而這種資料的傳送就是將紅外模組的特定引腳與STM32的GPIO相連,以高低電平的形式向STM32傳遞資訊的。

2)主控制器對接收到的資料進行判斷。接著上面循跡小車的例子,在主控制器的程式中,每過一定的時間(比如10ms)就會掃描並一下接收感測器訊號的那幾個引腳(IO口)上的高低電平的資訊。然後對這些資訊進行分析判斷,判斷的結果是小車當前是否還沿著預定軌跡行駛,如果

偏離了預定的軌跡,應該怎麼調整。

3)主控制器將判斷結果通過IO口傳出。上面第2點,最後的判斷結果會通過IO口將調整資訊發出到電機驅動部分,電機驅動部分會根據主控模組發來的資料對電機轉速進行調整,從而達到讓小車循跡行駛的目的。

總結一下,上面這三點主要是想讓大家瞭解GPIO的作用,在一個專案、一個系統中的作用。說簡單了就是輸出高低電平和讀取高低電平輸入的。


下面進入正文,介紹GPIO的初始化和使用方法。


首先從最簡單的角度介紹GPIO是什麼東西。


首先GPIO最基本、最簡單的作用是我們可以通過程式設計的方式讓它作輸入或者輸出,而輸入/輸出的形式為高低電平(通常0V為低電平,3.3V為高電平)。要讓GPIO作輸入或者輸出,首先就需要對IO口相關的暫存器進行配置。

先介紹一下什麼是暫存器,暫存器是中央處理器內的組成部分,暫存器是有限存貯容量的高速存貯部件,它們可用來暫存指令、資料和地址。因此對IO口的初始化就是向相關暫存器裡面寫不同的值,從而確定使用哪一個IO口(IO口標號)、以及IO口工作模式(輸入還是輸出)、輸出速度等引數。在經過初始化之後就可以正常使用IO口了,比如如果IO口設定成了某個輸入模式,就可以通過呼叫相關函式或者直接操作相關暫存器去得到IO口的電平是高電平還是低電平。

下面從庫函式的層面來說明如何初始化IO口。


typedef struct
{
	uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
									  This parameter can be any value of @ref GPIO_pins_define */

	GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
									  This parameter can be a value of @ref GPIOSpeed_TypeDef */

	GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
									  This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

首先看這個結構體的定義,裡面有三個變數,首先這三個變數的型別是通過型別重新命名得到的,具體如下:

typedef unsigned short     int uint16_t;
typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
typedef enum
{ GPIO_Mode_AIN = 0x0,			//模擬輸入
  GPIO_Mode_IN_FLOATING = 0x04,		//浮空輸入
  GPIO_Mode_IPD = 0x28,			//下拉輸入
  GPIO_Mode_IPU = 0x48,			//上拉輸入
  GPIO_Mode_Out_OD = 0x14,		//開漏輸出
  GPIO_Mode_Out_PP = 0x10,		//推輓輸出
  GPIO_Mode_AF_OD = 0x1C,		//複用開漏輸出
  GPIO_Mode_AF_PP = 0x18		//複用推輓輸出
}GPIOMode_TypeDef;

所以實際上,GPIO_InitTypeDef這個結構體第一個變數型別為一種無符號的整形,變數名為GPIO_Pin,即為確定是哪一個IO口。GPIO_InitTypeDef的第二個變數型別是用列舉定義的,根據變數名很容易知道它是確定IO口的輸入或輸出的速度的。GPIO_InitTypeDef的第三變數同樣是列舉定義的,是確定IO口作輸入還是輸出,當然這裡輸入和輸出又可以各自細分為好幾種,所以這裡看到這個結構體中八種模式(mode)。這八種模式中,最常用的也是應該掌握的有三種:推輓輸出、開漏輸出、上拉輸入。

推輓輸出:可以輸出高、低電平,連線數字器件推輓結構一般是指兩個三極體分別受兩互補訊號的控制,總是在一個三極體導通的時候另一個截止。高低電平由IC的電源低定。

開漏輸出:輸出端相當於三極體的集電極.要得到高電平狀態需要上拉電阻才行.適合於做電流型的驅動,其吸收電流的能力相對強(一般20ma以內) 。

上拉輸入:IO口內部輸入時由上拉電阻上拉。

具體八種IO口工作模式的解釋,可以參考這個帖子:http://www.openedv.com/posts/list/21980.htm

比如說我們需要將PB5這個IO口設定為推輓輸出,輸入速度為50MHz,實現的程式碼如下:

 GPIO_InitTypeDef  GPIO_InitStructure;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 		//使能PB埠時鐘		①
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				//PB.5 埠配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 		//推輓輸出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//IO口速度為50MHz
	
 GPIO_Init(GPIOB, &GPIO_InitStructure);					//根據設定引數初始化GPIOB.5	
//void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

這裡可能不懂的地方是我用圓圈標出來的兩個地方。首先第①行,對於STM32而言,外設和IO口是很多的,預設狀態下這些外設和IO口的狀態都是關閉的(未使能的),這樣可以節約CPU的資源,在使用的時候就要使能(開啟)相關時鐘。②的位置是呼叫IO口初始化函式,這是一個庫函式,是官方提供的,初學者沒有必要了解函式實現的細節。但需要掌握該函式呼叫時的入口引數。我們的例子是初始化PB5,所以第一個確定IO分組的引數應該寫GPIOB,第二個引數就是傳入剛才配置好的變數的地址。

再舉一個例子,比如我們要初始化PA8這個IO口為下拉輸入,輸入速度為50MHz,實現的程式碼如下:,程式碼如下:

 GPIO_InitTypeDef  GPIO_InitStructure;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 		//使能PA埠時鐘
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				//PA.8 埠配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	 			//下拉輸入
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//IO口速度為50MHz
	
 GPIO_Init(GPIOA, &GPIO_InitStructure);					//根據設定引數初始化GPIOA.8


通過上面的操作,就對IO口完成初始化了。下面我們可以開始對IO口進行相關操作了,比如讀取IO口的電平(當IO口設定為某個輸入模式的時候),或者通過IO口輸出高低電平(當IO口設定為某個輸出模式的時候)。這裡介紹這麼三個庫函式:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
第一個函式用於讀取相關IO口的電平的高低,比如我要讀 GPIOA.5 的電平狀態, 那麼方法是:GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);返回值是 1(Bit_SET)或者 0(Bit_RESET)。

後面兩個函式用於設定IO口的電平的高低,GPIO_SetBits()用於設定IO口電平為高,GPIO_ResetBits();用於設定IO口電平為低。

比如我們要設定 GPIOB.5 輸出 1,那麼方法為:GPIO_SetBits(GPIOB, GPIO_Pin_5);反之如果要設定GPIOB.5 輸出位 0,方法為:GPIO_ResetBits (GPIOB, GPIO_Pin_5);

以上的介紹就是GPIO最最基本的內容。掌握了這些,就可以試著寫一個跑馬燈一類的實驗了。