STM32标准库GPIO配置与使用详解

498 阅读7分钟

一、GPIO基本概念

GPIO(General Purpose Input/Output)即通用输入输出端口,是STM32微控制器最基本的外设功能。每个GPIO引脚都可以独立配置为输入或输出模式,是连接微控制器与外部设备的重要接口。

在STM32中,GPIO端口通常以字母命名(如GPIOA、GPIOB等),每个端口包含多个引脚(通常0-15)。GPIO的功能不仅限于简单的数字输入输出,还可以配置为复用功能,如USART、SPI、I2C等外设的通信接口。

二、GPIO工作模式详解(标准库)

STM32标准库提供了8种GPIO工作模式,通过GPIO_InitTypeDef结构体中的GPIO_Mode成员进行配置:

输入模式

  1. 浮空输入(GPIO_Mode_IN_FLOATING)​

    • 引脚处于高阻抗状态,电平完全由外部电路决定
    • 适用于按键检测、开关量输入等场景
    • 注意:当引脚悬空时,电平状态不确定
  2. 上拉输入(GPIO_Mode_IPU)​

    • 内部上拉电阻使能,默认高电平
    • 当外部无信号时,引脚保持高电平
    • 适用于按键检测(按键接地时)
  3. 下拉输入(GPIO_Mode_IPD)​

    • 内部下拉电阻使能,默认低电平
    • 当外部无信号时,引脚保持低电平
    • 适用于某些需要默认低电平的传感器接口
  4. 模拟输入(GPIO_Mode_AIN)​

    • 引脚连接到ADC模块
    • 用于模拟信号采集
    • 注意:此模式下数字输入功能不可用

输出模式

  1. 开漏输出(GPIO_Mode_Out_OD)​

    • 只能输出低电平或高阻态
    • 需要外部上拉电阻才能输出高电平
    • 适用于I2C等需要线与功能的接口
  2. 推挽输出(GPIO_Mode_Out_PP)​

    • 可以输出强高电平和强低电平
    • 驱动能力强,最常用的输出模式
    • 适用于LED控制、继电器驱动等
  3. 复用开漏(GPIO_Mode_AF_OD)​

    • 用于外设功能的开漏输出
    • 如I2C的SCL/SDA引脚
  4. 复用推挽(GPIO_Mode_AF_PP)​

    • 用于外设功能的推挽输出
    • 如USART的TX引脚、SPI的SCK引脚等

三、GPIO输出配置与使用

1. 配置步骤详解

// 1. 定义GPIO初始化结构体
GPIO_InitTypeDef GPIO_InitStructure;

// 2. 使能GPIO时钟(必须步骤)
// STM32的外设都需要先使能时钟才能使用
// APB2总线上的GPIOA-GPIOG时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 例如使能GPIOA

// 3. 配置GPIO参数
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;      // 配置PA5引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度50MHz

// 4. 初始化GPIO
GPIO_Init(GPIOA, &GPIO_InitStructure);

2. 输出控制函数详解

// 设置引脚为高电平
GPIO_SetBits(GPIOA, GPIO_Pin_5);

// 设置引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_5);

// 直接写入整个端口(16位)
GPIO_Write(GPIOA, 0xFFFF); // 所有引脚置高
GPIO_Write(GPIOA, 0x0000); // 所有引脚置低

// 写入单个引脚(更安全的方式)
GPIO_WriteBit(GPIOA, GPIO_Pin_5, Bit_SET);   // 置高
GPIO_WriteBit(GPIOA, GPIO_Pin_5, Bit_RESET); // 置低

// 切换引脚电平状态(标准库没有直接函数,可自行封装)
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
    if(GPIO_ReadOutputDataBit(GPIOx, GPIO_Pin) == Bit_SET)
        GPIO_ResetBits(GPIOx, GPIO_Pin);
    else
        GPIO_SetBits(GPIOx, GPIO_Pin);
}

四、GPIO输入配置与使用

1. 配置步骤详解

GPIO_InitTypeDef GPIO_InitStructure;

// 使能GPIO时钟(以GPIOB为例)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

// 配置GPIO参数(PB12为例)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

// 初始化GPIO
GPIO_Init(GPIOB, &GPIO_InitStructure);

2. 输入状态读取详解

STM32标准库提供了多种读取GPIO状态的函数:

// 读取单个输入引脚电平(最常用)
uint8_t pinState = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
if(pinState == Bit_SET) {
    // 高电平处理逻辑
} else {
    // 低电平处理逻辑
}

// 读取整个端口的输入状态(16位)
uint16_t portState = GPIO_ReadInputData(GPIOB);

// 读取输出寄存器状态(了解当前配置的输出状态)
uint8_t outputState = GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12);
uint16_t portOutputState = GPIO_ReadOutputData(GPIOB);

3. 输入模式选择建议

  • 按键检测​:通常使用上拉输入模式,按键接地。当按键按下时,引脚被拉低;松开时,内部上拉使引脚保持高电平。

  • 传感器数字信号​:根据传感器输出特性选择:

    • 开漏输出的传感器:使用上拉输入
    • 推挽输出的传感器:可使用浮空输入
  • 高速信号​:如外部中断、编码器输入等,建议使用浮空输入,由外部电路确定上下拉。

五、GPIO速度配置详解

在输出模式下,GPIO速度配置影响信号的上升/下降时间和抗干扰能力:

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 最常用

三种可选速度:

  1. GPIO_Speed_10MHz

    • 输出速度较低
    • 功耗较小
    • 适用于低速信号,如LED控制、低频通信
  2. GPIO_Speed_2MHz

    • 输出速度最慢
    • 功耗最低
    • 适用于对速度要求极低的场合
  3. GPIO_Speed_50MHz

    • 最高输出速度(默认推荐)
    • 驱动能力强,信号边沿陡峭
    • 适用于高速通信(SPI、USART等)和快速切换的场合
    • 注意:高速模式可能增加EMI干扰

选择建议:

  • 普通I/O控制:10MHz或50MHz
  • 通信接口:50MHz
  • 电池供电设备:根据实际需要选择最低可用速度

六、GPIO使用注意事项

  1. 时钟使能
    使用任何GPIO前必须使能对应的时钟,否则配置无效。
  2. 复用功能
    当GPIO配置为复用功能时(如USART、SPI等),需要同时使能对应外设的时钟。
  3. 5V容忍
    只有部分STM32引脚是5V容忍的(标记为FT的引脚),其他引脚输入电压不能超过VDD+0.3V。
  4. 初始化顺序
    建议先配置GPIO,再初始化相关外设。
  5. 功耗考虑
    未使用的GPIO最好配置为模拟输入模式以降低功耗。
  6. 输入滤波
    对于抖动较大的输入信号,建议在硬件上增加RC滤波,或在软件中实现去抖动算法。

七、完整示例代码

LED闪烁示例(输出模式)

#include "stm32f10x.h"

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}

int main(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
															//使用各个外设前必须开启时钟,否则对外设的操作无效
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;					//定义结构体变量
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;				//GPIO引脚,赋值为第0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器
															//实现GPIOA的初始化
	
	/*主循环,循环体内的代码会一直循环执行*/
	while (1)
	{
		/*设置PA0引脚的高低电平,实现LED闪烁,下面展示3种方法*/
		
		/*方法1:GPIO_ResetBits设置低电平,GPIO_SetBits设置高电平*/
		GPIO_ResetBits(GPIOA, GPIO_Pin_0);					//将PA0引脚设置为低电平
		Delay_ms(500);										//延时500ms
		GPIO_SetBits(GPIOA, GPIO_Pin_0);					//将PA0引脚设置为高电平
		Delay_ms(500);										//延时500ms
		
		/*方法2:GPIO_WriteBit设置低/高电平,由Bit_RESET/Bit_SET指定*/
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);		//将PA0引脚设置为低电平
		Delay_ms(500);										//延时500ms
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);			//将PA0引脚设置为高电平
		Delay_ms(500);										//延时500ms
		
		/*方法3:GPIO_WriteBit设置低/高电平,由数据0/1指定,数据需要强转为BitAction类型*/
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);		//将PA0引脚设置为低电平
		Delay_ms(500);										//延时500ms
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);		//将PA0引脚设置为高电平
		Delay_ms(500);										//延时500ms
	}
}