【STM32H7教程】第17章 STM32H7之GPIO的HAL庫API


完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第17章       STM32H7之GPIO的HAL庫API

本章教程為大家講解GPIO(General-purpose I/Os)的API使用和注意事項。GPIO是所有外設里面較容易掌握的,但也是用到最多的。

配合第15章講解的各種IO模式再學習本章,更容易理解透徹。

17.1 初學者重要提示

17.2 GPIO涉及到的寄存器

17.3 源文件stm32h7xx_hal_gpio.c

17.4 如何使用HAL庫的GPIO驅動

17.5 總結

 

 

17.1 初學者重要提示

1、  如何閱讀HAL庫源碼的問題

HAL庫實現的函數有復雜的,也有簡單的,簡單的可以直接閱讀代碼。復雜的代碼閱讀起來比較耗時間,如果再配合參考手冊摳每個寄存器的配置,那就更消耗時間了。所以對於這種函數,用戶僅需了解每個部分實行的功能即可,而且HAL庫都做了關鍵注釋,以說明這部分實現的功能。所以用戶沒有必要去摳每個配置是如何實現的,僅需知道實現了什么功能。以后工程項目有需要了解具體配置時,再看即可。

2、  學習本章節前,務必保證已經學習了第15章。

17.2 GPIO涉及到的寄存器

GPIO外設涉及到的寄存器比較少,也容易理解,推薦大家閱讀GPIO源碼的時候將參考手冊中對應的寄存器功能做一個了解。

很多時候,我們會直接調用GPIO的寄存器進行配置,而不使用HAL進行調用,以提高執行效率,特別是中斷里面執行時。

17.3 源文件stm32h7xx_hal_gpio.c

這個文件主要是實現GPIO的引腳配置,學習這個文件注意事項:

  1.   系統上電后,引腳默認狀態是模擬模式。
  2.   所有的引腳有弱上拉和弱下拉電阻,阻值范圍30-50KΩ。其中配置為模擬模式時,上拉和下拉被硬件禁止,其它的輸入、輸出和復用都可以配置上拉和下拉。
  3.   在輸出或者復用模式,每個引腳可以配置成推挽或者開漏,且有GPIO速度等級可配置。另外注意,不同的供電范圍,實際速度等級是有些區別的。
  4.   每個GPIO都可以配置成外部中斷/事件模式,但要特別注意,引腳要配置成輸入模式,在芯片的內部有個多路選擇器,選擇引腳與16個外部中斷/事件EXTI0 - EXTI15中的那個導通。這就決定了,每個外部中斷/事件只能與一個引腳導通,如果用戶配置了多個引腳PA0,PB0,PC0等,那么只有一個能夠與EXTI0導通。

17.3.1 函數HAL_GPIO_Init

函數原型:

void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
/* 部分省略未寫 */

  /* 配置GPIO引腳,這些采用16個引腳的循環檢測模式 */
  for(position = 0; position < GPIO_NUMBER; position++)
  {
     /* 部分省略未寫 */
    if(iocurrent == ioposition)
    {
      /*--------------------- GPIO模式配置 ------------------------*/
     
      /*--------------------- EXTI模式配置 ------------------------*/
     
    }
  }
}

函數描述:

此函數用於初始化GPIO,此函數主要實現如下功能:

  •   GPIO功能配置。
  •   設置EXTI功能。

函數參數:

  •   第1個參數用於填寫使用的端口號,可以是:
#define GPIOA    ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB    ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC    ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD    ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE     ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF     ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG     ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH     ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOI      ((GPIO_TypeDef *) GPIOI_BASE)
#define GPIOJ      ((GPIO_TypeDef *) GPIOJ_BASE)
#define GPIOK     ((GPIO_TypeDef *) GPIOK_BASE)
  •   第2個形參是GPIO_InitTypeDef類型的結構體變量,這個變量比較重要,要熟練掌握,定義如下:
typedef struct
{
  uint32_t Pin;    
  uint32_t Mode; 
  uint32_t Pull;     
  uint32_t Speed;   
  uint32_t Alternate; 
}GPIO_InitTypeDef;

下面將結構體每個成員做個說明:

  •   成員Pin用於配置選擇的引腳,范圍GPIO_PIN_0到GPIO_PIN_15,額外還可以選擇GPIO_PIN_All和GPIO_PIN_MASK。
  •   成員Mode可以選擇:
GPIO_MODE_INPUT             /* 輸入模式  */
GPIO_MODE_OUTPUT_PP        /* 推挽輸出  */
GPIO_MODE_OUTPUT_OD       /* 開漏輸出  */
GPIO_MODE_AF_PP             /* 復用推挽  */
GPIO_MODE_AF_OD            /* 復用開漏  */

GPIO_MODE_ANALOG          /* 模擬模式  */
GPIO_MODE_IT_RISING         /* 外部中斷,上升沿觸發檢測 */
GPIO_MODE_IT_FALLING       /* 外部中斷,下降沿觸發檢測 */
GPIO_MODE_IT_RISING_FALLING    /* 外部中斷,雙沿觸發檢測   */

GPIO_MODE_EVT_RISING           /* 外部事件模式,上升沿觸發檢測  */
GPIO_MODE_EVT_FALLING          /* 外部事件模式,下降沿觸發檢測  */
GPIO_MODE_EVT_RISING_FALLING  /* 外部事件模式,雙沿觸發檢測 */
  •   成員Pull用於配置上拉下拉電阻:
GPIO_NOPULL         /* 無上拉和下拉電阻 */
GPIO_PULLUP          /* 帶上拉電阻  */
GPIO_PULLDOWN    /* 帶下拉電阻  */
  •   成員Speed用於配置GPIO速度等級,有下面四種可選:
GPIO_SPEED_FREQ_LOW          /* 低速 */
GPIO_SPEED_FREQ_MEDIUM      /* 中等速度 */
GPIO_SPEED_FREQ_HIGH         /* 快速 */
GPIO_SPEED_FREQ_VERY_HIGH   /* 高速  */
  •   成員Alternate用於配置引腳復用,可選擇的復用方式在文件stm32h7xx_hal_gpio_ex.h里面進行了定義,比如串口復用:
GPIO_AF7_USART1   
GPIO_AF7_USART2    
GPIO_AF7_USART3       
GPIO_AF7_USART6    
GPIO_AF7_UART7 

注意事項:

  1. 與F1,F4系列的標准庫不同,H7的HAL庫已經沒有單獨的EXTI外部中斷設置文件,是將其整合到此函數里面了。
  2. 函數HAL_GPIO_Init對引腳的初始化是把同組16個引腳for循環檢測了一遍,效率稍低。所以不推薦下面這種初始化:
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;                   
GPIO_InitStruct.Pull = GPIO_NOPULL;              
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;  
GPIO_InitStruct.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);   //這里會執行16次for查詢

GPIO_InitStruct.Pin = GPIO_PIN_1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);   //這里會執行16次for查詢
       
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  //這里會執行16次for查詢

如果是程序運行期間的引腳狀態切換,最好采用下面的方式或者直接寄存器操作:

GPIO_InitStruct.Pin = GPIO_PIN_0 |GPIO_PIN_1 | GPIO_PIN_2 ;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;                   
GPIO_InitStruct.Pull = GPIO_NOPULL;              
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;  

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  //這里會執行16次for查詢

使用舉例:

GPIO_InitTypeDef  GPIO_InitStruct;

GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;      /* 推挽輸出 */         
GPIO_InitStruct.Pull = GPIO_NOPULL;                /* 無上拉和下拉電阻 */ 
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* GPIO速度等級最高 */

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 

17.3.2 函數HAL_GPIO_DeInit

函數原型:

void HAL_GPIO_DeInit(GPIO_TypeDef  *GPIOx, uint32_t GPIO_Pin)
{  
  for(position = 0; position < GPIO_NUMBER; position++)
  {
     /* 部分省略未寫 */
    if(iocurrent == ioposition)
    {
      /*------------------------- GPIO Mode Configuration --------------------*/
      /* 配置為模擬模式 */
      GPIOx->MODER |= (GPIO_MODER_MODER0 << (position * 2));

      /* 配置復用模式為AF0,即作為通用IO */
      GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ;

      /* 配置到最低速度 */
      GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2));

      /* 輸出類型是推挽,如果IO模式被設置為模擬,此選項對其沒有影響 */
      GPIOx->OTYPER  &= ~(GPIO_OTYPER_OT_0 << position) ;

      /* 無上拉和下拉電阻 */
      GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (position * 2));

      /*------------------------- EXTI模式配置 --------------------*/
      
    }
  }
}

函數描述:

此函數用於復位IO到初始化狀態,具體狀態看函數原型中的注釋即可。

函數參數:

  •   第1個參數用於填寫使用的端口號,可以是:
#define GPIOA    ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB    ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC    ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD    ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE     ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF     ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG     ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH     ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOI      ((GPIO_TypeDef *) GPIOI_BASE)
#define GPIOJ      ((GPIO_TypeDef *) GPIOJ_BASE)
#define GPIOK     ((GPIO_TypeDef *) GPIOK_BASE)
  •   第2個參數是配置選擇的引腳,范圍GPIO_PIN_0到GPIO_PIN_15。

使用舉例:

此函數的使用比較簡單,需要調用的時候直接調用即可。

17.3.3 函數HAL_GPIO_ReadPin

函數原型:

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  GPIO_PinState bitstatus;

  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
  {
    bitstatus = GPIO_PIN_SET;
  }
  else
  {
    bitstatus = GPIO_PIN_RESET;
  }
  return bitstatus;
}

函數描述:

此函數用於讀取引腳狀態,通過GPIO的IDR寄存器讀取。

函數參數:

  •   第1個參數用於填寫使用的端口號,從GPIOA到GPIAK。
  •   第2個參數是配置選擇的引腳,范圍GPIO_PIN_0到GPIO_PIN_15。

使用舉例:

此函數的使用比較簡單,需要調用的時候直接調用即可。

17.3.4 函數HAL_GPIO_WritePin

函數原型:

void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  assert_param(IS_GPIO_PIN_ACTION(PinState));

  if(PinState != GPIO_PIN_RESET)
  {
    GPIOx->BSRRL = GPIO_Pin;
  }
  else
  {
    GPIOx->BSRRH = GPIO_Pin ;
  }
}

函數描述:

此函數用於設置引腳輸出高電平或者低電平。使用GPIO的BSRR寄存器進行設置,使用這個寄存器的好處是支持原子操作,由硬件支持的。原子操作的含義是操作過程不會被中斷打斷,而我們使用GPIO中另一個設置輸出的寄存ODR是會被中斷打斷的。大家看下寄存器賦值操作對應的反匯編,是由多條匯編指令組成的。

函數參數:

  •   第1個參數用於填寫使用的端口號,從GPIOA到GPIAK。
  •   第2個參數是配置選擇的引腳,范圍GPIO_PIN_0到GPIO_PIN_15。
  •   第3個參數用於設置引腳輸出高電平還是低電平,GPIO_PIN_RESET表示低電平,GPIO_PIN_SET表示高電平。

使用舉例:

此函數的使用比較簡單,需要調用的時候直接調用即可。

17.3.5 函數HAL_GPIO_TogglePin

函數原型:

void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  GPIOx->ODR ^= GPIO_Pin;
}

函數描述:

此函數用於設置引腳的電平翻轉,使用GPIO的ODR寄存器進行設置。

函數參數:

  •   第1個參數用於填寫使用的端口號,從GPIOA到GPIAK。
  •   第2個參數是配置選擇的引腳,范圍GPIO_PIN_0到GPIO_PIN_15。

使用舉例:

此函數的使用比較簡單,需要調用的時候直接調用即可。

17.3.6 函數HAL_GPIO_LockPin

函數原型:

HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  __IO uint32_t tmp = GPIO_LCKR_LCKK;

  assert_param(IS_GPIO_LOCK_INSTANCE(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  /* 應用IO鎖的寫入順序 */
  tmp |= GPIO_Pin;
  /* 設置 LCKx bit(s): LCKK='1' + LCK[15-0] */
  GPIOx->LCKR = tmp;
  /* 復位 LCKx bit(s): LCKK='0' + LCK[15-0] */
  GPIOx->LCKR = GPIO_Pin;
  /* 設置 LCKx bit(s): LCKK='1' + LCK[15-0] */
  GPIOx->LCKR = tmp;
  /* 復位 LCKK bit*/
  tmp = GPIOx->LCKR;

 if((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET)
  {
    return HAL_OK;
  }
  else
  {
    return HAL_ERROR;
  }
}

函數描述:

此函數用於鎖住GPIO引腳所涉及到的寄存器,這些寄存器包括GPIOx_MODER,GPIOx_OTYPER,GPIOx_OSPEEDR,GPIOx_PUPDR,GPIOx_AFRL 和 GPIOx_AFRH。

函數參數:

  •   第1個參數用於填寫使用的端口號,從GPIOA到GPIAK。
  •   第2個參數是配置選擇的引腳,范圍GPIO_PIN_0到GPIO_PIN_15。

注意事項:

  1. 此函數是鎖住用戶設置的引腳所對應的寄存器某些位,並不是把整個寄存器都鎖住了。
  2. 一旦鎖住后,就不能再修改,只有復位后才可以重新配置。

使用舉例:

此函數的使用比較簡單,需要調用的時候直接調用即可。

17.4 如何使用HAL庫的GPIO驅動

使用方法由HAL庫提供(本章17.3.1小節提供的例子就是這種方式):

  第1步:使能GPIO所在總線的AHB時鍾,__HAL_RCC_GPIOx_CLK_ENABLE()。

  第2步:通過函數HAL_GPIO_Init()配置GPIO。

(1)    通過結構體GPIO_InitTypeDef的成員Mode配置輸入、輸出、模擬等模式。

(2)    通過結構體GPIO_InitTypeDef的成員Pull配置上拉、下拉電阻。

(3)    通過結構體GPIO_InitTypeDef的成員Speed配置GPIO速度等級。

(4)    如果選擇了復用模式,那么就需要配置結構體GPIO_InitTypeDef的成員Alternate。

(5)    如果引腳功能用於ADC、DAC的話,需要配置引腳為模擬模式。

(6)    如果是用於外部中斷/事件,結構體GPIO_InitTypeDef的成員Mode可以配置相應模式,相應的上升沿、下降沿或者雙沿觸發也可以選擇。

  第3步:如果配置了外部中斷/事件,可以通過函數HAL_NVIC_SetPriority設置優先級,然后調用函數HAL_NVIC_EnableIRQ使能此中斷。

  第4步:輸入模式讀取引腳狀態可以使用函數HAL_GPIO_ReadPin。

  第5步:輸出模式設置引腳狀態可以調用函數HAL_GPIO_WritePin()和HAL_GPIO_TogglePin。

 

另外注意下面三個問題:

  1.   系統上電復位后,GPIO默認是模擬模式,除了JTAG相關引腳。
  2.   關閉LSE的話,用到的兩個引腳OSC32_IN和OSC32_OUT(分別是PC14,PC15)可以用在通用IO,如果開啟了,就不能再做GPIO。
  3.   關閉HSE的話,用到的兩個引腳OSC_IN和OSC_OUT(分別是PH0,PH1)可以用在通用IO,如果開啟了,就不能再做GPIO。

17.5 總結

本章節就為大家講解這么多,建議大家將GPIO的驅動源碼結合參考手冊中的寄存器通讀一遍,對於我們后面章節的學習大有裨益。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM