STM32 GPIO詳細篇(基於HAL庫)

東小東發表於2020-12-13

一、基礎認識

GPIO全名為General Purpose Input Output,即通用輸入輸出。有時候簡稱為“IO口”。通用,說明它是常見的。輸入輸出,就是說既能當輸入口使用,又能當輸出口使用。埠,就是元器件上的一個引腳。

輸入模式和輸出模式是GPIO的基本特性,當然GPIO還有其它模式可選。

(一) IO耐壓問題

STM32是一款3.3V電壓的晶片,IO輸出是3.3V,但IO大部分都是可以容忍5V電壓輸入。一般在晶片手冊的“引腳定義”章節可以檢視到有FT標識表示該IO可以容忍5V電壓輸入。

二、在標準庫中GPIO的模式

(一)模式彙總

輸入模式:

l  浮空輸入(GPIO_Mode_IN_FLOATING):引腳電平是真實的外部聯結器件電壓,電平有不確定性

l  上拉輸入 (GPIO_Mode_IPU):預設通過電阻上拉到VCC,不接外部器件時可以讀出高電平

l  下拉輸入 (GPIO_Mode_IPD):預設通過電阻下拉到GND,不接外部器件時可以讀出低電平

l  模擬輸入 (GPIO_Mode_AIN):將外部訊號直接傳輸到數模轉換通道上

輸出模式:

l  開漏輸出(GPIO_Mode_Out_OD):只能輸出低電平,高電平由電阻上拉決定

l  開漏複用功能(GPIO_Mode_AF_OD):用於外設功能使用

l  推輓式輸出(GPIO_Mode_Out_PP):可以輸出強高和強低,通常使用該功能控制LED

l  推輓式複用功能(GPIO_Mode_AF_PP):用於外設功能使用

GPIO的基本結構:

TTL肖特基觸發器其實可以理解為用肖特基管構成的施密特觸發器,作用簡單說就是將相對緩慢變化的模擬訊號變成矩形(方波)訊號,便於後面讀取。這裡有一個閾值電壓的概念,比如從低到高達到多少才會導通,從高到底多少才會關閉。

(二)   浮空輸入(GPIO_Mode_IN_FLOATING)

浮空就是邏輯器件與引腳即不接高電平,也不接低電平。由於邏輯器件的內部結構和外部引腳所接的器件決定電平狀態。一般實際運用時,引腳不建議懸空,易受干擾。通俗講就是浮空就是浮在空中,就相當於此埠在預設情況下什麼都不接,呈高阻態,這種設定在資料傳輸時用的比較多。浮空最大的特點就是電壓的不確定性,它可能是0V,頁可能是VCC,還可能是介於兩者之間的某個值(最有可能) 浮空一般用來做ADC輸入用,這樣可以減少上下拉電阻對結果的影響。

(三)  上拉輸入 (GPIO_Mode_IPU)

上拉就是把點位拉高,比如拉到Vcc。上拉就是將不確定的訊號通過一個電阻嵌位在高電平。電阻同時起到限流的作用。弱強只是上拉電阻的阻值不同,沒有什麼嚴格區分。

電阻通常為30-50KΩ

(四) 下拉輸入 (GPIO_Mode_IPD)

下拉就是把點位拉低,比如拉到GND。下拉就是將不確定的訊號通過一個電阻嵌位在低電平。電阻同時起到限流的作用。弱強只是下拉電阻的阻值不同,沒有什麼嚴格區分

(五) 模擬輸入 (GPIO_Mode_AIN)

模擬輸入是指傳統方式的輸入,數字輸入是輸入PCM數字訊號,即0,1的二進位制數字訊號,通過數模轉換,轉換成模擬訊號,經前級放大進入功率放大器,功率放大器還是模擬的

(六)  開漏輸出(GPIO_Mode_Out_OD)

IO輸出0接GND,IO輸出1,懸空,需要外接上拉電阻,才能實現輸出高電平。當輸出為1時,IO口的狀態由上拉電阻拉高電平,但由於是開漏輸出模式,這樣IO口也就可以由外部電路改變為低電平或不變。可以讀IO輸入電平變化,實現C51的IO雙向功能。

只能輸出強低電平。

(七) 開漏複用功能(GPIO_Mode_AF_OD)

用於外設使用

(八)推輓式輸出(GPIO_Mode_Out_PP)

IO輸出0-接GND, IO輸出1 -接VCC。這是使用最多的了。控制LED基本都是使用這種模式。

可以輸出強高低電平,連線外部數字器件

(九)推輓式複用功能(GPIO_Mode_AF_PP)

用於外設使用

三、配置輸入輸出IO

(一)輸入

(1).   GPIO Pull-up/Pull-down:

IO上下拉配置

l  No pull-up and no pull-down,浮空輸入,配置為不上拉和下拉

l  Pull-up,上拉輸入

l  Pull-down,下拉輸入

(二)輸出

(1).   GPIO output level

l  Low:IO初始化預設輸出低電平

l  High:IO初始化預設輸出高電平

(2).   GPIO mode

l  Output Open Drain,開漏輸出,可以輸出低電平

l  Output Push Pull,推輓輸出,可以輸出低電平和高電平 

(3).   GPIO Pull-up/Pull-down:

IO上下拉配置

l  No pull-up and no pull-down,浮空輸入,配置為不上拉和下拉

l  Pull-up,上拉輸入

l  Pull-down,下拉輸入

(4).   Maximum output speed

l  Low,GPIO速度為低速,通常為2MHZ

l  Medium,GPIO速度為中速,通常為10MHZ

l  High,GPIO速度為高速,通常為50MHZ

四、 輸出程式設計

測試有GPIOA1和GPIOA2設定為輸出測試

(一)CubeMx設定

 

(二) 初始化函式

巨集定義

#define DONG_OUT_1_Pin GPIO_PIN_1
#define DONG_OUT_1_GPIO_Port GPIOA
#define DONG_OUT_2_Pin GPIO_PIN_2
#define DONG_OUT_2_GPIO_Port GPIOA

初始化函式是自動生成的

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA時鐘

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, DONG_OUT_1_Pin|DONG_OUT_2_Pin, GPIO_PIN_RESET);//設定上電電平為低

  /*Configure GPIO pins : PAPin PAPin */
  GPIO_InitStruct.Pin = DONG_OUT_1_Pin|DONG_OUT_2_Pin;//兩個GPIO_PIN
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推輓輸出模式
  GPIO_InitStruct.Pull = GPIO_NOPULL;//浮空,不上拉也不下拉
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;//低速
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

(三)輸出相關函式

設定或清除選定的資料埠位

void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)

引數:

GPIOx :其中x可以(A..G取決於所使用的裝置)來選擇GPIO外設

GPIO_Pin :指定要寫入的埠位。此引數可以是GPIO_PIN_x之一,其中x可以是( 0..15 )

PinState :指定要寫入選定位的值。此引數可以是GPIO_PinState列舉值之一:

l  GPIO_PIN_RESET:清除埠Pin,低電平

l  GPIO_PIN_SET:設定埠Pin,高電平

例子:

HAL_GPIO_WritePin(GPIOA, DONG_OUT_1_Pin|DONG_OUT_2_Pin, GPIO_PIN_RESET);//兩個設定為低電平
HAL_Delay(1000);//1s
HAL_GPIO_WritePin(GPIOA, DONG_OUT_1_Pin, GPIO_PIN_SET);//單獨設定為高電平
HAL_GPIO_WritePin(GPIOA,DONG_OUT_2_Pin, GPIO_PIN_SET);//單獨設定為高電平
HAL_Delay(1000);//1s

切換指定的GPIO pin

void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

引數:

GPIOx :其中x可以(A..G取決於所使用的裝置)來選擇GPIO外設

GPIO_Pin :指定要寫入的埠位。此引數可以是GPIO_PIN_x之一,其中x可以是(0..15 )

例子:

HAL_GPIO_TogglePin(GPIOA, DONG_OUT_1_Pin|DONG_OUT_2_Pin);//兩個輸出電平取反
HAL_Delay(1000);//1s
HAL_GPIO_TogglePin(GPIOA, DONG_OUT_1_Pin);//單獨輸出電平取反
HAL_GPIO_TogglePin(GPIOA,DONG_OUT_2_Pin);//單獨輸出電平取反
HAL_Delay(1000);//1s

五、輸入程式設計(輪詢檢測)

(一)CubeMX設定

 (二)初始化函式

巨集定義

#define DONG_IN_1_Pin GPIO_PIN_3
#define DONG_IN_1_GPIO_Port GPIOA

初始化部分

GPIO_InitTypeDef GPIO_InitStruct = {0};//初始化結構體
__HAL_RCC_GPIOA_CLK_ENABLE();//GPIO時鐘開啟
GPIO_InitStruct.Pin = DONG_IN_1_Pin;//引腳
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//輸入模式
GPIO_InitStruct.Pull = GPIO_PULLUP;//上拉
HAL_GPIO_Init(DONG_IN_1_GPIO_Port, &GPIO_InitStruct);

(三)輸入相關函式

讀取指定的輸入埠引腳

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

引數:

GPIOx :其中x可以(A..G取決於所使用的裝置)來選擇GPIO外設

GPIO_Pin :指定要寫入的埠位。此引數可以是GPIO_PIN_x之一,其中x可以是(0..15 )

返回:

typedef enum
{
  GPIO_PIN_RESET = 0u,//低電平
  GPIO_PIN_SET//高電平
} GPIO_PinState;

例子:

GPIO_PinState res=HAL_GPIO_ReadPin(DONG_IN_1_GPIO_Port,DONG_IN_1_Pin);//讀取電平
if(res==GPIO_PIN_RESET){
     HAL_GPIO_WritePin(GPIOA, DONG_OUT_1_Pin|DONG_OUT_2_Pin, GPIO_PIN_SET);//兩個設定為高電平
}else{
     HAL_GPIO_WritePin(GPIOA, DONG_OUT_1_Pin|DONG_OUT_2_Pin, GPIO_PIN_RESET);//兩個設定為低電平
}

六、輸入程式設計(中斷檢測)

(一)CubeMX設定

 

GPIO mode:

l  上升沿觸發檢測的外部中斷模式(External Interrupt Mode with Rising edge trigger detection)

l  下降沿觸發檢測的外部中斷模式(External Interrupt Mode with Falling edge trigger detectiort)

l  上升/下降沿觸發檢測的外部中斷模式(External Interrupt Mode with Risinq/Falling edge trigger detection)

l  上升沿觸發檢測的外部事件模式(External Event Mode with Rising edge trigger detection)

l  下降沿觸發檢測的外部事件模式(External Event Mode with Falling edge trigger detection)

l  上升/下降沿觸發檢測的外部事件模式(External Event Mode with Rising/Falling edge trigger detectiont)

中斷和事件的區別:

l  中斷是當IO達到中斷條件後會向CPU產生中斷請求

l  事件是事先設定好的任務,當微控制器達到要求將通過硬體的方式處理事先設定好的任務,而不向CPU請求中斷,比如DMAAD轉換等

(二)初始化函式

巨集定義

#define KEY1_Pin GPIO_PIN_3
#define KEY1_GPIO_Port GPIOA
#define KEY1_EXTI_IRQn EXTI3_IRQn

初始化部分

__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = KEY1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);

(三)中斷輸入相關函式

中斷回撥函式

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

引數:

GPIO_Pin :指定連線EXTI線的引腳

例子:

//GPIO中斷回撥函式
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
//判斷進入中斷的GPIOs
if(KEY1_Pin==GPIO_Pin){
            HAL_GPIO_TogglePin(GPIOA, DONG_OUT_1_Pin);//單獨輸出電平取反
            HAL_GPIO_TogglePin(GPIOA,DONG_OUT_2_Pin);//單獨輸出電平取反
     }
}

其它

關於按鍵防抖的問題:

l  軟體防抖可以檢測到電平延時一段時間再確認電平,延時時間一般為10-20ms

l  硬體防抖可以在按鍵上並聯一個電容,一般為0.1uf


 參考:

https://blog.csdn.net/baidu_37366055/article/details/80060962

相關文章