GPIO初始化及调用

发布于:2025-08-18 ⋅ 阅读:(19) ⋅ 点赞:(0)

下面把 HAL 库标准外设库(SPL) 初始化 GPIO 点亮/熄灭 LED 的完整步骤、示例代码和常用 API 逐一说清楚。用例默认 PC13 接 LED(蓝板常见;低电平点亮,高电平熄灭——若板子相反,只把写 1/0 对调即可)。

一、HAL 库:GPIO 初始化与点亮/熄灭 LED

步骤(通用顺序)

  1. 使能端口时钟 __HAL_RCC_GPIOx_CLK_ENABLE()

  2. 填写 GPIO_InitTypeDef 结构体(Pin/Mode/Speed …)

  3. HAL_GPIO_Init(GPIOx, &init) 完成配置

  4. HAL_GPIO_WritePin / TogglePin / ReadPin 控制或读引脚
    (可选)5) 若需 EXTI:还要配置中断优先级并使能 NVIC,使用 HAL_GPIO_EXTI_IRQHandler/HAL_GPIO_EXTI_Callback

示例代码(HAL)

led.h

#ifndef __LED_H__
#define __LED_H__

#include "stm32f1xx_hal.h"

/* ====== 硬件相关宏定义 ====== */
#define LED_GPIO_PORT      GPIOC        // LED 所在的端口(此处为 GPIOC)
#define LED_GPIO_PIN       GPIO_PIN_13  // LED 引脚号(PC13)

/* ====== LED 控制函数声明 ====== */
void LED_Init(void);     // 初始化 LED 引脚
void LED_On(void);       // 点亮 LED
void LED_Off(void);      // 熄灭 LED
void LED_Toggle(void);   // 翻转 LED 状态

#endif

led.c:

#include "led.h"

/**
  * @brief  初始化 LED 引脚
  * @note   配置为推挽输出,默认熄灭(PC13高电平)
  */
void LED_Init(void)
{
    /* 1. 使能 GPIOC 时钟(如果不打开,GPIO 寄存器无法操作) */
    __HAL_RCC_GPIOC_CLK_ENABLE();

    /* 2. 配置 GPIO 参数 */
    GPIO_InitTypeDef gpio = {0};              // 定义配置结构体并清零
    gpio.Pin   = LED_GPIO_PIN;                // 选择 PC13
    gpio.Mode  = GPIO_MODE_OUTPUT_PP;         // 推挽输出模式
    gpio.Speed = GPIO_SPEED_FREQ_LOW;         // 低速输出(足够驱动 LED)
    HAL_GPIO_Init(LED_GPIO_PORT, &gpio);      // 初始化 GPIOC 的 13 引脚

    /* 3. 缺省熄灭 LED(PC13 高电平 = 灭) */
    HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_SET);
}

/**
  * @brief 点亮 LED
  */
void LED_On(void)
{
    HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_RESET); // PC13 输出低电平
}

/**
  * @brief 熄灭 LED
  */
void LED_Off(void)
{
    HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_SET);   // PC13 输出高电平
}

/**
  * @brief 翻转 LED 状态
  */
void LED_Toggle(void)
{
    HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PIN);                // HAL 内部用 BSRR 实现
}

main.c

#include "stm32f1xx_hal.h"
#include "led.h"

/* 系统时钟配置函数(具体实现依赖 CubeMX 或手写) */
static void SystemClock_Config(void);

int main(void)
{
    /* 1. HAL 库初始化:包括时钟源、SysTick 配置等 */
    HAL_Init();

    /* 2. 配置系统时钟(比如 HSE=8MHz → SYSCLK=72MHz) */
    SystemClock_Config();

    /* 3. 初始化 LED 引脚 */
    LED_Init();

    /* 4. 主循环:控制 LED 闪烁 */
    while (1)
    {
        LED_On();       // 点亮
        HAL_Delay(300); // 延时 300 ms

        LED_Off();      // 熄灭
        HAL_Delay(300); // 延时 300 ms

        LED_Toggle();   // 翻转状态
        HAL_Delay(300); // 延时 300 ms
    }
}

/* ===== 系统时钟配置函数(此处仅示意,实际需根据工程生成) ===== */
static void SystemClock_Config(void)
{
    /* 如果使用 CubeMX,一般会自动生成这里的代码。
       自己手写时,需要配置 HSE/PLL,把 SYSCLK 提升到 72MHz。
       如果不写,默认 SystemInit() 可能只运行在 8MHz HSI。 */
}

HAL 结构体/参数要点(F1)

  • Pin:引脚位图,可或起来(如 GPIO_PIN_0 | GPIO_PIN_1)。

  • Mode

    • GPIO_MODE_OUTPUT_PP / _OD(推挽/开漏)

    • GPIO_MODE_INPUTGPIO_MODE_ANALOG

    • GPIO_MODE_AF_PP / _AF_OD(复用推挽/开漏)

    • GPIO_MODE_IT_RISING/FALLING/RISING_FALLING(外部中断)

    • GPIO_MODE_EVT_*(事件)

  • SpeedGPIO_SPEED_FREQ_LOW/MEDIUM/HIGH(≈2/10/50 MHz)

注:F1 的 HAL 不带 Pull 字段(上拉/下拉由 CRL/CRH 的 CNF 决定;若要上拉/下拉,需把 Mode 设为输入并用 ODR 置 1/0 完成上/下拉,或直接用 HAL 的 GPIO_MODE_INPUT + 后续写 ODR)。

二、标准外设库(SPL):GPIO 初始化与点亮/熄灭 LED

步骤

  1. 使能端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE)

  2. GPIO_InitTypeDef(Pin/Mode/Speed)

  3. GPIO_Init(GPIOx, &init)

  4. GPIO_SetBits / ResetBits / WriteBit 控制

示例代码(SPL)

led.h:

#ifndef __LED_H__
#define __LED_H__

#include "stm32f10x.h"

/* ====== 硬件相关宏定义 ====== */
#define LED_GPIO_PORT      GPIOC                  // LED 所在端口
#define LED_GPIO_PIN       GPIO_Pin_13            // LED 引脚 PC13
#define LED_GPIO_CLK       RCC_APB2Periph_GPIOC   // GPIOC 时钟

/* ====== LED 控制函数声明 ====== */
void LED_Init(void);     // 初始化 LED 引脚
void LED_On(void);       // 点亮 LED
void LED_Off(void);      // 熄灭 LED
void LED_Toggle(void);   // 翻转 LED 状态

#endif

led.c:

#include "led.h"

/**
  * @brief  初始化 LED 引脚
  * @note   PC13 配置为推挽输出,默认熄灭
  */
void LED_Init(void)
{
    /* 1. 使能 GPIOC 时钟 */
    RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);

    /* 2. 配置 PC13 为推挽输出 */
    GPIO_InitTypeDef gpio;
    gpio.GPIO_Pin   = LED_GPIO_PIN;      // 选择引脚
    gpio.GPIO_Speed = GPIO_Speed_2MHz;   // 输出速度 2MHz
    gpio.GPIO_Mode  = GPIO_Mode_Out_PP;  // 推挽输出
    GPIO_Init(LED_GPIO_PORT, &gpio);

    /* 3. 缺省熄灭 LED(PC13 高电平 = 灭) */
    GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN);
}

/**
  * @brief 点亮 LED
  */
void LED_On(void)
{
    GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); // 低电平
}

/**
  * @brief 熄灭 LED
  */
void LED_Off(void)
{
    GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN);   // 高电平
}

/**
  * @brief 翻转 LED 状态
  */
void LED_Toggle(void)
{
    if (GPIO_ReadOutputDataBit(LED_GPIO_PORT, LED_GPIO_PIN))
        GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); // 如果当前是 1 → 清零
    else
        GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN);   // 如果当前是 0 → 置 1
}

main.c:

#include "stm32f10x.h"
#include "led.h"

/* 时钟配置函数 */
static void Clock_Config(void);

int main(void)
{
    /* 1. 配置系统时钟(如果需要) */
    Clock_Config();

    /* 2. 初始化 LED 引脚 */
    LED_Init();

    /* 3. 主循环:控制 LED 闪烁 */
    while (1)
    {
        LED_On();   // 点亮
        for(volatile int i=0;i<600000;i++);  // 简单延时

        LED_Off();  // 熄灭
        for(volatile int i=0;i<600000;i++);

        LED_Toggle(); // 翻转状态
        for(volatile int i=0;i<600000;i++);
    }
}

/**
  * @brief  时钟配置
  * @note   SPL 启动文件里默认调用 SystemInit(),会把 HSE/PLL 配置成 72MHz。
  *         如果已经够用,这里可以留空。
  */
static void Clock_Config(void)
{
    /* 一般用默认 SystemInit 即可 */
}

SPL 结构体/参数要点

  • GPIO_Mode

    • GPIO_Mode_AIN(模拟输入)

    • GPIO_Mode_IN_FLOATING(浮空输入)

    • GPIO_Mode_IPD / GPIO_Mode_IPU(下拉/上拉输入)

    • GPIO_Mode_Out_PP / _Out_OD(通用推挽/开漏输出)

    • GPIO_Mode_AF_PP / _AF_OD(复用推挽/开漏输出)

  • GPIO_SpeedGPIO_Speed_2MHz / 10MHz / 50MHz(仅对输出/复用输出有效)

三、图里 HAL GPIO 其他函数的作用(并给出 SPL 对应函数)

HAL 函数 作用(要点) 关键参数 SPL/等价做法
HAL_GPIO_Init(GPIOx, &init) 根据 Pin/Mode/Speed 配置端口(本质写 CRL/CRH) GPIOx:端口;Pin 位图;ModeSpeed GPIO_Init(GPIOx, &init)
HAL_GPIO_DeInit(GPIOx, GPIO_Pin) 复位指定引脚到缺省(模拟输入),清除 EXTI 绑定 GPIO_Pin 位图 GPIO_DeInit(GPIOx)(注意 SPL 是“整个端口复位”;单独复位需手写寄存器)
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PinState) 通过 BSRR 原子置 1/清 0 GPIO_PinStateGPIO_PIN_SET/RESET GPIO_WriteBit/SetBits/ResetBitsGPIOx->BSRR/BRR
HAL_GPIO_TogglePin(GPIOx, GPIO_Pin) 翻转输出(对 ODR 异或) GPIO_Pin 位图 无直接 API,可 GPIO_WriteBit(GPIOx,pin, (BitAction)!GPIO_ReadOutputDataBit(...)) 或操作 ODR
HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) IDR,返回 GPIO_PIN_SET/RESET GPIO_Pin GPIO_ReadInputDataBit(GPIOx, pin)
HAL_GPIO_LockPin(GPIOx, GPIO_Pin) 通过 LCKR 锁定配置,直到下次复位(防误改) GPIO_Pin 位图 GPIO_PinLockConfig(GPIOx, pin)
HAL_GPIO_EXTI_IRQHandler(GPIO_Pin) 通用 EXTI 线中断处理:清挂起位并调用回调 GPIO_Pin:哪条线触发 SPL:在 EXTIxx_IRQHandlerEXTI_GetITStatus/EXTI_ClearITPendingBit,然后自己回调
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 弱定义(__weak)回调,用户重写做业务 GPIO_Pin:触发的线 SPL:自己写回调或在 IRQHandler 里直接处理

EXTI 的初始化(两库都需要额外步骤)

  • HAL:把引脚 Mode 设为 GPIO_MODE_IT_*,然后用 HAL_NVIC_SetPriorityHAL_NVIC_EnableIRQ 开中断即可。

  • SPL:GPIO_EXTILineConfig(AFIO_PORTx, PinSourcex) + EXTI_Init(&cfg) + NVIC_Init(&nvic)

四、常见易错点与小技巧

  • 时钟别忘开:F1 的 GPIO 都在 APB2,HAL 用 __HAL_RCC_GPIOx_CLK_ENABLE();SPL 用 RCC_APB2PeriphClockCmd(...)

  • 蓝板 PC13 低电平点亮:别把“写 1 点亮”写反。

  • 原子操作首选 BSRR:HAL 的 WritePin/TogglePin 已经用 BSRR,SPL 用 GPIOx->BSRR/BRR 更安全。

  • 速度只对输出有效:输入模式时 Speed 无意义。

  • 锁定功能:量产固件防误改时可用 HAL_GPIO_LockPin / GPIO_PinLockConfig

  • 多脚同时配置Pin 可位或(如 GPIO_PIN_0|GPIO_PIN_1),一次初始化多个引脚。


网站公告

今日签到

点亮在社区的每一天
去签到