1. 初始函数 GPIO_Init
在 STM32 的 HAL 库开发中,GPIO_Init 是我们接触最多的初始化函数之一。无论是点亮 LED、读取按键,还是驱动外设,第一步几乎都是配置 GPIO。理解这个函数的内部实现,能帮助我们真正掌握 STM32 的寄存器操作,而不是停留在"照着 CubeMX 生成的代码抄一遍"的层面。
本文将从 GPIO_InitTypeDef 结构体、时钟使能、引脚按位或、寄存器配置到 HAL_GPIO_Init() 的完整源码逐段拆解,带你彻底看懂 GPIO 初始化的底层原理。

1.1 GPIO_InitTypeDef 结构体
GPIO_InitTypeDef 是一个结构体类型,用来描述一个 GPIO 的配置。= {0} 表示所有成员初始化为 0,防止出现随机值导致配置错误。下图是结构体成员:

1.2 使能 GPIO 时钟
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
STM32 中任何外设使用前必须先打开时钟,否则寄存器写入无效。这里打开了 GPIOF 和 GPIOA 两个端口的时钟。
为什么必须开时钟? STM32 为了降低功耗,默认情况下所有外设时钟都是关闭的。只有先通过 RCC(Reset and Clock Control)寄存器打开对应外设的时钟,该外设的寄存器才能被读写。如果忘记开时钟,配置的寄存器值会被直接丢弃,引脚不会有任何反应。

1.3 按位或与引脚选择

因为在 HAL 库内部,一组引脚是用一个 16 位整数表示的。比如你想同时配置第 8 和第 9 号引脚,只要"按位或"起来:
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_PIN_8 的值是 0x0100(二进制 0000 0001 0000 0000),GPIO_PIN_9 的值是 0x0200(二进制 0000 0010 0000 0000),两者按位或的结果是 0x0300,正好用 16 位整数同时表示两个引脚。这种设计让 HAL 库可以一次配置多个引脚,非常高效。
端口配置寄存器
有低寄存器和高寄存器,用高寄存器还是低寄存器具体看用什么引脚
mode设置是输入还是输出
cnf设置是什么输入什么输出,通用推挽/通用开漏/复用推挽/复用开漏
HAL_GPIO_Init()
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t position = 0x00u;
uint32_t ioposition;
uint32_t iocurrent;
uint32_t temp;
uint32_t config = 0x00u;
__IO uint32_t *configregister;
uint32_t registeroffset;
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
while (((GPIO_Init->Pin) >> position) != 0x00u)
{
ioposition = (0x01uL << position);
iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;
if (iocurrent == ioposition)
{
assert_param(IS_GPIO_AF_INSTANCE(GPIOx));
switch (GPIO_Init->Mode)
{
case GPIO_MODE_OUTPUT_PP:
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_PP;
break;
case GPIO_MODE_OUTPUT_OD:
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_OD;
break;
case GPIO_MODE_AF_PP:
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_PP;
break;
case GPIO_MODE_AF_OD:
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_OD;
break;
case GPIO_MODE_INPUT:
case GPIO_MODE_IT_RISING:
case GPIO_MODE_IT_FALLING:
case GPIO_MODE_IT_RISING_FALLING:
case GPIO_MODE_EVT_RISING:
case GPIO_MODE_EVT_FALLING:
case GPIO_MODE_EVT_RISING_FALLING:
assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
if (GPIO_Init->Pull == GPIO_NOPULL)
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_FLOATING;
}
else if (GPIO_Init->Pull == GPIO_PULLUP)
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;
GPIOx->BSRR = ioposition;
}
else
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;
GPIOx->BRR = ioposition;
}
break;
case GPIO_MODE_ANALOG:
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_ANALOG;
break;
default:
break;
}
configregister = (iocurrent < GPIO_PIN_8) ? &GPIOx->CRL : &GPIOx->CRH;
registeroffset = (iocurrent < GPIO_PIN_8) ? (position << 2u) : ((position – 8u) << 2u);
MODIFY_REG((*configregister), ((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << registeroffset), (config << registeroffset));
if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
__HAL_RCC_AFIO_CLK_ENABLE();
temp = AFIO->EXTICR[position >> 2u];
CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));
SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));
AFIO->EXTICR[position >> 2u] = temp;
if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{
SET_BIT(EXTI->RTSR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->RTSR, iocurrent);
}
if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{
SET_BIT(EXTI->FTSR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->FTSR, iocurrent);
}
if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{
SET_BIT(EXTI->EMR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->EMR, iocurrent);
}
if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{
SET_BIT(EXTI->IMR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->IMR, iocurrent);
}
}
}
position++;
}
}
这段代码是 STM32 HAL 库中 HAL_GPIO_Init() 函数的完整实现,用于初始化一个或多个 GPIO 引脚。






可见嵌入式其实最应该提升下c语言功底
config介绍
config 4 位 = CNF 高 2 位 + MODE 低 2 位



总得来说HAL_GPIO_Init() 解决了
选择哪个寄存器,配置引脚,写入寄存器的哪里的问腿
![[开源]基于STM32单片机WiFi智能停车场系统 Onene车位管理设计 云平台停车场车位检测 APP智慧停车场HK-010-171主机测评](https://www.171host.com/wp-content/uploads/2026/09/20260921150408-6ab1476821e49-220x150.jpg)




