GPIO的不同输入模式是在程序中通过GPIOx_CRL和GPIOx_CRH两个寄存器进行配置的。配置寄存器的值影响的是片内电路的通断(可以理解为每个位控制1个开关),不同GPIO模式对应的是不同的片内连通状态。根据GPIO的模式,片内配置可分为四类:

1. 输入配置(Input Configuration)

输入配置包括输入浮空、输入上拉和输入下拉3种寄存器配置。片内配置原理示意图如下图所示。I/O引脚输入端上、下各有一个保护二极管,其作用是防止外部过高的电压输入对内部电路造成损坏。如果输入正电压显著高于VDD,则上方二极管导通;如果输入负电压显著低于VSS,则下方二极管导通。这样可以将输入芯片内部的电压钳制在VDD和VSS附近(约±0.7V)。

输入浮空/上拉/下拉模式芯片内部配置

说明:

  • ODR与引脚间断开。此时ODR可被CPU读写,可辅助配置寄存器,实现输入上/下拉模式配置。
  • 片内弱上/下拉功能开启。上拉时上方的开关闭合,下拉时下方的开关闭合,浮空输入时两个开关均开启。
  • Schimtt Trigger开启,在每个APB2时钟周期,信号经此TTL触发器取样,输入IDR。
  • 读取IDR可得到I/O电平状态。
  • 对可接受5V的I/O引脚,可用VDD_FT替代VDD。


2. 输出配置(Output Configuration)

通用输出推挽和开漏两种输出模式片内配置原理示意图如下图所示。

通用输出推挽/开漏模式片内配置

说明:

  • ODR与引脚连通。
  • 片内弱上/下拉功能关闭。
  • 开漏模式:输出控制器将P-MOS栅极置1,P-MOS始终不工作。ODR为1时,N-MOS导通,输出低电平;ODR为0时,N-MOS也截止,引脚处于既不是高电平也不是低电平的高阻态。可见,开漏模式只能输出低电平。
  • 推挽模式:ODR为0时P-MOS导通、N-MOS截止,输出高电平;ODR为1时,N-MOSE导通,P-MOS截止,输出低电平。推挽模式可以输出高/低电平。
  • Schmitt触发器开启,在每个APB2时钟周期,引脚电平都被取样存入IDR。
  • 读取IDR寄存器可以获得引脚当前电平状态。


3. 复用功能配置(AFIO Configuration)

STM32内部集成了众多的外设控制器,如USART、ADC等,如果原来的GPIO引脚(通过对ODR或IDR的操作输出或输入电平信号)要充当外设控制器的引脚,此时需要将引脚配置为AFIO(Alternate
Function
Input/Output)模式,即通过配置相关寄存器,将引脚与外设控制器连通。具体到某个GPIO引脚可以复用哪些功能(可接哪些外设),需要查阅芯片的《Data
Sheet》中对引脚的定义,一般在数据手册的Pinouts and pin
descriptions章节有关于引脚定义的表格。AFIO复用功能输入输出模式片内配置原理示意图如下图所示。

AFIO复用功能输入输出模式片内配置

说明:

  • ODR开启,但不是直接与引脚相连,只能被芯片内部的外设控制器访问。
  • 片内弱上/下拉功能关闭。
  • Schmitt触发器开启,在每个APB2时钟周期,引脚电平都被取样存入IDR。
  • 读取IDR寄存器可以获得引脚当前电平状态。
  • 复用输出支持推挽/开漏。
  • 主要特征:输入/输出均汇于片内外设。对大多数外设,I/O须配置为复用模式。


4. 模拟配置(Analog Configuration)

模拟配置用于ADC的输入和DAC的输出。

模拟模式片内配置

说明

  • ODR与引脚断开。
  • 片内弱上/下拉关闭。
  • Schmitt触发器关闭。省电!
  • 这种模式下读取IDR始终返回0。

Analog模式是最省电的模式。特别是对电池供电的应用场合,建议将所有GPIO引脚初始化为Analog,然后再按需设置用到的I/O引脚的工作模式。可以在程序调用GPIO_Init()之类的函数初始化I/O之前,调用如下函数:

void GPIO_SetAllIO2Analog(void){
	GPIOA->CRL = 0x00; // Set all GPIO to Analog,
	GPIOA->CRH = 0x00; // in order to save energy.
	GPIOB->CRL = 0x00;
	GPIOB->CRH = 0x00;
	GPIOC->CRL = 0x00;
	GPIOC->CRH = 0x00;
	GPIOD->CRL = 0x00;
	GPIOD->CRH = 0x00;
	GPIOE->CRL = 0x00;
	GPIOE->CRH = 0x00;
	GPIOF->CRL = 0x00;
	GPIOF->CRH = 0x00;
	GPIOG->CRL = 0x00;
	GPIOG->CRH = 0x00;
}

注意:一定要在调用GPIO_SetAllIO2Analog()之后,再调用GPIO_Init(),执行使能时钟、初始化所需I/O端口等操作。



总结:

  • I/O端口对外虽然只是一个引脚,但每个引脚在芯片内部可能有多种连通路径。
  • 具体连通哪条路径,是通过配置寄存器(开关)开实现的。
  • I/O端口的复用和重映射都是基于这一原理。可以根据需求,通过配置寄存器,将内部外设切换到某个可选的引脚。
  • 具体到某个外设,需要设置为哪种GPIO模式,可查阅芯片的《Reference Manual》中关于GPIO和AFIO的章节。
  • 具体的某个引脚,可能的复用和重映射选项,可查阅芯片的《Data Sheet》中关于Pin definitions相关的表格。