1. GPIO输出控制LED闪烁

GPIO输出控制LED闪烁 学习卡片

任务说明

本案例要求基于HAL(硬件抽象层)完成GPIO的初始化与输出控制,实现LED定时闪烁。核心目标是建立一套可复用的GPIO驱动接口,使上层应用无需关心具体寄存器操作,仅通过HAL函数即可控制LED状态。案例将实现完整的初始化、状态切换和延时控制闭环,并提供可观测的验证方法。

HAL接口设计

为体现HAL的抽象与复用特性,定义以下最小接口集:

  • HAL_GPIO_Init():配置引脚为推挽输出模式,初始电平为低;
  • HAL_GPIO_WritePin():设置引脚高/低电平;
  • HAL_GPIO_TogglePin():翻转引脚当前电平;
  • HAL_Delay():毫秒级阻塞延时。

接口内部通过结构体封装引脚号与端口基地址,屏蔽底层寄存器差异。本案例以STM32F103系列为参考硬件,但HAL层代码与具体MCU解耦,仅需修改底层映射即可移植到其他平台。

代码实现


// hal_gpio.h
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

#include <stdint.h>

typedef struct {
    volatile uint32_t *port;   // GPIO端口基地址
    uint16_t pin;              // 引脚编号 (0-15)
} GPIO_Handle_t;

void HAL_GPIO_Init(GPIO_Handle_t *gpio);
void HAL_GPIO_WritePin(GPIO_Handle_t *gpio, uint8_t state);
void HAL_GPIO_TogglePin(GPIO_Handle_t *gpio);
void HAL_Delay(uint32_t ms);

#endif

// hal_gpio.c
#include "hal_gpio.h"

// 模拟寄存器映射(实际使用时替换为具体MCU头文件)
#define RCC_APB2ENR   (*(volatile uint32_t *)0x40021018)
#define GPIOB_CRL     (*(volatile uint32_t *)0x40010C00)
#define GPIOB_ODR     (*(volatile uint32_t *)0x40010C0C)

void HAL_GPIO_Init(GPIO_Handle_t *gpio) {
    // 使能GPIOB时钟(以PB0为例)
    RCC_APB2ENR |= (1 << 3);
    
    // 配置为推挽输出,50MHz(CRL寄存器低4位)
    uint32_t crl = GPIOB_CRL;
    crl &= ~(0xF << (gpio->pin * 4));
    crl |= (0x2 << (gpio->pin * 4));  // 0x2 = 输出模式, 50MHz
    GPIOB_CRL = crl;
    
    // 初始输出低电平
    GPIOB_ODR &= ~(1 << gpio->pin);
}

void HAL_GPIO_WritePin(GPIO_Handle_t *gpio, uint8_t state) {
    if (state) {
        GPIOB_ODR |= (1 << gpio->pin);
    } else {
        GPIOB_ODR &= ~(1 << gpio->pin);
    }
}

void HAL_GPIO_TogglePin(GPIO_Handle_t *gpio) {
    GPIOB_ODR ^= (1 << gpio->pin);
}

void HAL_Delay(uint32_t ms) {
    // 简单软件延时(实际应使用定时器)
    for (volatile uint32_t i = 0; i < ms * 8000; i++);
}

// main.c
#include "hal_gpio.h"

int main(void) {
    GPIO_Handle_t led;
    led.port = (volatile uint32_t *)0x40010C00;  // GPIOB基地址
    led.pin = 0;                                  // PB0接LED
    
    HAL_GPIO_Init(&led);
    
    while (1) {
        HAL_GPIO_TogglePin(&led);
        HAL_Delay(500);  // 500ms翻转一次,周期1s
    }
}

SVG:GPIO输出控制时序与验证观测点

GPIO输出控制LED闪烁——时序与观测点 t (ms) 0 500 1000 1500 2000 高 低 T = 1000ms 验证观测点: ① 示波器CH1接PB0,观察方波输出,频率应为1Hz(周期1s) ② 高电平时间500ms ± 50ms,低电平时间500ms ± 50ms ③ 若LED串联限流电阻(约330Ω),目视应每秒闪烁一次 HAL_GPIO_TogglePin() HAL_Delay(500)

编译与运行

将hal_gpio.h、hal_gpio.c、main.c加入工程。若使用STM32标准库或HAL库环境,需将hal_gpio.c中的寄存器地址替换为实际定义(如RCC->APB2ENR、GPIOB->CRL、GPIOB->ODR)。编译烧录后,LED应持续闪烁。

验证方法与判定标准

静态检查:确认HAL_GPIO_Init()中时钟使能位与引脚模式配置正确,HAL_GPIO_TogglePin()使用异或操作翻转ODR寄存器对应位。

动态验证:使用示波器探头连接PB0引脚与GND,上电后应观察到频率为1Hz的方波。高电平持续时间应为500ms±50ms。若使用逻辑分析仪,可同时观察RCC使能时序与ODR翻转时刻的对应关系。

判定通过条件:示波器显示方波周期为1s±0.1s,占空比约50%,且LED目视闪烁频率稳定。若波形异常,优先检查延时函数参数(当前软件延时依赖CPU主频,若主频非72MHz需调整HAL_Delay循环次数)。