GPIO初始化及调用
下面把 HAL 库 和 标准外设库(SPL) 初始化 GPIO 点亮/熄灭 LED 的完整步骤、示例代码和常用 API 逐一说清楚。用例默认 PC13 接 LED(蓝板常见;低电平点亮,高电平熄灭——若板子相反,只把写 1/0 对调即可)。
一、HAL 库:GPIO 初始化与点亮/熄灭 LED
步骤(通用顺序)
使能端口时钟
__HAL_RCC_GPIOx_CLK_ENABLE()
填写
GPIO_InitTypeDef
结构体(Pin/Mode/Speed …)调
HAL_GPIO_Init(GPIOx, &init)
完成配置用
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; // 选择 PC13gpio.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 msLED_Off(); // 熄灭HAL_Delay(300); // 延时 300 msLED_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_INPUT
、GPIO_MODE_ANALOG
GPIO_MODE_AF_PP / _AF_OD
(复用推挽/开漏)GPIO_MODE_IT_RISING/FALLING/RISING_FALLING
(外部中断)GPIO_MODE_EVT_*
(事件)
Speed
:GPIO_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
步骤
使能端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE)
填
GPIO_InitTypeDef
(Pin/Mode/Speed)调
GPIO_Init(GPIOx, &init)
用
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; // 输出速度 2MHzgpio.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 → 清零elseGPIO_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_Speed
:GPIO_Speed_2MHz / 10MHz / 50MHz
(仅对输出/复用输出有效)
三、图里 HAL GPIO 其他函数的作用(并给出 SPL 对应函数)
HAL 函数 | 作用(要点) | 关键参数 | SPL/等价做法 |
---|---|---|---|
HAL_GPIO_Init(GPIOx, &init) | 根据 Pin/Mode/Speed 配置端口(本质写 CRL/CRH) | GPIOx :端口;Pin 位图;Mode ;Speed | 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_PinState :GPIO_PIN_SET/RESET | GPIO_WriteBit/SetBits/ResetBits 或 GPIOx->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_IRQHandler 里 EXTI_GetITStatus /EXTI_ClearITPendingBit ,然后自己回调 |
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) | 弱定义(__weak)回调,用户重写做业务 | GPIO_Pin :触发的线 | SPL:自己写回调或在 IRQHandler 里直接处理 |
EXTI 的初始化(两库都需要额外步骤)
HAL:把引脚
Mode
设为GPIO_MODE_IT_*
,然后用HAL_NVIC_SetPriority
与HAL_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
),一次初始化多个引脚。