目录
一.GPIO的简介
二.GPIO工作模式-----输入
1.浮空输入模式
2.上拉输入模式
3.下拉输入模式
4.模拟输入模式
三.GPIO工作模式-----输出
1.开漏输出模式
2.推挽输出模式
3.复用开漏输出
4.复用推挽输出
四.GPIO模式总结
五.GPIO配置用法
1.cubemx配置GPIO前的基本配置
2.GPIO输出模式的配置
3.GPIO输入模式的配置
4.配置完成后生成代码
5.相关GPIO代码
GPIO是通用输入输出端口的简称,简单来说就是STM32可控制的引脚,STM32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32芯片的GPIO被分成很多组,每组有16个引脚,所有的GPIO引脚都有基本的输入输出功能。
最基本的输出功能是由STM32控制引脚输出高、低电平,实现开关控制,如把GPIO引脚接入LED灯,那就可以控制LED灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。
最基本的输入功能是检测外部电平,如把GPIO引脚连接到按键,通过电平高低区分按键是否被按下。
GPIO的复用:
STM32F4 有很多的内置外设,这些外设的外部引脚都是与 GPIO 共用的。也就是说,一个引脚可以有很多作用,但是默认为IO口,如果想使用一个 GPIO内置外设的功能引脚,就需要GPIO的复用,那么当这个 GPIO 作为内置外设使用的时候,就叫做复用。 比如说串口 就是GPIO复用为串口
GPIO剖图如图所示
我们所用到的每一个GPIO其内部结构都是这样,分别对应着GPIO的八种模式 这里我们简单的介绍下:
保护二极管: IO引脚上下两边两个二极管用于防止引脚外部过高、过低的电压输入,当引脚电压高于VDD_FT时,上方的二极管导通,当引脚电压低于VSS时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁
上拉、下拉电阻:控制引脚默认状态的电压,开启上拉的时候引脚默认电压为高电平,开启下拉的时候引脚默认电压为低电平
TTL施密特触发器:基本原理是当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;IO口信号经过触发器后,模拟信号转化为0和1的数字信号 也就是高低电平 并且是TTL电平协议 这也是为什么STM32是TTL电平协议的原因
P-MOS管和N-MOS管:信号由P-MOS管和N-MOS管,依据两个MOS管的工作方式,使得GPIO具有“推挽输出”和“开漏输出”的模式 P-MOS管高电平导通,低电平关闭,下方的N-MOS低电平导通,高电平关闭
注: VDD_FT 代表IO口,兼容3.3V和5V,如果没有标注“FT”,就代表着不兼容5V
浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。MCU直接读取I/O口电平,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。 (接用电压表测量其引脚电压为1点几伏,这是个不确定值) 以用来做KEY识别。
上图红色的表示便是浮空输入的过程,外部输入时0读出的就是0,外部输入时1读出的就是1,外部没有输入IO处于阻塞读不出电平状态。
用处:感觉在信号处理方面用的比较好,比如在读取一段一段的波形,可以清晰的知道什么时候是0信号,什么时候是1信号,什么时候是没有信号的。
IO内部接上拉电阻,此时如果IO口外部没有信号输入或者引脚悬空,IO口默认为高电平 如果I/O口输入低电平,那么引脚就为低电平,MCU读取到的就是低电平
STM32的内部上拉是"弱上拉",即通过此上拉输出的电流是很弱的,如要求大电流还是需要外部上拉。
上拉输入和浮空输入的区别是,上拉电阻的开关关闭了,如上图所示。IO没有输入的时候,IO电平等于VDD即1电平,当然IO输入低电平的事就是VDD和IO口形成一个闭环电路,根据分压法IO口出分担的电压为0。当然IO输入为1时,IO口电压和VDD相等,上拉电阻好比断开了,IO口的电压还是0。
用处:在按键使用的时候特别适用,按键的一端接地,一端接IO口,当按键没有按下的时候电平为高电平,当按键按下的时候IO是低电平。
小计:
上拉输入,不管输入1还是不输入IO的电平都是1,输入0是IO口的电平是0
PS按键是共地还是共VCC选择的时候要慎重
IO内部接下拉电阻,此时如果IO口外部没有信号输入或者引脚悬空,IO口默认为低电平 如果I/O口输入高电平,那么引脚就为高电平,MCU读取到的就是高电平
下拉输入和上拉输入的区别是,上拉电阻的开关打开了了,下拉电阻的开关关闭;了。如上图所示。IO没有输入的时候,IO电平等于VSS即0电平,当IO输入高电平的时候IO口就和VSS组成一个闭合电路,根据分压法,电压都分担到了电阻上,所以IO口电平为高电平。当然IO输入为低电平的时候,IO口肯定是低电平。
用处:在按键使用的时候特别适用,按键的一端接VCC,一端接IO口,当按键没有按下的时候电平为低电平,当按键按下的时候IO是高电平电平。
PS按键是共地还是共VCC选择的时候要慎重。
当GPIO引脚用于ADC采集电压的输入通道时,用作"模拟输入"功能,此时信号不经过施密特触发器,直接直接进入ADC模块,并且输入数据寄存器为空 ,CPU不能在输入数据寄存器上读到引脚状态
当GPIO用于模拟功能时,引脚的上、下拉电阻是不起作用的,这个时候即使配置了上拉或下拉模式,也不会影响到模拟信号的输入输出
除了 ADC 和 DAC 要将 IO 配置为模拟通道之外其他外设功能一律 要配置为复用功能模式,
模拟输入和其他输入最大的区别
1、 没有连接TTL触发器,这样保留最原始的电压值,不是转换过后的0和1信号
2、 数据连接的终点不一样,其他的输入我们都是读取输入寄存器的值,而模拟输入,数据直接送到片上外设,一般是ADC。
在开漏输出模式时,只有N-MOS管工作,如果我们控制输出为0,低电平,则P-MOS管关闭,N-MOS管导通,使输出低电平,I/O端口的电平就是低电平,若控制输出为1时,高电平,则P-MOS管和N-MOS管都关闭,输出指令就不会起到作用,此时I/O端口的电平就不会由输出的高电平决定,而是由I/O端口外部的上拉或者下拉决定 如果没有上拉或者下拉 IO口就处于悬空状态
并且此时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR可读取I/O的实际状态。,I/O口的电平不一定是输出的电平。
在推挽输出模式时,N-MOS管和P-MOS管都工作,如果我们控制输出为0,低电平,则P-MOS管关闭,N-MOS管导通,使输出低电平,I/O端口的电平就是低电平,若控制输出为1 高电平,则P-MOS管导通N-MOS管关闭,使输出高电平,I/O端口的电平就是高电平, 外部上拉和下拉的作用是控制在没有输出时IO口电平
类比: 学过51单片机PO口,对PO口就是类似的开漏输出, PO口作为输出的时候一定要加上拉电阻,加上上拉电阻后,输入寄存器为1的时候,n-mos截止截止了,好比IO和输出端断开,这是IO口点压就等于上拉电阻的电压。这样变输出了高电平,如果IO口的高电平,连接到了外设低电平的,就会产生电流,电流不会流到IO口,(N-mos管截止了)直接流到外设。是不是增大了驱动能力了。(IO口的驱动能力有限,不能容忍大电流)。
GPIO复用为其他外设,输出数据寄存器GPIOx_ODR无效; 输出的高低电平的来源于其它外设,施密特触发器打开,输入可用,通过输入数据寄存器可获取I/O实际状态 除了输出信号的来源改变 其他与开漏输出功能相同。
GPIO复用为其他外设(如 I2C),输出数据寄存器GPIOx_ODR无效; 输出的高低电平的来源于其它外设,施密特触发器打开,输入可用,通过输入数据寄存器可获取I/O实际状态 除了输出信号的来源改变 其他与开漏输出功能相同。
开漏输出和推挽输出的区别:
推挽输出:
可以输出强高低电平,连接数字器件
推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止.
开漏输出:
可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极. 需要外接上拉电阻,才能实现输出高电平 合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内);
在使用任何一种开漏模式时,都需要接上拉电阻,否则只能输出低电平。
推挽输出电路: 其中IN端输出高电平时下面的PNP三极管截止,而上面NPN三极管导通,输出电平VS+;当IN端输出低电平时则恰恰相反,PNP三极管导通,输出和地相连,为低电平
开漏输出电路:IN端输出低电平时,三极管导通,使输出接地,IN端输出高电平时,三极管截止,所以引脚既不输出高电平,也不输出低电平,为高阻态。为正常使用时必须接上拉电阻,
在STM32中选用IO模式:
上拉输入、下拉输入可以用来检测外部信号;例如,按键等;
模拟输入 ——应用ADC模拟输入,或者低功耗下省电
开漏输出一般应用在I2C、SMBUS通讯等需要"线与"功能的总线电路中。
推挽输出模式一般应用在输出电平为0和3.3伏而且需要高速切换开关状态的场合。在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。
复用功能的推挽输出_AF_PP ——片内外设功能(I2C的SCL,SDA)
复用功能的开漏输出_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)
在 STM32 中选用 IO 模式
(1) 浮空输入_IN_FLOATING ——浮空输入,可以做 KEY 识别, RX1
(2)带上拉输入_IPU——IO 内部上拉电阻输入
(3)带下拉输入_IPD—— IO 内部下拉电阻输入
(4) 模拟输入_AIN ——应用 ADC 模拟输入,或者低功耗下省电
(5)开漏输出_OUT_OD ——IO 输出 0 接 GND, IO 输出 1,悬空,需要外接上拉电阻,才能实现输出
高电平。当输出为 1 时, IO 口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样 IO 口也就可以
由外部电路改变为低电平或不变。可以读 IO 输入电平变化,实现 C51 的 IO 双向功能
(6)推挽输出_OUT_PP ——IO 输出 0-接 GND, IO 输出 1 -接 VCC,读输入值是未知的
(7)复用功能的推挽输出_AF_PP ——片内外设功能(I2C 的 SCL,SDA)
(8)复用功能的开漏输出_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)
STM32 设置实例:
(1)模拟 I2C 使用开漏输出_OUT_OD,接上拉电阻,能够正确输出 0 和 1;读值时先
GPIO_SetBits(GPIOB, GPIO_Pin_0);拉高,然后可以读 IO 的值;使用
GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0);
(2)如果是无上拉电阻, IO 默认是高电平;需要读取 IO 的值,可以使用带上拉输入_IPU 和浮空输入
_IN_FLOATING 和开漏输出_OUT_OD;
通常有 5 种方式使用某个引脚功能,它们的配置方式如下:
1)作为普通 GPIO 输入:根据需要配置该引脚为浮空输入、 带弱上拉输入或带弱下拉输入,同时不要使能
该引脚对应的所有复用功能模块。
2)作为普通 GPIO 输出:根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复
用功能模块。
3)作为普通模拟输入:配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
4)作为内置外设的输入:根据需要配置该引脚为浮空输入、 带弱上拉输入或带弱下拉输入,同时使能该引
脚对应的某个复用功能模块。
5)作为内置外设的输出:根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所
有复用功能模块。
(1)打开cubemx选择stm32f103c8t6
(2)配置系统伏仿真调试接口, 在System Core 目录下单击SYS选项,将其中的Debug选项选为Serial Wire, 此时PA13 PA14引脚会被占用,配置图如下:
(3)配置系统时钟源,在System Core 目录下单击RCC选项,将其中的High Speed Clock( HSE )选项选为Crystal/ceramic resona…, 此时PD0 PD1引脚会被占用,配置图如下:
(1)配置GPIO PC13引却为输出,在右侧图中单击PC13引脚 ,在出现的选项选框中选择GPIO_Output 选项,选完后在在System Core 目录下单击GPIO选项,在GPIO子项中单击列表中的PC13,可看查看到PC13的详细设置参数.默认如下图配置,为推挽输出。
GPIO output level:指的是单片机一通电,默认的io口的电平。
GPIO Pull-up/ Pull-down:上下拉的选择,有三种
Maximun output speed:输出速度的选择。有三种
User Label:自定义该io口的命名。
(2)配置开漏输出,选择上拉输出
(1)配置GPIO PC13引却为输入,在右侧图中单击PC13引脚 ,在出现的选项选框中选择GPIO_Iutput 选项,选完后在在System Core 目录下单击GPIO选项,在GPIO子项中单击列表中的PC13,可看查看到PC13的详细设置参数.
(2)输入模式的选择,可在输入时选择上下拉的配置,分边对应的浮空,上拉,下拉的模式
(1)设置为推挽输出配置完成生成工程,下面介绍调用的函数,首先是GPIO控制函数:
HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
例如我想要控制PA0为高电平:
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
我想要控制PA0为低电平:
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
下面是GPIO的自动翻转的函数:
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
例如控制PA0自动翻转
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
(2)设置为输入配置完成生成工程,下面介绍调用的函数,首先是GPIO控制函数:
HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1))
{
HAL_Delay(20);
if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1))
{
key_val=1;
}
while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1));
}
还有其他更多的按键扫描方式,较为常用的是状态机矩阵按键扫描法,但是这种方法需要不断的扫描IO口,尽管没有延时但依旧占用大量的CPU资源,如果系统较复杂可能回影响系统的实时性能。
在高度复杂的系统中最好采用矩阵基于中断的矩阵键盘扫描法,即在普通状态下无需扫描,只当按键被按下触发了中断才进行一次按键扫描。