Skip to main content

GPIO

1. GPIO简介

GPIO(General Purpose Input/Output)通用输入输出口

可配置为8种输入输出模式。引脚电平0-3.3V,部分引脚可容忍5V,输出模式下可控制端口输出高低电平,用来驱动LED、控制蜂鸣器、模拟通信协议输出时序等。

输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据。

如果需要接入功率比较大的设备,需要接入驱动电路。

2. GPIO基本结构

微信截图_20241025155054

APB2是外设总线。在STM32中,所有的GPIO都挂载在APB2外设总线上。

每个GPIO外设有16个引脚,顺序是第0-15号引脚。每个GPIO模块内,主要包含了寄存器和驱动器,寄存器是一段特殊的存储器,内核可以通过APB2总线对寄存器进行读写。

输入寄存器读取为1,证明目前端口是高电平,为0则是低电平。

STM32是32位的单片机,所以STM32内部的寄存器都是32位的。驱动器增加信号的驱动能力,寄存器只负责存储数据。

如果需要点灯,还是需要驱动器增大信号的驱动能力。

3. GPIO位结构

微信截图_20241025160331

由图可见,左边三个寄存器,右边则是驱动器,最右边则是引脚。上半部分是输入部分,下半部分是输出部分。

4. 输入

输入部分由IO引脚和两个保护二极管组成,上面的二极管接VDD(3.3V),下面的二极管接VSS(0V),输入电压如果比3.3V高,那么上方二极管将导通,输入电压产生的电流将不会流入主电路;如果输入电压低于VSS(负电压),那么下方二极管将导通。

来到左边,上拉电阻至VDD,下拉电阻至VSS,开关通过程序进行配置。上面导通,下面断开,就是上拉输入模式;下面导通,上面断开,就是下拉输入模式。两个都断开,就是浮空。输入引脚如果什么都不接,输入就是浮空,它的位置不确定,极易受到外界影响,所以要避免引脚悬空,就要加上上拉或者下拉电阻。

tip

上拉输入可以称作默认为高电平的输入模式,下拉则相反,是低电平的输入模式。

由于翻译问题,TTL肖特基触发器应为施密特触发器。它负责为输入电压进行整形。如果输入电压大于某一个阈值,就会升为高电平。如果小于某值就会降为低电平(参考数电)。

最左边的模拟输入线,连接到ADC(需要接收模拟量)。另一个是复用功能输入(接收数字量),连接到其他需要读取端口的外设上,比如串口的输入引脚等。

5. 输出

数字部分可以由输出数据寄存器或片上外设控制,通过数据选择器接到了输出控制部分。

选择输出数据寄存器进行控制,就是普通IO口输出,写该寄存器的某一位即可操作对应端口;位设置/清除寄存器可以用来单独操作输出数据寄存器的某一位,不影响其他位,如果想单独控制其中某个端口,需要几种方式:

  1. 读出寄存器,按位与(&=)和按位或(|=)的方式更改某一位,再将更改后的数据写回。(效率不高)
  2. 设置位设置/清除寄存器,对某一位进行置1,在位设置寄存器的对应位写1,不需操作的写0。清除则在位清除寄存器对应位写1。(主要使用)
  3. 读写STM32的位带区域(映射了RAM和外设寄存器的所有的位)。读写这段地址中的数据,相当于读写所映射位置的某一位。

右边的MOS管控制开关的导通和关闭,开关负责将IO口接到VDD或者VSS,可以选择推挽、开漏或关闭三种输出方式。

在推挽输出模式下,P-MOS和N-MOS均有效。数据寄存器为1时,上管导通,下管断开,输出直接接到VDD,即输出高电平。这样高低电平均有较强的驱动能力,因此也称为强推输出模式。这种模式下,STM32对IO口的控制权极大。

在开漏输出模式下,P-MOS是无效的,只有N-MOS在工作。数据寄存器为1时,下管断开,输出相当于断开,即高阻模式。数据寄存器为0时,下管导通,输出直接接到VSS,即输出低电平。该模式下,仅有低电平有驱动能力,高电平则没有。乍一看没有什么用,但它可以作为通信协议的驱动方式(I2C),可以在多机输入的情况下减小干扰。此外,还可以用于输出5V的电平信号。

在关闭输出模式下,两个MOS管都无效,即输出关闭,端口的电平由外部信号来控制。

6. GPIO输入模式

模式性质特征
浮空输入数字输入可读取引脚电平,若引脚悬空,则电平不确定
上拉输入数字输入可读取引脚电平,内部连接上拉电阻,悬空时默认高电平
下拉输入数字输入可读取引脚电平,内部连接下拉电阻,悬空时默认低电平
模拟输入模拟输入GPIO无效,引脚直接接入内部ADC
开漏输出数字输出可输出引脚电平,高电平为高阻态,低电平接VSS
推挽输出数字输出可输出引脚电平,高电平为VDD,低电平接VSS
复用开漏输出数字输出由片上外设控制,高电平为高阻态,低电平接VSS
复用推挽输出数字输出由片上外设控制,高电平为VDD,低电平接VSS

前三个模式的电路结构基本一样(刚刚也讲过),都属于数字输入口,都可以读取端口的高低电平。使用浮空输入时,端口一定要接一个连续的驱动源。

模拟输入:基本上是ADC模数转换器的专属,使用ADC的时候,将引脚配置为模拟输入。其他时候基本用不到。

开漏和推挽:结构也基本一样。区别刚刚讲过。

7. 封装技术

以STM32H723为例:

LQFP封装:

https://github.com/user-attachments/assets/91f3e340-acb7-412b-8d41-7c3a19d3b2e0

QFN封装:

https://github.com/user-attachments/assets/3a98584b-f735-45e9-b772-06449305c888

BGA:球栅阵列封装技术

8. 相关函数(标准库)

8.1 GPIO初始化函数

看一下GPIO_TypeDef结构体:

typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;

看一下GPIO_InitTypeDef结构体:

typedef struct
{
// 引脚、传输速度、模式
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
// GPIO_Mode_AIN 模拟输入
// GPIO_Mode_IN_FLOATING 浮空输入
// GPIO_Mode_IPD 下拉输入
// GPIO_Mode_IPU 上拉输入
// GPIO_Mode_Out_OD 开漏输出
// GPIO_Mode_Out_PP 推挽输出
// GPIO_Mode_AF_OD 开漏复用输出
// GPIO_Mode_AF_PP 复用推挽输出
}GPIO_InitTypeDef

这些 GPIO 工作模式 是 STM32 微控制器中 GPIO(通用输入/输出)的配置选项,不同的模式适用于不同的应用场景。以下是每种模式的详细说明及典型应用场景:


1. 模拟输入(GPIO_Mode_AIN)

  • 功能:引脚配置为模拟输入,用于读取模拟信号(如 ADC 采集)。
  • 典型应用
    • ADC(模数转换)输入,如读取传感器(温度、光照、电压等)。
    • DAC(数模转换)输出(但 DAC 通常有专用引脚)。
  • 特点
    • 数字输入/输出功能被禁用,仅用于模拟信号。
    • 无上拉/下拉电阻。

2. 浮空输入(GPIO_Mode_IN_FLOATING)

  • 功能:引脚仅作为数字输入,无内部上拉或下拉电阻。
  • 典型应用
    • 外部信号输入,但外部电路已经提供确定电平(如按键+外部上拉/下拉)。
    • 高速通信接口(如 UART RX、I2C SDA/SCL 等)。
  • 特点
    • 如果外部信号未连接,电平可能不确定(易受干扰)。
    • 适用于信号源已有明确驱动能力的场景。

3. 下拉输入(GPIO_Mode_IPD)

  • 功能:引脚作为数字输入,内部启用下拉电阻(默认拉低)。
  • 典型应用
    • 检测高电平有效的信号(如按键按下时接 VCC)。
    • 防止引脚悬空时误触发。
  • 特点
    • 无外部信号时,引脚电平为低。

4. 上拉输入(GPIO_Mode_IPU)

  • 功能:引脚作为数字输入,内部启用上拉电阻(默认拉高)。
  • 典型应用
    • 检测低电平有效的信号(如按键按下时接地)。
    • 防止引脚悬空时误触发(如按键输入)。
  • 特点
    • 无外部信号时,引脚电平为高。

5. 开漏输出(GPIO_Mode_Out_OD)

  • 功能:输出模式,只能拉低或高阻态(不能直接输出高电平)。
  • 典型应用
    • I2C 通信(SDA/SCL 需要开漏模式支持多设备总线)。
    • 电平转换(如 3.3V MCU 控制 5V 设备)。
    • 需要外部上拉电阻的场景。
  • 特点
    • 输出 0 时拉低,输出 1 时高阻(靠外部上拉电阻拉高)。
    • 支持“线与”逻辑(多个设备共享同一总线)。

6. 推挽输出(GPIO_Mode_Out_PP)

  • 功能:输出模式,可主动输出高电平或低电平。
  • 典型应用
    • 驱动 LED、继电器、MOSFET 等。
    • 高速数字信号(如 SPI、USART TX)。
    • 需要强驱动能力的场景。
  • 特点
    • 输出 0 时拉低,输出 1 时拉高(无需外部上拉)。
    • 驱动能力强,但不能直接用于总线(如 I2C)。

7. 开漏复用输出(GPIO_Mode_AF_OD)

  • 功能:外设控制的开漏输出(如 I2C、TIM 等硬件控制)。
  • 典型应用
    • I2C 的 SDA/SCL 引脚(STM32 的硬件 I2C 必须用此模式)。
    • 需要开漏模式的外设功能。
  • 特点
    • 类似开漏输出,但由硬件外设自动控制。

8. 复用推挽输出(GPIO_Mode_AF_PP)

  • 功能:外设控制的推挽输出(如 SPI、USART 等硬件控制)。
  • 典型应用
    • SPI 的 SCK/MOSI 引脚。
    • USART 的 TX 引脚。
    • PWM 输出(TIM 外设)。
  • 特点
    • 类似推挽输出,但由硬件外设自动控制。

总结表格

模式典型应用特点
AIN(模拟输入)ADC 采集、DAC 输出仅用于模拟信号,数字功能禁用
IN_FLOATING(浮空)UART RX、外部已驱动的数字信号无上拉/下拉,依赖外部电路
IPD(下拉输入)高电平有效的按键检测默认拉低,防干扰
IPU(上拉输入)低电平有效的按键检测默认拉高,防干扰
Out_OD(开漏输出)I2C、电平转换需外部上拉,支持线与逻辑
Out_PP(推挽输出)LED、SPI、USART TX强驱动能力,直接输出高低电平
AF_OD(复用开漏)硬件 I2C外设控制的开漏模式
AF_PP(复用推挽)SPI、USART、PWM外设控制的推挽模式

如何选择模式?

  1. 输入信号

    • 模拟信号 → AIN
    • 数字信号(外部已驱动)→ IN_FLOATING
    • 数字信号(需防干扰)→ IPUIPD
  2. 输出信号

    • 普通 IO 控制 → Out_PP(推挽)或 Out_OD(开漏 + 上拉)
    • 通信接口(I2C、SPI、UART)→ 使用对应的 复用模式AF_ODAF_PP
  3. 外设功能

    • 硬件外设(如 TIM、USART、I2C)必须使用 复用模式AF_*),不能直接用普通输入/输出模式。

常见外设的 GPIO 模式示例

外设推荐模式说明
ADCAIN模拟输入
I2CAF_OD(或手动模拟开漏)必须开漏 + 外部上拉
SPIAF_PP推挽输出,高速驱动
UARTRX: IN_FLOATING, TX: AF_PPRX 浮空输入,TX 推挽输出
PWMAF_PP定时器控制的推挽输出
按键IPU 或 IPD根据按键电路选择上拉/下拉

初始化示例:

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

8.2 GPIO读取输入函数

主要是ReadInputDataBit来完成。

uint8_t ReadInValue;
ReadInValue = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);

如果要读取所有A口的引脚的输入,那就不指定引脚:

uint16_t ReadInValue;
ReadInValue = GPIO_ReadInputData(GPIOA);

8.3 GPIO读取输出函数

uint8_t ReadOutValue;
ReadOutValue = GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0);

8.4 GPIO写入函数

GPIO_SetBits(GPIOA, GPIO_Pin_0); // 设置指定的数据端口位为1,但需要注意端口模式!
GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 清除指定的数据端口位,置0
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); // 写数据到指定的数据端口位,Bit_SET表示写1,Bit_RESET表示写0
GPIO_Write(GPIOA, 0x00FF); // 写数据到指定的数据端口,0x00FF表示写11111111

8.5 添加一个按键来控制LED的亮灭(例程)

• 按键按下,LED点亮; • 按键释放,LED熄灭。

这里的LED是PC13.

#include "vartypes.h"
#include "includes.h"

#define KEY_ON 1
#define KEY_OFF 0

void LedInit(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;// 推挽输出
}
void KeyInit(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉Pull-Down,当然这里的按键接的是3V3,所以下拉,但正常来说都是接地的,所以正常来说应该是上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

int KeyScan(void){
uint32_t ReadValue;
ReadValue = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1);
return ReadValue;
}

void LED1(uint32_t Switch){
if(Switch == KEY_ON){
GPIO_SetBits(GPIOC, GPIO_Pin_13);
}else if(Switch == KEY_OFF){
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
}
}
#include "includes.h"

int main(){
LedInit();
KeyInit();

LED1(0);

while(1){
if(KeyScan() == KEY_ON){
LED1(1);
}else{
LED1(0);
}
}
}

Reference

[1]. 江协科技.STM32入门教程-2023版 细致讲解 中文字幕[EB/OL](2021-07-29)[2024-10-25]. https://www.bilibili.com/video/BV1th411z7sn/?p=5&share_source=copy_web&vd_source=8b2bc57e71349607b55c9fde6b078ebd