打印
[应用相关]

STM32使用HAL库操作GPIO(转载)

[复制链接]
2791|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
磨砂|  楼主 | 2018-11-13 12:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一  初始化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。

沙发
磨砂|  楼主 | 2018-11-13 12:01 | 只看该作者
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。

使用特权

评论回复
板凳
磨砂|  楼主 | 2018-11-13 12:02 | 只看该作者
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口接的外部晶振。

使用特权

评论回复
地板
磨砂|  楼主 | 2018-11-13 12:03 | 只看该作者
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则为低电平。

使用特权

评论回复
5
磨砂|  楼主 | 2018-11-13 12:03 | 只看该作者
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)可调换顺序

使用特权

评论回复
6
磨砂|  楼主 | 2018-11-13 12:04 | 只看该作者
二  功能解释
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;

使用特权

评论回复
7
磨砂|  楼主 | 2018-11-13 12:04 | 只看该作者
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;
}





使用特权

评论回复
8
磨砂|  楼主 | 2018-11-13 12:04 | 只看该作者
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;
    }
}

使用特权

评论回复
9
磨砂|  楼主 | 2018-11-13 12:05 | 只看该作者
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;
    }
}

使用特权

评论回复
10
磨砂|  楼主 | 2018-11-13 12:06 | 只看该作者
5.标志变量自加。


void FlagPlus(int *flag)
{
    (*flag)++;
    if((*flag)==16)
    {
        (*flag)=12;
    }
}





这里一定要用指针,因为函数参数是值传递所以只能用指针来改变LEDNUM_Flag。

使用特权

评论回复
11
磨砂|  楼主 | 2018-11-13 12:06 | 只看该作者
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

使用特权

评论回复
12
磨砂|  楼主 | 2018-11-13 12:07 | 只看该作者
三  重要的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);


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

85

主题

3886

帖子

2

粉丝