一、基礎認識
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請求中斷,比如DMA、AD轉換等
(二)初始化函式
巨集定義
#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