STM32 HAL库学习(一):GPIO and EXIT

0. 写在前面的话

ST先后提供了两种库:标准库和HAL库。

STM32芯片面世之初只提供了丰富全面的编撰库,大大便利了用户程序开发。

大约在2014年左右,ST在标准库的基础上又推出了HAL库。实际上HAL库和标准库本质上是一样的,都是提供底层硬件操作API,而且使用上也是大同小异。

ST这几年大力推广HAL库,是因为HAL的结构更加容易整合STM32Cube,而STM32CubeMX是ST这几年极力推荐的程序生成开发工具,它能够通过图形化界面设置生成芯片初始化代码,让用户专注于应用层面的开发。

1. HAL库

1.1 HAL文件结构

HAL 库文件可以分为两部分:库文件和用户级别文件,详细列举如下:

库文件:
	stm32f2xx_hal_ppp.c/.h			// 主要的外设或者模块的驱动源文件,包含了该外设的通用API
	stm32f2xx_hal_ppp_ex.c/.h		// 外围设备或模块驱动程序的扩展文件。这组文件中包含特定型号或者系列的芯片的特殊API。以及如果该特定的芯片内部有不同的实现方式,则该文件中的特殊API将覆盖_ppp中的通用API。
	stm32f2xx_hal.c/.h				// 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的时间延迟等相关的API
	其他库文件
用户级别文件:
	stm32f2xx_hal_msp_template.c	// 只有.c没有.h。它包含用户应用程序中使用的外设的MSP初始化和反初始化(主程序和回调函数)。使用者复制到自己目录下使用模板。
	stm32f2xx_hal_conf_template.h	// 用户级别的库配置文件模板。使用者复制到自己目录下使用
	system_stm32f2xx.c				// 此文件主要包含SystemInit()函数,该函数在刚复位及跳到main之前的启动过程中被调用。 **它不在启动时配置系统时钟(与标准库相反)**。 时钟的配置在用户文件中使用HAL API来完成。
	startup_stm32f2xx.s				// 芯片启动文件,主要包含堆栈定义,终端向量表等
	stm32f2xx_it.c/.h				// 中断处理函数的相关实现
	main.c/.h						//

其中,库文件中的 ppp 代表着 STM32 的外设,如ADC、GPIO等。

用户级别文件中,除了常用的主函数 main.c,还应重点关注与中断相关的 stm32f2xx_it.c/.h 和 MSP 相关的stm32f2xx_hal_msp_template.c 文件,MSP 在下面有详细介绍。

1.2 HAL库初始化

HAL_Init() 是主函数中首要处理的函数,主要用来初始化HAL库。

HAL_Init();

即用来初始化所有的外围设备,Flash接口和系统定时器,系统中断组,初始化低级别硬件这个函数不能修改,return HAL_OK向函数返回一个值,代表函数编译成功。

HAL_StatusTypeDef HAL_Init(void)
{
     
  /* Configure Flash prefetch, Instruction cache, Data cache */ 
#if (INSTRUCTION_CACHE_ENABLE != 0U)
   __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();  // 配置指令缓存使能
#endif /* INSTRUCTION_CACHE_ENABLE */

#if (DATA_CACHE_ENABLE != 0U)
   __HAL_FLASH_DATA_CACHE_ENABLE();  // 配置数据缓存使能
#endif /* DATA_CACHE_ENABLE */

#if (PREFETCH_ENABLE != 0U)
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();  // 配置Flash预读取使能
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);  

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

1.3 HAL库函数状态

在HAL库中,HAL_StatusTypeDef 函数状态一共有四种状态,分别是:成功,错误,忙碌,超时。具体值如下:

typedef enum 
{
     
  HAL_OK       = 0x00U,
  HAL_ERROR    = 0x01U,
  HAL_BUSY     = 0x02U,
  HAL_TIMEOUT  = 0x03U
} HAL_StatusTypeDef;
HAL_Delay(500)// HAL库自带的延时函数,单位毫秒

1.4 xxxx_HandleTypeDef

在 HAL 库中,将外设可能用到的变量、结构体、函数、锁等都封装在一个大的结构体中,可以通过 xxxx_HandleTypeDef 来定义,比如:

I2C_HandleTypeDef hi2c1;

UART_HandleTypeDef huart4;

DMA_HandleTypeDef hdma_usart1_rx;

IWDG_HandleTypeDef hiwdg;

这里以串口为例,UART_HandleTypeDef 中的成员如下:

  • 其中,包含了我们在标准库中常用的初始化结构体 UART_InitTypeDef
typedef struct
{
     
  USART_TypeDef            *Instance;        /*!< UART registers base address        */

  UART_InitTypeDef         Init;             /*!< UART communication parameters      */

  UART_AdvFeatureInitTypeDef AdvancedInit;   /*!< UART Advanced Features initialization parameters */

  uint8_t                  *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */

  uint16_t                 TxXferSize;       /*!< UART Tx Transfer size              */

  __IO uint16_t            TxXferCount;      /*!< UART Tx Transfer Counter           */

  uint8_t                  *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */

  uint16_t                 RxXferSize;       /*!< UART Rx Transfer size              */

  __IO uint16_t            RxXferCount;      /*!< UART Rx Transfer Counter           */

  uint16_t                 Mask;             /*!< UART Rx RDR register mask          */

  DMA_HandleTypeDef        *hdmatx;          /*!< UART Tx DMA Handle parameters      */

  DMA_HandleTypeDef        *hdmarx;          /*!< UART Rx DMA Handle parameters      */

  HAL_LockTypeDef           Lock;            /*!< Locking object                     */

  __IO HAL_UART_StateTypeDef    gState;      /*!< UART state information related to global Handle management 
                                                  and also related to Tx operations.
                                                  This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO HAL_UART_StateTypeDef    RxState;     /*!< UART state information related to Rx operations.
                                                  This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO uint32_t             ErrorCode;       /*!< UART Error code                    */

}UART_HandleTypeDef;

2. GPIO

2.1 常用函数

GPIO八大函数功能

// 相对于标准库,函数名前多了 HAL_
// 读取 GPIO 状态 
GPIO_PinState     HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 控制 GPIO 状态:
//   *  GPIO_PIN_RESET:清0
//   *  GPIO_PIN_SET:置1
void              HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
// 翻转 GPIO 状态
void              HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 中断控制器
void              HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
// 中断回调函数
void              HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

// GPIO 初始化函数
void              HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init);
// GPIO 反初始化函数,恢复默认值
void              HAL_GPIO_DeInit(GPIO_TypeDef  *GPIOx, uint32_t GPIO_Pin);

2.2 HAL_GPIO_Init 配置

功能:对STM32中的某端口上的引脚进行初始化(设置引脚输入输出的连接关系)。(1)参数1(GPIO_TypeDef *GPIOx ):GPIO_TypeDef——包含I/O口所有寄存器的结构体名;*GPIOx——指向x I/O口的地址
(2)参数2(GPIO_InitTypeDef *GPIO_Init)
GPIO_InitTypeDef——包含I/O口所有参数的结构体名;*GPIO_Init——指向I/O口所有参数的地址

// GPIO_TypeDef结构体成员
typedef struct
{
     
  __IO uint32_t MODER; //模式寄存器
  __IO uint32_t OTYPER; //输出类型寄存器
  __IO uint32_t OSPEEDR; //输出速度寄存器
  __IO uint32_t PUPDR; //上拉/下拉寄存器
  __IO uint32_t IDR;  //输入数据寄存器
  __IO uint32_t ODR;  //输出数据寄存器
  __IO uint32_t BSRR; //置位/清除寄存器
  __IO uint32_t LCKR; //配置锁定寄存器
  __IO uint32_t AFR[2]; //端口复用功能寄存器
  __IO uint32_t BRR;  //复位寄存器
}GPIO_TypeDef;
// *GPIOx指向GPIO口的地址参数为:
#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
// GPIO_InitTypeDef结构体成员
typedef struct
{
     
  uint32_t Pin; // A 选定将被配置的GPIO引脚
  uint32_t Mode;   // B 指定选定的引脚运行模式
  uint32_t Pull; // C 指定选定的引脚上拉或下拉
  uint32_t Speed; // D 指定选定的引脚速度——只有在输出模式下才配置
  uint32_t Alternate; // E 复用功能连通选定的引脚
}GPIO_InitTypeDef;
A 参数可以为:
#define GPIO_PIN_0                 //Pin 0 selected    
#define GPIO_PIN_1                 //Pin 1 selected 
……
#define GPIO_PIN_15                //Pin 15 selected   
#define GPIO_PIN_All               //All pins selected
B 参数可以为
#define  GPIO_MODE_INPUT        //浮空输入模式
#define  GPIO_MODE_OUTPUT_PP    //通用推挽输出模式
#define  GPIO_MODE_OUTPUT_OD    //通用开漏输出模式
/*开漏输出只能输出低电平,类似于三极管的集电极,要输出高电平需要上拉电阻才能输出*/
#define  GPIO_MODE_AF_PP        //复用功能推挽模式 
#define  GPIO_MODE_AF_OD       //复用功能开漏模式
#define  GPIO_MODE_IT_RISING   //外部中断,上升沿触发
#define  GPIO_MODE_IT_FALLING  //外部中断,下降沿触发
#define  GPIO_MODE_IT_RISING_FALLING //外部中断,双边沿触发
C 参数可为:
#define  GPIO_NOPULL        //无上位或下拉  
#define  GPIO_PULLUP        //上拉                  
#define  GPIO_PULLDOWN      //下拉
D 参数可为:
#define  GPIO_SPEED_FREQ_LOW             //最大速度0.4MHz
#define  GPIO_SPEED_FREQ_MEDIUM        //最大速度2MHz   
#define  GPIO_SPEED_FREQ_HIGH             //最大速度10MHz 
#define  GPIO_SPEED_FREQ_VERY_HIGH //最大速度35MHz
E 参数可为:
#define GPIO_AF0_EVENTOUT      // EVENTOUT 复用功能映射 
#define GPIO_AF0_TIM21         // TIM21 复用功能映射    
#define GPIO_AF0_SPI1          // SPI1 复用功能映射     
#define GPIO_AF0_USART2        // USART2 复用功能映射   
#define GPIO_AF0_MCO           // MCO 复用功能映射      
#define GPIO_AF0_SWDIO         // SWDIO 复用功能映射    
#define GPIO_AF0_SWCLK         // SWCLK 复用功能映射

2.3 HAL_GPIO_Init 应用

GPIO应用教程
要求:将STM32引脚A0、A2端口设置为推挽输出模式、输出速度10MHz。
注意:在配置STM32外设的时候,任何时候都要先使能该外设的时钟。

1)定义结构体变量
(2)使能时钟
(3)配置初始化电平
(4)通过结构体变量初始化GPIO
HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init);
static void MX_GPIO_Init(void)
{
     
  GPIO_InitTypeDef   GPIO_InitStruct; // 定义一个结构体变量,后缀 TypeDef 声明类型别名
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能A端口时钟
  /*Configure GPIO pin : PA0 PA2*/
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2; //选择引脚
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //引脚工作模式
  GPIO_InitStruct.Pull = GPIO_NOPULL; //引脚上下拉电阻
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //引脚输出速度
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //调用引脚初始化程序
}

2.4 GPIO.Mode

此处参考标准库中的 8 种输入输出模式进行理解。GPIO输入输出模式讲解
Q1:在STM32中选用怎样选择I/O模式?

  • 浮空输入_IN_FLOATING ——浮空输入,输入电平不确定,可以做按键识别,RX1
  • 带上拉输入_IPU——IO内部上拉电阻输入,无信号输入时为高电平
  • 带下拉输入_IPD—— IO内部下拉电阻输入,无信号输入时为低电平
  • 模拟输入_AIN ——应用ADC模拟输入,或者低功耗下省电
  • 开漏输出_OUT_OD ——IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能
  • 推挽输出_OUT_PP ——IO输出0-接GND, IO输出1 -接VCC,可输出高低电平
  • 复用功能的推挽输出_AF_PP ——片内外设功能(I2C的SCL、SDA)
  • 复用功能的开漏输出_AF_OD——片内外设功能(TX1、MOSI、MISO.SCK.SS)

Q2:开漏输出和推挽输出的区别?

  • 开漏输出:只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极。适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内);
  • 推挽输出:可以输出强高、低电平,连接数字器件。

Q3:什么是上下拉电阻?

  • 上拉电阻:把一个不确定的信号通过电阻连接到高电平,是电信号初始化为高电平。
  • 下拉电阻:把一个不确定的信号通过电阻连接到高电平,使电信号初始为低电平。
    STM32 HAL库学习(一):GPIO and EXIT_第1张图片

3. EXIT

3.1 EXIT 简介

EXIT (External interrupt/event controller)——外部中断/事件控制器,管理了控制器的中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
STM32 HAL库学习(一):GPIO and EXIT_第2张图片
下图是中断线的映射图,每个中断线可以对应多个GPIO口,但每次只能连接到一个IO口上。
STM32 HAL库学习(一):GPIO and EXIT_第3张图片
EXIT —— 外部中断
IRQ —— 中断请求
NVIC ——嵌套向量中断控制器,简称中断控制器,位于Cortex内核中。
NVIC 等级最高,不仅掌管着 EXIT 中断,还管理着串口中断、定时器中断等其他中断。
STM32 HAL库学习(一):GPIO and EXIT_第4张图片

3.2 外部中断配置流程

1)使能 GPIO 时钟;
(2)中断出发方式设置;
(3)配置中断优先级,并使能中断
(4)编写中断服务函数: HAL_GPIO_EXIT_IRQHandler;
(5)编写中断处理回调函数: HAL_GPIO_EXIT_Callback;

举例

// GPIO 句柄
GPIO_InitTypeDef GPIO_Initure;
// (1) 使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE;

// (2) 触发方式
GPIO_Initure.Pin = GPIO_Pin_0;
GPIO_Initure.Mode = GPIO_MODE_IT_RISING;
GPIO_Initure.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);

// (3) 设置中断优先级
HAL_NVIC_SetPriority(EXIT0_IRQn,0,0);
HAL_NVIC_EnableIRQ(EXIT0_IRQn,0,0);

3.3 回调函数

(1)外部中断共用入口函数

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);

这个函数是外部中断服务函数,用来响应外部中断的触发,函数实体里面有两个功能,1是清除中断标记位,2是调用下面要介绍的回调函数。
(2)回调函数

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

可以理解为中断函数具体要响应的动作。
中断触发后,就自动的把中断处理函数包含进来了。中断函数除了简单的处理完套路中的清理中断标志外就是调用回调函数。回调函数才是我们中断函数内要做的事情。

你可能感兴趣的:(STM32,HAL库)