STM32 GPIO
版权声明:署名-非商业性使用-相同方式共享
@@ Tags: STM32 GPIO
@@ Date: 2026-01-28 1238
@@ Note: ~
概念
在STM32中,GPIO 中有两个重要的概念:
端口
- 定义:STM32 将 GPIO 分成了很多个组, 每一组称为端口。端口可以看做是一个独立的GPIO外设模块。
- 命名:端口用大写字母表示,如
GPIOA、GPIOB、GPIOC、GPIOD、GPIOH(具体数量取决于芯片型号)。
引脚
- 定义:引脚是芯片物理上伸出的金属“针脚”,是与外部电路进行电气连接的实际接口。它是端口的具体成员。
- 命名:由“端口字母 + 引脚编号”组成。例如:
- PA1:表示 GPIOA端口 的 第1号引脚。
- PC13:表示 GPIOC端口 的 第13号引脚。
电路结构

引脚模式
输入模式
1.浮空输入
-
Floating Input / Input floating
-
纯粹的数字输入。引脚电平完全由外部电路决定。
-
内部既不上拉也不下拉。如果外部悬空,引脚电平将是不确定的,极易受电磁干扰影响而翻转。
-
施密特触发器开启。
-
典型应用: 连接外部已有确定驱动能力的信号,如另一个MCU的推挽输出、通信总线中主设备驱动的信号线(如UART_RX,当外部有上拉时)。
2.上拉输入
-
Input pull-up
-
数字输入,内部通过一个约40kΩ的电阻连接到VDD。
-
当外部无驱动时,引脚被默认拉至高电平。
-
需要读取低电平时,外部电路需提供足够的“灌电流”将电平拉低。
-
典型应用: 按键、开关,一端接地,按下时引脚被拉低。空闲时因上拉而保持高电平。
3.下拉输入
- Input pull-down
- 数字输入,内部通过一个约40kΩ的电阻连接到VSS。
- 当外部无驱动时,引脚被默认拉至低电平。
- 需要读取高电平时,外部电路需提供足够的“拉电流”将电平拉高。
- 典型应用: 按键、开关,一端接VCC,按下时引脚被拉高。空闲时因下拉而保持低电平。
4.模拟输入
- Analog Mode
- 引脚作为ADC(模数转换器) 或DAC(数模转换器) 的通道。
- 数字功能被完全禁用。施密特触发器关闭,上下拉电阻断开。引脚上的电压被直接送至模拟外设。
- 功耗最低的输入模式,因为数字输入电路不工作。
- 典型应用: 连接温度传感器、电位器、麦克风等模拟信号源。
输出模式
1.通用推挽输出
- General-purpose output push-pull
- 最常用的输出模式。MCU可以主动驱动引脚为高电平(通过P-MOS管连接VDD)或低电平(通过N-MOS管连接VSS)。
- 输出能力强(STM32通常单引脚最大±20mA,具体看数据手册),高低电平由MCU的VDD和VSS决定。
- 两个MOS管像“推”和“挽”一样交替工作,因此得名。
- 典型应用: 驱动LED、继电器、蜂鸣器、电平控制等绝大多数需要数字输出的场景。
2.通用开漏输出
- General-purpose output open-drain
- 只能主动拉低(N-MOS管工作),不能主动拉高(P-MOS管被禁用)。高电平状态需要依赖外部上拉电阻连接到正电源。
- 优点1:电平转换。外部上拉电阻可以接到一个不同于MCU VDD的电压上(如5V),实现与不同电压器件的通信。
- 优点2:“线与”功能。多个开漏输出的引脚可以直接连在一起,只要有一个拉低,总线即为低;所有都释放,总线才被上拉为高。这是I²C总线的基础。
- 缺点:驱动高电平时,电流由外部上拉电阻提供,因此上升沿速度较慢(RC充电)。
- 典型应用: I²C、SMBUS总线,驱动高于MCU电压的器件,需要“线与”逻辑的场景。
3.复用功能推挽输出
- Alternate function output push-pull
- 引脚的控制权交给片上外设(如SPI、USART、TIM等),而非CPU或GPIO寄存器。输出特性与通用推挽完全相同。
- 例如,配置UART_TX引脚为此模式,数据将由USART外设自动产生并输出。
- 典型应用: 所有需要由硬件外设驱动的输出功能:
SPI_SCK/MOSI、UART_TX、I2S_WS/CK、TIM_PWM输出等。
4.复用功能开漏输出
- Alternate function output open-drain
- 引脚的控制权交给片上外设,输出特性与通用开漏完全相同。
- 典型应用: 需要开漏特性的硬件外设输出,最经典的就是 I²C 的 SDA 和 SCL 线。I²C外设会自动管理开漏输出和输入检测。
输出速度配置
在配置输出模式(推挽/开漏,通用/复用)时,MODEx位还用于选择输出速度,这对于信号完整性和EMI至关重要。
- 2 MHz(低速): 用于低速信号,功耗和噪声低。
- 10 MHz(中速): 常用平衡选择。
- 50 MHz(高速): 用于高速信号(如
SPI、USB),但需注意过冲和振铃。 - (新一代STM32有更高速度选项,如Very High)
GPIO 相关寄存器
STM32 的 GPIO 分成了多组端口,端口所含引脚的工作模式通过多个寄存器(端口寄存器组)来进行配置,寄存器中的对应位控制该端口中对应的引脚。
比如 STM32F411 分成了5组端口:GPIOA、GPIOB、GPIOC、GPIOD 和 GPIOH。每组端口由10个32位的寄存器来控制。
注意:
- 寄存器常量中的
x代表具体的端口号, 如GPIOA、GPIOB等。 - 寄存器中低位对应低序号引脚, 如
GPIOA_MODER中0~1位对应PA0,30~31位对应PA15。
GPIOx_MODER(模式寄存器)
控制引脚的工作模式,每个引脚占2位:
00:输入模式(复位值)01:通用输出模式10:复用功能模式11:模拟模式(用于ADC/DAC)
GPIOx_OTYPER(输出类型寄存器)
控制输出类型(每个引脚占1位):
0:推挽输出(复位值)1:开漏输出
GPIOx_OSPEEDR(输出速度寄存器)
控制输出驱动速度(每个引脚占2位):
00:低速(复位值)01:中速10:高速11:超高速(具体频率见芯片手册)
GPIOx_PUPDR(上拉/下拉寄存器)
(Pull-up Pull-down Register) 控制内部上下拉(每个引脚占2位):
00:无上下拉(复位值)01:上拉10:下拉11:保留
GPIOx_IDR(输入数据寄存器)
读取引脚输入状态(每个引脚占1位, 高16位保留, 只读):
0:低电平1:高电平
GPIOx_ODR(输出数据寄存器)
控制引脚输出电平(每个引脚占1位, 高16位保留):
0:输出低电平1:输出高电平
GPIOx_BSRR(置位/复位寄存器)
(Bit Set Reset Register) 原子操作设置/清除输出位:
BSy(00-15位):设置对应引脚为高电平(写1有效,写0无影响)BRy(16-31位):设置对应引脚为低电平(写1有效,写0无影响)
注意:
GPIOx_ODR与GPIOx_BSRR的区别在于, 设置某引脚的输出电平, 前者需要读->改->写后者可以直接写。
GPIOx_LCKR(配置锁寄存器)
锁定引脚配置,防止意外修改。
GPIOx_AFRL和GPIOx_AFRH(复用功能寄存器)
(Alternate Function Register Low/High) 选择引脚的复用功能(每个引脚占4位),AFRL用于引脚0-7,AFRH用于引脚8-15。
通过寄存器的编程
通过查阅芯片的参考手册可知, GPIO 各端口寄存器的在内存地址空间中的具体地址, 因此我们可以直接通过指针访问这些寄存器。
#define GPIOA_MODER *(volatile unsigned int *)(0x40020000UL)
GPIOA_MODER = 0x00000003; // 向 GPIOA_MODER 寄存器中写入 0x03
unsigned int a = GPIOA_MODER; // 读取GPIOA_MODER寄存器的内容,并存入变量a
另外我们还可以通过预定义的 C 结构体指针访问寄存器, 这种方式要比直接使用地址友好得多。
// stm32f411xe.h
typedef struct
{
__IO uint32_t MODER;
__IO uint32_t OTYPER;
__IO uint32_t OSPEEDR;
__IO uint32_t PUPDR;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t LCKR;
__IO uint32_t AFRL;
__IO uint32_t AFRH;
} GPIO_TypeDef;
#define GPIOA ((GPIO_TypeDef *)0x40020000UL)
GPIOA->MODER &= ~(3<<(5*2)); // 清除模式寄存器的 bit11:bit10 为 00
// - 操作的是第5个引脚 (5)
// - 每个引脚占2个bit (*2)
// - 清除2个bit (3 即 0b11)
GPIOA->MODER |= 1<<(5*2); // 设置 bit11:bit10 = 01, 引脚PA5为推挽输出
GPIOA->BSRR = 1<<5; // 设置 bit5 为 1,PA5 输出高电平,开启LD2
GPIOA->BSRR = 1<(5+16); // 设置 bit21 为1,PA5 输出低电平,关闭LD2
通过 HAL 库的方式编程
// stm32f4xx_hal_gpio.h
typedef struct
{
uint32_t Pin; // 选择需要配置的引脚
uint32_t Mode; // 设置所选引脚的工作模式
uint32_t Pull; // 使能所选引脚的上拉/下拉电阻
uint32_t Speed; // 设置所选引脚的输出速度
uint32_t Alternate; // 设置引脚的复用功能
} GPIO_InitTypeDef;
typedef enum
{
GPIO_PIN_RESET = 0u, // 引脚低电平
GPIO_PIN_SET // 引脚高电平
} GPIO_PinState;
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
/* .............. */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
#define GPIO_PIN_MASK 0x0000FFFFu /* PIN mask for assert test */
// 配置引脚 PA5和 PA15:推挽输出,无上拉/下拉,输出速度为低速
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// PA15 引脚设置为低电平
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
Comments ()