GPIO 方法详解

GPIO 方法详解

GPIO(General Purpose Input/Output)是 STM32 最基础的外设,用于控制引脚输出高低电平或读取外部信号。HAL 库把 GPIO 操作封装为几个简单直观的函数。

HAL_GPIO_Init

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);

参数拆解

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
//              │         │
//              │         └── GPIO 初始化参数结构体指针
//              └────────────────── GPIO 端口

功能

根据 GPIO_InitTypeDef 结构体中的参数,初始化指定 GPIO 端口的引脚。

GPIO_InitTypeDef 结构体

typedef struct {
    uint32_t Pin;        // 引脚编号,如 GPIO_PIN_13
    uint32_t Mode;       // 模式:输入/输出/复用/模拟/中断
    uint32_t Pull;       // 上下拉:NOPULL/PULLUP/PULLDOWN
    uint32_t Speed;      // 输出速度
    uint32_t Alternate;  // 复用功能(复用模式下使用)
} GPIO_InitTypeDef;

常用取值:

字段常见取值
ModeGPIO_MODE_INPUTGPIO_MODE_OUTPUT_PPGPIO_MODE_OUTPUT_ODGPIO_MODE_AF_PPGPIO_MODE_ANALOGGPIO_MODE_IT_RISINGGPIO_MODE_IT_FALLINGGPIO_MODE_IT_RISING_FALLING
PullGPIO_NOPULLGPIO_PULLUPGPIO_PULLDOWN
SpeedGPIO_SPEED_FREQ_LOWGPIO_SPEED_FREQ_MEDIUMGPIO_SPEED_FREQ_HIGH

示例

GPIO_InitTypeDef GPIO_InitStruct = {0};

__HAL_RCC_GPIOC_CLK_ENABLE();

GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;  // 开漏输出
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

使用任何 GPIO 前,必须先通过 __HAL_RCC_GPIOx_CLK_ENABLE() 开启对应端口的时钟,否则引脚不会响应。

HAL_GPIO_DeInit

void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);

参数拆解

HAL_GPIO_DeInit(GPIOC, GPIO_PIN_13);
//                │           │
//                │           └── 引脚编号
//                └──────────────── GPIO 端口

功能

将指定引脚恢复到复位后的默认状态(通常为浮空输入)。

示例

HAL_GPIO_DeInit(GPIOC, GPIO_PIN_13);

HAL_GPIO_WritePin

void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

参数拆解

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
//                  │           │              │
//                  │           │              └── 输出状态:SET / RESET
//                  │           └───────────────── 引脚编号
//                  └───────────────────────────── GPIO 端口

功能

设置指定 GPIO 引脚的输出电平。

示例

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);  // PC13 输出低电平
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);    // PC13 输出高电平

很多开发板上的 LED 是低电平点亮(一端接 VCC,另一端接引脚)。此时 GPIO_PIN_RESET 点亮 LED,GPIO_PIN_SET 熄灭 LED。

HAL_GPIO_ReadPin

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);

参数拆解

GPIO_PinState state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
//                                       │           │
//                                       │           └── 引脚编号
//                                       └─────────────── GPIO 端口

功能

读取指定 GPIO 引脚的当前电平状态。

返回值

返回值说明
GPIO_PIN_RESET低电平
GPIO_PIN_SET高电平

示例

if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
    // PA0 为高电平
}

读取按键时,通常需要配合软件消抖,避免机械触点的抖动导致误判。

HAL_GPIO_TogglePin

void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);

参数拆解

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
//                 │           │
//                 │           └── 引脚编号
//                 └─────────────── GPIO 端口

功能

翻转指定 GPIO 引脚的输出状态。如果当前是高电平,则变为低电平;反之亦然。

示例

while (1) {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);  // LED 翻转
    HAL_Delay(500);
}

外部中断相关函数

HAL_GPIO_EXTI_IRQHandler

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);

参数拆解

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
//                       │
//                       └── 触发中断的引脚编号

功能

GPIO 外部中断的统一入口处理函数,通常放在 EXTIx_IRQHandler 中调用。它会清除中断标志并调用 HAL_GPIO_EXTI_Callback

示例

void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

HAL_GPIO_EXTI_Callback

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

参数拆解

void HAL_GPIO_EXTI_Callback(GPIO_PIN_0)
//                          │
//                          └── 触发中断的引脚编号

功能

GPIO 外部中断回调函数,用户在该函数中编写中断处理逻辑。

示例

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_0) {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
}

完整示例:按键控制 LED

// PC13 配置为开漏输出,驱动 LED
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

// PA0 配置为输入,读取按键(假设按键另一端接地,使用内部上拉)
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

while (1) {
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
        HAL_Delay(20);  // 简单消抖
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
            HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
            while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);  // 等待释放
        }
    }
}