Skip to content

2.2 GPIO 输出电压

通用输入输出端口 GPIO

参考资料

推荐至少先阅读 G0 系列 TRM,因为其有中文版本。事实上笔者在此文中也大量参考 G0 系列 TRM,因此本文内容可能与 F1 系列有所出入。

如果你发现你不认识或不理解 电平 上拉(电阻) MOSFET 等词汇,建议先自行搜索学习。

引脚工作模式

请见 UM1850 20.1.1 结构体 GPIO_InitTypeDef,其中引脚模式的定义可大致有以下几种分类方法:

  • 输入模式 / 输出模式 / 复用模式
    • 输入模式 由外部驱动的信号对 MCU 产生影响,如按键输入,传感器信号输入等。 我把 GPIO_MODE_IT_* GPIO_MODE_EVT_* 也归为输入模式,因为这些模式是为了处理外部中断而设计的。 GPIO_MODE_ANALOG 也归为输入模式,因为这是为了处理模拟信号而设计的。
    • 输出模式 MCU 输出信号给外部设备,如 LED 灯,继电器等
    • 复用模式 当使用片上外设时,需要将引脚设置为复用模式
  • 推挽输出 / 开漏输出 / 输入
  • 接口上拉 / 接口下拉 / 无上下拉

输入模式

此处先介绍狭义的输入模式,即 GPIO_MODE_INPUT

将 I/O 端口编程为输入时:

  • 输出缓冲器被禁止
  • 施密特触发器输入被打开
  • 根据 GPIOx_PUPDR 寄存器中的值决定是否打开上拉和下拉电阻
  • 输入数据寄存器每隔 1 个 AHB 时钟周期对 I/O 引脚上的数据进行一次采样
  • 对输入数据寄存器的读访问可获取 I/O 状态

解析:

  • 输出缓冲器被禁止,意味着此时引脚不能向外输出(废话 你可以这么理解,此时的引脚在整个电路中相当于一个耐压 3.3V(部分引脚为 5VpF 级别的电容,试图对这个引脚施加超过耐压值的电压就会炸,也不能指望这个 pF 级别的电容给你提供多少电流。
  • 施密特触发器输入被打开,意味着引脚的输入电平会经过施密特触发器,这样可以减少噪声对输入的影响。
  • 根据 GPIOx_PUPDR 寄存器中的值决定是否打开上拉和下拉电阻,这个在后面章节中会单独提到,这里不再赘述。
  • 对输入数据寄存器的读访问可获取 I/O 状态,意思是你可以读取引脚上的电平。

GPIO_MODE_ANALOG 模式时,施密特触发器输入停用以免其对小模拟信号产生干扰,可以理解为此时信号被直接连接至 ADC 以供转换,具体请见 ADC 章节。

GPIO_MODE_IT_* GPIO_MODE_EVT_* 也可以算是输入模式,但是这两种模式是为了处理外部中断而设计的,请查看中断相关章节,不在此处讨论。

输出模式

包含 GPIO_MODE_OUTPUT_PPGPIO_MODE_OUTPUT_OD 两种模式,分别对应推挽输出和开漏输出。

将 I/O 端口编程为输出时:

  • 输出缓冲器被打开:
    • 开漏模式:输出寄存器中的 “0” 可激活 N-MOS,而输出寄存器中的 “1” 会使端口保持高阻态 (Hi-Z)(P-MOS 始终不激活)
    • 推挽模式:输出寄存器中的 “0” 可激活 N-MOS,而输出寄存器中的 “1” 可激活 P-MOS
  • 施密特触发器输入被打开
  • 根据 GPIOx_PUPDR 寄存器中的值决定是否打开上拉和下拉电阻
  • 输入数据寄存器每隔 1 个 AHB 时钟周期对 I/O 引脚上的数据进行一次采样
  • 对输入数据寄存器的读访问可获取 I/O 状态
  • 对输出数据寄存器的读访问可获取最后的写入值

施密特触发器输入被打开,意思是你仍然可以从引脚读取其实际电平,对输入数据寄存器的读访问可获取 I/O 状态,对输出数据寄存器的读访问可获取最后的写入值,意思是读取引脚上当前的实际电平,和你上一次设置的值需要用到不同的 API,务必不要混淆。

推挽与开漏

请见上图 MSv33182V2 中输出驱动部分的框图。

我们发现输出管脚同时分别通过一个 N-MOS 管和一个 P-MOS 管直接连接至电源和地。当我们需要输出高电平时,P-MOS 导通,N-MOS 截止,输出电压为高电平;当我们需要输出低电平时,N-MOS 导通,P-MOS 截止,输出电压为低电平。

这种设计称为推挽输出(Push-Pull Output很好理解,N-MOS 将电流从管脚「推」出去,P-MOS 将电流「拉」回来。

非常简单的设计,那为什么还要有开漏输出呢?当一个信号有多个输出设备时,如果每个输出端都是推挽输出,那么当其中一个输出端输出高电平时,其他设备不能输出低电平。假设一个信号上有一个设备输出高电平,另一个设备输出低电平,这就会产生短路,产生非常大的电流,从而损坏设备。

因此,我们需要一种设计,当一个设备输出高电平时,其他设备可以输出低电平,这就是开漏输出(Open-Drain Output

在开漏输出模式下,只有 N-MOS 管起作用,P-MOS 管始终处于关断状态。当 N-MOS 导通时,电流只能从管脚经过 N-MOS 的极(Drain)至地。此时的输出电压为低电平;当 N-MOS 截止时,该管脚对外部电路不起任何作用(同样可以视作一个输入管脚,或一个 pF 级别的电容,或一个 MOhms 级别的电阻我们称这种输出电压为高阻态(Hi-Z

开漏输出通常与上拉电阻配合使用,开漏输出电路自身无法主动输出高电平。当开漏端断开(即处于高阻态)时,电路处于悬空状态,如果不加上拉电阻,输出端将无法确定电平。上拉电阻将输出引脚连接到电源正极(通常为 Vcc确保在高阻态时输出为高电平。

上拉与下拉

比较基础,先挖坑不讲。

关于复用(AF)模式的深入介绍

请见 RM0008 9.1.9

将 I/O 端口编程为复用功能时:

  • 可将输出缓冲器配置为开漏或推挽模式
  • 输出缓冲器由来自外设的信号驱动(发送器使能和数据)
  • 施密特触发器输入被打开
  • 根据 GPIOX PUPDR 寄存器中的值决定是否打开弱上拉电阻和下拉电阻
  • 输入数据寄存器每隔 1 个 AHB 时钟周期对 I/O 引脚上的数据进行一次采样
  • 对输入数据寄存器的读访问可获取 I/O 状态

框图 MSv31479V2 显示,当 IO 管脚被配置为 AF 时,IO 的输入输出被来自片上外设的信号「接管而非来自 GPIO 外设(你可以把 GPIO 模块也理解为一种片上外设,与 I2C 等外设平行)

因此我们需要一个有别于常用(或者说传统,就是当使用用户程序控制 GPIO 状态时)的模式来配置 GPIO,这就是 AF 模式。

实际上你 不需要,也不应该 手动将一个管脚配置为 AF 模式,除非你在使用某个外设,而这个外设的相关文档指导你这样做。也就是说你不必特别关心 AF 模式,只需要知道它是存在的,当你需要使用某个外设时,你需要查阅相关文档,看看是否需要将某个管脚配置为 AF 模式。

--- 下面部分换作者了 ---

几个常用的 GPIO 输出指令

c
HAL_GPIO_WritePin(GPIOx, GPIO_PIN_x, GPIO_PinState);

写入引脚状态 GPIO_PinState 可为 GPIO_PIN_SET or GPIO_PIN_RESET

(注:SET 与 RESET 对应高低电平取决于 STM32CubeMX 中的定义)

c
HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_x);

反转电平

工程配置

  • 配置复位时钟控制器(RCC)
  • 配置时钟树
    • HSE
    • HSI
    • PLLCLK
  • 配置串口定义