网关外设驱动移植:HAL驱动架构与中断处理工程案例 - 第4节
4.1 GPIO 外设驱动移植概述
在物联网网关中,GPIO(General Purpose Input/Output)是最基础、使用最频繁的外设接口。无论是控制继电器、读取按键状态、驱动 LED 指示灯,还是模拟 I2C/SPI 时序,都离不开 GPIO 的精确配置与操作。本章将深入解析 HAL 库中 GPIO 驱动的核心 API,并结合中断配置,展示从裸机驱动到 HAL 驱动移植的完整工程案例。
4.2 HAL_GPIO_Init / DeInit 详解
4.2.1 HAL_GPIO_Init 函数原型与参数
HAL_GPIO_Init 是 GPIO 初始化的核心函数,负责配置引脚的工作模式、输出类型、上下拉电阻及速度。其函数原型如下:
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
| 参数 | 类型 | 说明 |
|---|---|---|
| GPIOx | GPIO_TypeDef* | GPIO 端口基地址,如 GPIOA、GPIOB |
| GPIO_Init | GPIO_InitTypeDef* | 初始化结构体指针,包含 Pin、Mode、Pull、Speed、Alternate |
GPIO_InitTypeDef 结构体关键成员:
- Pin:指定要配置的引脚,支持按位或运算同时配置多个引脚(如
GPIO_PIN_0 | GPIO_PIN_1)。 - Mode:工作模式,包括输入、输出、复用功能、模拟模式。
- Pull:上下拉电阻配置,可选无上下拉、上拉、下拉。
- Speed:输出速度等级,通常有低速、中速、高速、极高速。
- Alternate:复用功能选择,当 Mode 为复用功能时指定具体外设。
__HAL_RCC_GPIOx_CLK_ENABLE() 宏手动使能。
4.2.2 HAL_GPIO_DeInit 函数详解
HAL_GPIO_DeInit 用于将 GPIO 引脚恢复为默认复位状态,通常在系统休眠或外设卸载时调用。其原型为:
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
该函数会将指定引脚重置为输入浮空模式,并清除中断挂起标志。在中断驱动的应用中,DeInit 后需重新配置中断才能再次使用。
4.3 HAL_GPIO_WritePin / ReadPin 详解
4.3.1 输出控制:HAL_GPIO_WritePin
该函数用于设置 GPIO 引脚的电平状态,支持单个引脚或一组引脚同时操作。函数原型:
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
PinState 枚举值:
GPIO_PIN_RESET:输出低电平(0)GPIO_PIN_SET:输出高电平(1)
4.3.2 输入读取:HAL_GPIO_ReadPin
读取指定引脚的电平状态,返回 GPIO_PinState 枚举值。函数原型:
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
典型应用场景:
- 读取按键状态,实现按键检测
- 读取传感器数字输出引脚
- 读取外部中断触发后的电平确认
4.4 GPIO 中断配置
4.4.1 中断模式初始化
GPIO 中断配置需要在 HAL_GPIO_Init 的 Mode 参数中指定中断触发方式。HAL 库支持以下中断模式:
| 模式宏定义 | 触发方式 | 典型应用 |
|---|---|---|
| GPIO_MODE_IT_RISING | 上升沿触发 | 按键松开检测 |
| GPIO_MODE_IT_FALLING | 下降沿触发 | 按键按下检测 |
| GPIO_MODE_IT_RISING_FALLING | 双边沿触发 | 电平变化检测 |
| GPIO_MODE_IT_LOW | 低电平触发 | 低电平有效中断 |
| GPIO_MODE_IT_HIGH | 高电平触发 | 高电平有效中断 |
4.4.2 中断服务函数与回调机制
HAL 库采用弱定义回调函数机制,用户只需重写对应的回调函数即可处理中断事件。GPIO 中断回调函数为:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
中断处理流程:
- 硬件检测到 GPIO 电平变化,触发 EXTI 中断
- CPU 跳转到中断向量表,执行
EXTIx_IRQHandler - HAL 库的
HAL_GPIO_EXTI_IRQHandler被调用,清除中断挂起标志 - 该函数内部调用用户定义的
HAL_GPIO_EXTI_Callback - 用户在回调函数中根据 GPIO_Pin 参数判断具体引脚,执行相应逻辑
4.4.3 中断优先级配置
在 HAL 库中,GPIO 中断优先级通过 NVIC(嵌套向量中断控制器)配置。典型配置代码如下:
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // 设置抢占优先级和子优先级
HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 使能中断
4.5 工程案例:按键中断驱动 LED
4.5.1 硬件连接
| 外设 | 引脚 | 配置 |
|---|---|---|
| 按键 S1 | PA0 | 输入、下降沿中断、上拉 |
| LED D1 | PB0 | 推挽输出、高速 |
4.5.2 初始化代码
// 使能 GPIO 时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// 配置按键引脚 PA0 为中断输入
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置 LED 引脚 PB0 为推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置中断优先级并使能
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
4.5.3 中断回调函数实现
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_0)
{
// 按键按下,翻转 LED 状态
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
}
}
4.6 本章小结
本章详细讲解了 HAL 库中 GPIO 驱动的四个核心 API:HAL_GPIO_Init、HAL_GPIO_DeInit、HAL_GPIO_WritePin 和 HAL_GPIO_ReadPin,并深入分析了 GPIO 中断的配置流程与回调机制。通过按键中断驱动 LED 的工程案例,展示了从硬件初始化到中断响应的完整移植路径。掌握这些基础 API 和中断处理模式,是后续移植更复杂外设(如 UART、SPI、I2C)的重要前提。