通用IO(GPIO)
嵌入式老杨 2026-01-14


GPIO 是 STM32 与外部交互的核心接口。本文以 STM32F407 为例,详解通用 IO 的模式分类、工作原理、寄存器配置及库函数用法,附 LED 控制实例,快速掌握 GPIO 配置与应用。


01


简介


STM32F4xx 系列(含 STM32F407)最多提供 9 组通用 I/O 端口(GPIOA~GPIOH),总计最多 140 个可用 GPIO 引脚。每个引脚可独立配置为以下 4 种基本模式之一,并支持多种子式:


模式大类

子模式

典型应用

输入

浮空、上拉、下拉、模拟

按键检测、ADC 输入

输出

推挽、开漏(带上下拉)

LED、蜂鸣器、电平转换

复用

复用推挽/开漏

USART、SPI、I²C、PWM

模拟

无数字功能

ADC/DAC 专用


关键硬件特性:

5V 电压容忍:所有 GPIO 可直接承受 5V 输入;
快速翻转:最快 2 个时钟周期完成电平翻转(168 MHz 下约 11.9 ns);
保护电路:内置钳位二极管、上/下拉电阻(30~50 kΩ);
复用灵活性:每个引脚最多支持 16 种复用功能(AF0~AF15)。


02


主要模式和功能


图为stm32f4xx内部GPIO基本结构,主要包括输入驱动器、输出驱动器、输入/输出数据寄存器、复位/置位寄存器、内部上/下拉、内部保护二极管、I/O引脚等。程序中使用模式寄存器(GPIOx_MODER)、输出类型寄存器(GPIOx_OTYPER)、上拉/下拉寄存器(GPIOx_PUPDR)复用功能寄存器(GPIOx_AFRL/GPIOx_AFRH)进行配置所有模式。


输入浮空

作为输入浮空时,内部上/下拉断开,若外部也未接上/下拉,则此引脚为高阻态,容易受到外界噪声和感应电压影响。输入浮空模式常用于电平检测(如按键输入电路),为了检测到准确的电平,需要外部接上/下拉。


输入上拉

I/O引脚内部相当于连接一个30KΩ~50KΩ的上拉电阻至VDD。若外部未接上/下拉,则I/O引脚会被拉到高电平;若外部接下拉电阻到地,则引脚被强制下拉到低电平(由于内部有上拉电阻,此时产生微弱电流从VDD经内部上拉、外部下拉至Vss,不会影响外部电平)。此模式常用于电平检测,相比于输入浮空模式,输入上拉模式适用于高电平有效的情况(默认输出低电平,使电路保持无效状态),且可省去外接上拉电阻,简化电路设计。


输入下拉

与输入上拉模式相反,默认输出高电平VDD,适用于低电平有效的情况。


模拟功能

模拟功能常用于模拟信号处理,包括模拟输入(如ADC)和模拟输出(如DAC),此模式下内部上下拉无效。作为模拟输入时,I/O引脚输入的模拟信号不经过施密特触发器直接连接到外设;作为模拟输出时,模拟电压直接输出到I/O引脚。


具有上拉或下拉功能的开漏输出

开漏输出功能:仅N-MOS管参与输出控制。当输出寄存器写入0时,N-MOS导通,I/O引脚被拉到Vss(低电平);当输出寄存器写入1 时, N-MOS截止, I/O引脚进入高阻态,此时电平由外部电路决定(内部上拉/下拉电阻的阻值(约 30–50 kΩ)无法提供足够的驱动电流来建立明确的高电平)。

上/下拉功能:当N-MOS截止时,内部上拉电阻将引脚拉到VDD(高电平),内部下拉电阻将引脚拉到Vss(低电平)。上拉:默认输出高电平(需外部电路拉低才能输出低电平)。下拉:默认输出低电平(需外部电路拉高才能输出高电平)。

此模式常用于I2C总线:开漏输出+上拉电阻实现“线与”功能,多设备共享总线时,任一设备拉低即可使总线为低。


具有上拉或下拉功能的推挽输出

推挽输出功能:由一对互补的P-MOS和N-MOS管组成。当输出寄存器写入1时,P-MOS导通、N-MOS关断 ,引脚直接连接VDD(高电平)。当输出寄存器写入0时 ,P-MOS关断、N-MOS导通,引脚直接连接VSS(低电平)。

上/下拉功能:在推挽输出模式下,内部上拉/下拉电阻仅影响引脚未配置为输出时的默认状态。若配置为上拉,引脚在空闲时会被拉高(防止悬空)。若配置为下拉,引脚在空闲时会被拉低。

推挽输出时,上下拉电阻不参与输出驱动,仅作为备用保护机制。

典型应用场景为LED驱动和按键检测。


具有上拉或下拉功能的复用功能推挽输出

复用功能:复用功能寄存器(GPIOx_AFRL/GPIOx_AFRH)这2个寄存器可将每个I/O引脚配置为某个复用功能,每个I/O引脚有16个复用功能可选,由于I/O引脚的复用功能存在共用情况(如PA9和PB6都可配置为USART1_TX,PA10和PB7都可配置为USART1_RX…….),因此为了避免I/O引脚与复用功能发生冲突,一个复用功能只能连接到一个I/O引脚。


例如,将USART1_TX连接到PA9引脚,配置方法如下:

// 配置GPIOGPIO_InitStruct.Pin = GPIO_PIN_9; // PA9GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉(或GPIO_PULLDOWN)GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 速度50MHzGPIO_InitStruct.Alternate = GPIO_AF7_USART1; // 复用为USART1HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

推挽输出功能:同具有上拉或下拉功能的推挽输出模式。

上/下拉功能:同具有上拉或下拉功能的推挽输出模式。


具有上拉或下拉功能的复用功能开漏输出

复用功能:同具有上拉或下拉功能的复用功能推挽输出模式。

开漏输出功能:同具有上拉或下拉功能的开漏输出模式。

上/下拉功能:同具有上拉或下拉功能的开漏输出模式。


GPIO时钟

STM32F4xx 系列的所有通用 GPIO 端口(GPIOA ~ GPIOI)全部挂载在 AHB1 总线上,它们的时钟源完全相同,均由 RCC_AHB1ENR 寄存器统一控制。理论最大频率为168MHz(与HCLK相等),实际最高可配置为100MHz,但受限于信号完整性,建议不超过50MHz。可使用GPIO  端口输出速度寄存器 (GPIOx_OSPEEDR) 进行配置。


复用功能

可使用GPIO  复用功能低位寄存器 (GPIOx_AFRL)和GPIO  复用功能高位寄存器 (GPIOx_AFRH) 进行配置。


03


寄存器和库函数


1.寄存器介绍

STM32F4xx系列单片机GPIO共有10个寄存器,每个寄存器占用32位地址空间,可通过字节(8 位)、半字(16 位)或字(32 位)对 GPIO 寄存器进行访问。


序号

寄存器名称

有效位宽

功能

基地址

偏移地址

1

GPIOx_MODER(端口模式寄存器)

32 bit

设置引脚为输入(00)、输出(01)、复用功能(10)或模拟(11)。

GPIOx基地址

0x00

2

GPIOx_OTYPER(输出类型寄存器)

低 16 bit 有效

0=推挽,1=开漏。

GPIOx基地址

0x04

3

GPIOx_OSPEEDR(输出速度寄存器)

32 bit

00=2 MHz,01=25 MHz,10=50 MHz,11=100 MHz。

GPIOx基地址

0x08

4

GPIOx_PUPDR(上拉/下拉寄存器)

32 bit

00=浮空,01=上拉,10=下拉,11=保留。

GPIOx基地址

0x0C

5

GPIOx_IDR(输入数据寄存器)

低 16 bit

读取引脚当前电平状态

GPIOx基地址

0x10

6

GPIOx_ODR(输出数据寄存器)

低 16 bit

直接控制输出电平。

GPIOx基地址

0x14

7

GPIOx_BSRR(置位/复位寄存器)

32 bit

写 1 有效,写 0 无影响。

GPIOx基地址

0x18

8

GPIOx_AFRL  (复用功能低位寄存器)

32 bit

选择 16 种复用功能

GPIOx基地址

0x20

9

GPIOx_AFRH(复用功能高位寄存器)

32 bit

选择 16 种复用功能

0x24

10

GPIOx_LCKR(配置锁定寄存器)

17 bit

锁定引脚的 MODER/OTYPER/OSPEEDR/PUPDR 配置,防止误改写。

GPIOx基地址

0x1C

例如:GPIOA_BSRR 的地址 = GPIOA基地址(0x4002 0000) + 0x18 = 0x4002 0018。


2.GPIO常用库函数


序号

函数名称

功能

1

HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)

根据结构体参数配置引脚模式、输出类型、速度、上下拉功能,常用于普通GPIO功能初始化。

2

HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)

将指定引脚恢复为复位默认值。

3

HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)

设置引脚输出高/低电平。

4

HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

翻转引脚电平。

5

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

读取引脚当前输入电平,返回 GPIO_PIN_SET 或 GPIO_PIN_RESET。

6

HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)

配置引脚为复用推挽/开漏输出,并指定复用功能编号,常用于复用功能初始化。

7

HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

锁定引脚配置寄存器(MODER/OTYPER/OSPEEDR/PUPDR),防止误改写。

8

__HAL_RCC_GPIOx_CLK_ENABLE()

使能 GPIO 端口时钟(宏,非函数,但必用)。

04


硬件设计说明


STM32 与 PC 通过 USB 转 TTL 模块连接,TX 接 RX,RX 接 TX,GND 共地

05


程序说明


1.初始化流程
依次完成系统初始化、时钟配置、LED 控制引脚初始化和串口配置,为后续功能提供基础硬件环境。

2.交互逻辑
通过循环结构持续获取串口输入字符,回显确认后根据字符内容执行对应 LED 控制指令,形成完整的人机交互闭环。

3.状态控制
采用 switch-case 结构实现 8 种指令响应(7 种颜色 + 关闭)。

main.c

int main(void){ char ch;   HAL_Init();  /* 配置系统时钟为168 MHz */  SystemClock_Config(); /* 初始化RGB彩灯 */  LED_GPIO_Config();  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/ DEBUG_USART_Config();  /* 打印指令输入提示信息 */ Show_Message();  while(1) {  /* 获取字符指令 */ ch=getchar(); printf("接收到字符:%c\n",ch);  /* 根据字符指令控制RGB彩灯颜色 */ switch(ch) { case '1': LED_RED; break; case '2': LED_GREEN; break; case '3': LED_BLUE; break; case '4': LED_YELLOW; break; case '5': LED_PURPLE; break; case '6': LED_CYAN; break; case '7': LED_WHITE; break; case '8': LED_RGBOFF; break; default: /* 如果不是指定指令字符,打印提示信息 */ Show_Message(); break;  }  } }


bsp_led.c

#include "./led/bsp_led.h"   /** * @brief 初始化控制LED的IO * @param * @retval */void LED_GPIO_Config(void){   /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef  GPIO_InitStruct;  /*开启LED相关的GPIO外设时钟*/ LED1_GPIO_CLK_ENABLE(); LED2_GPIO_CLK_ENABLE(); LED3_GPIO_CLK_ENABLE();  /*选择要控制的GPIO引脚*/  GPIO_InitStruct.Pin = LED1_PIN;   /*设置引脚的输出类型为推挽输出*/ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;   /*设置引脚为上拉模式*/ GPIO_InitStruct.Pull = GPIO_PULLUP;  /*设置引脚速率为高速 */  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;   /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/ HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);   /*选择要控制的GPIO引脚*/  GPIO_InitStruct.Pin = LED2_PIN;  HAL_GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStruct);   /*选择要控制的GPIO引脚*/  GPIO_InitStruct.Pin = LED3_PIN;  HAL_GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStruct);   /*关闭RGB灯*/ LED_RGBOFF; }


bsp_debug_usart.c

void DEBUG_USART_Config(void){   UartHandle.Instance          = DEBUG_USART;  UartHandle.Init.BaudRate     = DEBUG_USART_BAUDRATE; UartHandle.Init.WordLength   = UART_WORDLENGTH_8B; UartHandle.Init.StopBits     = UART_STOPBITS_1; UartHandle.Init.Parity       = UART_PARITY_NONE; UartHandle.Init.HwFlowCtl    = UART_HWCONTROL_NONE; UartHandle.Init.Mode         = UART_MODE_TX_RX;  HAL_UART_Init(&UartHandle);  /*使能串口接收中断 */ __HAL_UART_ENABLE_IT(&UartHandle,UART_IT_RXNE); }  /** * @brief UART MSP 初始化  * @param huart: UART handle * @retval 无 */void HAL_UART_MspInit(UART_HandleTypeDef *huart){  GPIO_InitTypeDef  GPIO_InitStruct;  DEBUG_USART_CLK_ENABLE();  DEBUG_USART_RX_GPIO_CLK_ENABLE(); DEBUG_USART_TX_GPIO_CLK_ENABLE();  /**USART1 GPIO Configuration  PA9     ------> USART1_TX PA10    ------> USART1_RX  */ /* 配置Tx引脚为复用功能  */ GPIO_InitStruct.Pin = DEBUG_USART_TX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = DEBUG_USART_TX_AF; HAL_GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStruct);  /* 配置Rx引脚为复用功能 */ GPIO_InitStruct.Pin = DEBUG_USART_RX_PIN; GPIO_InitStruct.Alternate = DEBUG_USART_RX_AF; HAL_GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStruct);   HAL_NVIC_SetPriority(DEBUG_USART_IRQ ,0,1); //抢占优先级0,子优先级1 HAL_NVIC_EnableIRQ(DEBUG_USART_IRQ ); //使能USART1中断通道 }  /*****************  发送字符串 **********************/void Usart_SendString(uint8_t *str){ unsigned int k=0; do  { HAL_UART_Transmit(&UartHandle,(uint8_t *)(str + k) ,1,1000); k++; } while(*(str + k)!='\0'); }


06


测试结果


电脑端使用串口调试助手,选择电脑与STM32相连的COM口,设置为115200-N-8-1。下载程序后,电脑端发送字符到stm32,stm32会回显该字符到电脑端,同时STM32解析命令点亮RGB彩色灯。




07


代码链接


工程代码链接:

https://gitee.com/ylm1101111/stm32_basic3.git


声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。 微信联系小助理
0
评论
  • 相关技术文库
  • 单片机
  • 嵌入式
  • MCU
  • STM
下载排行榜
更多
评测报告
更多
广告