(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
*/