2.2 GPIO 输出电压
通用输入输出端口 GPIO
参考资料
- F1 系列 TRM 请见 RM0008 第 9 章
- F1 系列 HAL API 请见 UM1850 第 20 章
- G0 系列 TRM 请见 RM0444 第 6 章
推荐至少先阅读 G0 系列 TRM,因为其有中文版本。事实上笔者在此文中也大量参考 G0 系列 TRM,因此本文内容可能与 F1 系列有所出入。
如果你发现你不认识或不理解 电平
上拉(电阻)
MOSFET
等词汇,建议先自行搜索学习。
引脚工作模式
请见 UM1850 20.1.1 结构体 GPIO_InitTypeDef
,其中引脚模式的定义可大致有以下几种分类方法:
- 输入模式 / 输出模式 / 复用模式
- 输入模式 由外部驱动的信号对 MCU 产生影响,如按键输入,传感器信号输入等。 我把
GPIO_MODE_IT_*
GPIO_MODE_EVT_*
也归为输入模式,因为这些模式是为了处理外部中断而设计的。GPIO_MODE_ANALOG
也归为输入模式,因为这是为了处理模拟信号而设计的。 - 输出模式 MCU 输出信号给外部设备,如 LED 灯,继电器等
- 复用模式 当使用片上外设时,需要将引脚设置为复用模式
- 输入模式 由外部驱动的信号对 MCU 产生影响,如按键输入,传感器信号输入等。 我把
- 推挽输出 / 开漏输出 / 输入
- 接口上拉 / 接口下拉 / 无上下拉
输入模式
此处先介绍狭义的输入模式,即 GPIO_MODE_INPUT
。
将 I/O 端口编程为输入时:
- 输出缓冲器被禁止
- 施密特触发器输入被打开
- 根据 GPIOx_PUPDR 寄存器中的值决定是否打开上拉和下拉电阻
- 输入数据寄存器每隔 1 个 AHB 时钟周期对 I/O 引脚上的数据进行一次采样
- 对输入数据寄存器的读访问可获取 I/O 状态
解析:
- 输出缓冲器被禁止,意味着此时引脚不能向外输出(废话
你可以这么理解,此时的引脚在整个电路中相当于一个耐压 3.3V(部分引脚为 5V) 。 pF 级别的电容,试图对这个引脚施加超过耐压值的电压就会炸,也不能指望这个 pF 级别的电容给你提供多少电流。) , - 施密特触发器输入被打开,意味着引脚的输入电平会经过施密特触发器,这样可以减少噪声对输入的影响。
- 根据 GPIOx_PUPDR 寄存器中的值决定是否打开上拉和下拉电阻,这个在后面章节中会单独提到,这里不再赘述。
- 对输入数据寄存器的读访问可获取 I/O 状态,意思是你可以读取引脚上的电平。
GPIO_MODE_ANALOG
模式时,施密特触发器输入停用以免其对小模拟信号产生干扰,可以理解为此时信号被直接连接至 ADC 以供转换,具体请见 ADC 章节。
GPIO_MODE_IT_*
GPIO_MODE_EVT_*
也可以算是输入模式,但是这两种模式是为了处理外部中断而设计的,请查看中断相关章节,不在此处讨论。
输出模式
包含 GPIO_MODE_OUTPUT_PP
和 GPIO_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
非常简单的设计,那为什么还要有开漏输出呢?当一个信号有多个输出设备时,如果每个输出端都是推挽输出,那么当其中一个输出端输出高电平时,其他设备不能输出低电平。假设一个信号上有一个设备输出高电平,另一个设备输出低电平,这就会产生短路,产生非常大的电流,从而损坏设备。
因此,我们需要一种设计,当一个设备输出高电平时,其他设备可以输出低电平,这就是开漏输出(Open-Drain Output
在开漏输出模式下,只有 N-MOS 管起作用,P-MOS 管始终处于关断状态。当 N-MOS 导通时,电流只能从管脚经过 N-MOS 的漏极(Drain)至地。此时的输出电压为低电平;当 N-MOS 截止时,该管脚对外部电路不起任何作用(同样可以视作一个输入管脚,或一个 pF 级别的电容,或一个 MOhms 级别的电阻
开漏输出通常与上拉电阻配合使用,开漏输出电路自身无法主动输出高电平。当开漏端断开(即处于高阻态)时,电路处于悬空状态,如果不加上拉电阻,输出端将无法确定电平。上拉电阻将输出引脚连接到电源正极(通常为 Vcc
上拉与下拉
比较基础,先挖坑不讲。
关于复用(AF)模式的深入介绍
请见 RM0008 9.1.9
将 I/O 端口编程为复用功能时:
- 可将输出缓冲器配置为开漏或推挽模式
- 输出缓冲器由来自外设的信号驱动(发送器使能和数据)
- 施密特触发器输入被打开
- 根据 GPIOX PUPDR 寄存器中的值决定是否打开弱上拉电阻和下拉电阻
- 输入数据寄存器每隔 1 个 AHB 时钟周期对 I/O 引脚上的数据进行一次采样
- 对输入数据寄存器的读访问可获取 I/O 状态
框图 MSv31479V2 显示,当 IO 管脚被配置为 AF 时,IO 的输入输出被来自片上外设的信号「接管
因此我们需要一个有别于常用(或者说传统,就是当使用用户程序控制 GPIO 状态时)的模式来配置 GPIO,这就是 AF 模式。
实际上你 不需要,也不应该 手动将一个管脚配置为 AF 模式,除非你在使用某个外设,而这个外设的相关文档指导你这样做。也就是说你不必特别关心 AF 模式,只需要知道它是存在的,当你需要使用某个外设时,你需要查阅相关文档,看看是否需要将某个管脚配置为 AF 模式。
--- 下面部分换作者了 ---
几个常用的 GPIO 输出指令
HAL_GPIO_WritePin(GPIOx, GPIO_PIN_x, GPIO_PinState);
写入引脚状态 GPIO_PinState
可为 GPIO_PIN_SET
or GPIO_PIN_RESET
(注:SET 与 RESET 对应高低电平取决于 STM32CubeMX 中的定义)
HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_x);
反转电平
工程配置
- 配置复位时钟控制器(RCC)
- 配置时钟树
- HSE
- HSI
- PLLCLK
- 配置串口定义