(1)STM32使用HAL庫操作GPIO


一  初始化GPIO

使用HAL庫的優點在於不用手動添加初始化的代碼了,CubeMX會根據軟件設置自動生成。

自動生成的HAL庫GPIO初始化代碼:

復制代碼
static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); /*Configure GPIO pin : PD11 */ GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */ GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); }
復制代碼

順序:(1)定義結構體變量。(2)使能時鍾。(3)配置初始化電平。(4)通過結構體變量初始化GPIO。

1.首先定義一個結構體變量GPIO_InitStruct,該變量類型是GPIO_InitTypeDef。

GPIO_InitTypeDef 定義如下:

復制代碼
/** * @brief GPIO Init structure definition */ typedef struct { uint32_t Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ uint32_t Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIO_mode_define */ uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins. This parameter can be a value of @ref GPIO_pull_define */ uint32_t Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIO_speed_define */ uint32_t Alternate; /*!< Peripheral to be connected to the selected pins. This parameter can be a value of @ref GPIO_Alternate_function_selection */ }GPIO_InitTypeDef;
復制代碼

 

作用是:設置要用的是哪個引腳、引腳工作模式、上拉還是下拉、速度、XX這個還不知道是干嘛的XX。

2.使能時鍾。

  /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE();

這里使能時鍾的方法與標准庫不一樣,HAL庫其實是宏定義,標准庫則是函數。

宏定義(使能H口的宏定義):

復制代碼
#define __HAL_RCC_GPIOH_CLK_ENABLE()  do { \ __IO uint32_t tmpreg = 0x00U; \ SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOHEN);\ /* Delay after an RCC peripheral clock enabling */ \ tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOHEN);\ UNUSED(tmpreg); \ } while(0U)
復制代碼

這里使能H口是因為H口接的外部晶振。

3.配置引腳的初始化電平。

  /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);

這里設置D口的pin12、pin13、pin14、pin15為高電平。如果最后一個參數是GPIO_PIN_RESET則為低電平。

4.通過結構體變量配置具體的引腳。

復制代碼
  /*Configure GPIO pin : PD11 */ GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */ GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
復制代碼

 

PD11為輸入,上拉。PD12-15為推挽輸出。所以分開配置。

總結一下:(1)定義結構體變量。(2)使能時鍾。(3)配置初始化電平。(4)通過結構體變量初始化GPIO。

其中,(3)和(4)可調換順序

二  功能解釋

1.系統分析。

STM32F4Discovery的PD12-15的四個引腳是LED。

我們要做的功能是按鍵一次點亮一個LED(順時針PIN12-15,從PIN12開始)並關閉上一個LED。

首先我們需要一個標志變量來代表當前正在亮的LED:

int LEDNUM_Flag = 12;

流程:按鍵掃描  ->  讀到Pin11按下  ->  關閉當前LEDNUM_Flag代表的LED(正在亮的)  ->  LEDNUM_Flag+1  ->  點亮當前LEDNUM_Flag代表的LED;

2.按鍵輸入。

復制代碼
_Bool GetPress(void)
{
    if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==0) { HAL_Delay(10);//防抖 if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==0) { while(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==0)//等待按鍵抬起。 {;} return 1; } else return 0; } else return 0; }
復制代碼

 

3.點亮LED。

復制代碼
void TurnOnLED(int flag) { switch(flag) { case 12 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); break; case 13 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET); break; case 14 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); break; case 15 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET); break; } }
復制代碼

 

4.關閉LED。

復制代碼
void TurnOffLED(int flag) { switch(flag) { case 12 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); break; case 13 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET); break; case 14 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); break; case 15 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET); break; } }
復制代碼

 

5.標志變量自加。

復制代碼
void FlagPlus(int *flag) { (*flag)++; if((*flag)==16) { (*flag)=12; } }
復制代碼

 

這里一定要用指針,因為函數參數是值傳遞所以只能用指針來改變LEDNUM_Flag。

6.整合代碼。

復制代碼
#include "main.h" #include "stm32f4xx_hal.h" void SystemClock_Config(void); static void MX_GPIO_Init(void); int LEDNUM_Flag = 12; _Bool GetPress(void); void TurnOnLED(int flag); void TurnOffLED(int flag); void FlagPlus(int *flag); int main(void) {  HAL_Init();  SystemClock_Config();  MX_GPIO_Init(); //最開始先點亮PD12的LED  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); while (1) { //有按鍵按下 if(GetPress()==1) { TurnOffLED(LEDNUM_Flag); FlagPlus(&LEDNUM_Flag); TurnOnLED(LEDNUM_Flag); } } } /** System Clock Configuration */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); /*Configure GPIO pin : PD11 */ GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */ GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// _Bool GetPress(void) { if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==0) { HAL_Delay(10); if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==0) { while(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==0) {;} return 1; } else return 0; } else return 0; } void TurnOnLED(int flag) { switch(flag) { case 12 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); break; case 13 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET); break; case 14 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); break; case 15 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET); break; } } void TurnOffLED(int flag) { switch(flag) { case 12 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); break; case 13 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET); break; case 14 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); break; case 15 : HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET); break; } } void FlagPlus(int *flag) { (*flag)++; if((*flag)==16) { (*flag)=12; } } ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ void _Error_Handler(char * file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif
復制代碼

三  重要的API。

復制代碼
//IO口使能, 注意這里是D口 __HAL_RCC_GPIOD_CLK_ENABLE(); //設置推挽輸出的IO口輸出電平為低 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); //設置推挽輸出的IO口輸出電平為高 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); //初始化一個IO口為輸入 GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); //初始化IO為推挽輸出 GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); //讀取一個輸入IO口的電平 HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11);


免責聲明!

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



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