【自学嵌入式:stm32单片机】GPIO输出
GPIO输出
GPIO(General Purpose Input Output)通用输入输出口
- 可配置为8种输入输出模式
- 引脚电平:0V~3.3V,部分引脚可容忍5V
- 输出模式下可控制端口输出高低电平,用以驱动LED、控制器蜂鸣器、模拟协议输出时序灯
- 输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等
GPIO基本结构

在STM32种,所有的GPIO都挂载在APB2外设总线上
每个GPIO外设总共有16个引脚,下标从0到15,GPIOA的第0号引脚,我们一般把它称作PA0,接着第1号就是PA1,然后PA2,以此类推,一直到PA15,GPIOB也算一样,从PB0,一直到PB15,这样来命名,在每个GPIO模块内,主要包含了寄存器和驱动器这些东西,寄存器就是一段特殊的存储器,内核可以通过APB2总线对寄存器进行读写,这样就能完成输出电平和读取电平的功能,这个寄存器的每一位对应一个引脚,其中输出寄存器写1,对应的引脚就会输出高电平,写0,就输出低电平,输入寄存器读取为1,就证明对应的端口目前是高电平,读取为0,就是低电平,STM32是32位单片机,它每个寄存器都是32位的,但是这个端口只有16位,所以这个GPIO寄存器只有低16位对应的有端口,高16位是没有用到的,驱动器是用来增加信号的驱动能力,寄存器只负责存储数据,如果需要点灯这样的操作,需要驱动器提供更大的电路驱动能力
GPIO位结构

输入部分
I/O引脚接了两个二极管,是对输入电压进行限制的,上面VDD接3.3V,下面VSS 0V,如果输入电压比3.3V高,那上方的二极管就会导通,输入电压产生的电流就会直接流入VDD而不会流入内部电路,这样可以避免过高的电压对电路有伤害,如果输入电压比0V还要低(相对于VSS的电压,可能有负电压),那下方的二极管就会导通,电流会从VSS直接流出去,而不会从内部电路汲取电流,也是可以保护内部电路的,如果输入电压在0~3.3V之间,那两个二极管均不会导通,这时二极管对电路没有影响,这就是保护二极管的用途。

接下来到了这个连接了一个上拉电阻和一个下拉电阻的线的地方,上拉电阻至VDD,下拉电阻至VSS,这个开关是可以通过程序进行配置的,如果上面导通、下面断开,就是上拉输入模式;如果下面导通、上面断开,就是下拉输入模式,如果两个都断开就是浮空输入模式,这个上拉和下拉是为了给输入提供一个默认的输入电平的,因为对于一个数字端口,输入不是高电平就是低电平,如果输入引脚什么都不接,这时输入就会处于一种浮空状态,引脚的输入电平极易受外界干扰而改变,为了避免引脚悬空导致的输入数据不确定,我们就需要在这里加上上拉或者下拉电阻,如果接入上拉电阻,当引脚悬空时,还有上拉电阻来保证引脚的高电平,所以上拉输入又可以称作是默认为高电平的输入模式,下拉也同理,是默认为低电平的输入模式,这里上拉电阻和下拉电阻的阻值都是比较大的,
是一种弱上拉和弱下拉,目的是尽量不影响正常的输入操作。

肖特触发器应该是翻译错误,实际上是施密特触发器,这个施密特触发器是对输入电压进行整形的,它的执行逻辑是,如果输入电压大于某一阈值,输出就会瞬间升为高电平,如果输入电压小于某一阈值,输出就会瞬间降为低电平,因为引脚是外部输入,实际情况下信号可能会失真,会夹在一个波动的高低变化电平信号,如果没有施密特触发器,它很有可能会产生干扰和误判,有了施密特触发器,它会设定一个阈值上限和下限,如下图:

高于上线输出高,低于下限输出低,这样施密特触发器的输出就是首先是低于下限,输出低,然后高于上限,输出立即变为高,前一半信号有低于上限的波动,但是由于它不低于下限,所以并不会变化,而是继续维持高电平,右侧信号同理
经过施密特触发器整形的信号如下(蓝色):

然后经过施密特触发器整形的波形可以输入输入数据寄存器,我们再用程序读取输入输出寄存器对应某一位的数据,就可以知道端口的输入电平了。

最后上面还有两路线路(至片上外设),这些就是连接到片上外设的一些端口,其中有模拟输入,这个是连接到ADC上的,因为iADC需要接收模拟量,因为模拟输入需要读取模拟量,这个是接在施密特触发器前面的,复用功能输入接比如串口的输入引脚等,这根线接收的是数字量,所以接在施密特触发器后面。
输出部分

数字部分由输出数据寄存器或片上外设控制两种方式控制,通过这个数据选择器接到了输出控制部分,如果选择通过输出数据寄存器进行控制,就是普通的IO口输出,写这个数据寄存器的某一位就可操作某一个端口,左边还有个叫做位设置/清除寄存器,这个可以用来单独操作输出数据寄存器的某一位,而不影响其他位,因为这个输出数据寄存器同时控制16个端口,并且输出数据寄存器只能整体读写(不能按位寻址),所以想要单独控制某一位,需要一些特殊的操作方式:
- 第一种方式是先读出这个寄存器,然后用按位与和按位或的方式更改某一位,最后再将更改后的数据写回去在C语言种就是&=和|=的操作,这种方法比较麻烦,效率不高,对IO口的操作而言不太合适;
- 第二种方式是,如果我们要对某一位进行置1的操作,在位设置寄存器的对应位写1即可,剩下不需要操作的位写0,这样它内部就会有电路自动将输出数据寄存器对应位置为1,而剩下写0的位则保持不变,并且此操作一步到位;如果想对某一位进行清0的操作,就在清除寄存器的对应位写1即可,标准库函数也是用这种方式操作。
- 第三种方式是,读取stm32种的“位带”区域,这个位带的作用就跟51单片机的位寻址作用差不多,在stm32中,专门分配的有一段地址区域,这段地址映射了RAM和外设寄存器所有的位,读写这段地址中的数据,就相当于读写所映射位置的某一位。
![image]()
接下来输出控制之后就接到了两个MOS管,上面是P-MOS,下面是N-MOS,这个MOS管就是一种电子开关,用信号来控制开关的导通和关闭,开关负责将IO口街道VDD或者VSS,在这里可以选择推挽、开漏或关闭三种输出方式,在推挽输出模式下,P-MOS和N-MOS均有效,数据寄存器为1时,上管导通,下管断开,输出直接接到VDD,就是输出高电平,数据寄存器为0时,上管断开,下管导通,输出直接接到VSS,就是输出低电平,这种模式下,高低电平均有较强的驱动能力,所以推挽输出模式也可以叫强推输出模式,在推挽输出模式下,STM32对IO口具有绝对的控制权,高低电平都由STM32说的算;在开漏输出模式下,这个P-MOS是无效的,只有N-MOS在工作,数据寄存器为1时,下管断开,这时输出相当于断开,也就是高阻模式,数据寄存器为0时,下管导通,输出直接接到VSS,也就是输出低电平,这种模式下,只有低电平有驱动能力,高电平是没有驱动能力的,开漏模式可以作为通信协议的驱动方式,比如I2C通信的引脚,就是使用的开漏模式,在多机通信的情况下,这种模式可以避免设备的相互干扰,另外,开漏模式可以输出5V的电平信号,比如在IO口外接一个上拉电阻到5V的电源,如下图

当输出低电平时,由内部的N-MOS直接接VSS,当输出高电平时由外部的上拉电阻拉高至5V,这样可以输出5V的电平信号,用于兼容一些5V的设备,这就是开漏输出的主要用途。
剩下的一种状态就是关闭,这个是当引脚配置为输入模式的时候,这两个MOS管都无效,也就是输出关闭,端口的电平由外部信号控制。
GPIO的8种工作模式
通过配置GPIO的端口配置寄存器,端口可以配置成以下8种模式
| 模式名称 | 性质 | 特征 |
|---|---|---|
| 浮空输入 | 数字输入 | 可读取引脚电平,若引脚悬空,则电平不确定,使用浮空输入时,端口一定要接上一个连续的驱动源,不能出现悬空的状态 |
| 上拉输入 | 数字输入 | 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平 |
| 下拉输入 | 数字输入 | 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平 |
| 模拟输入 | 模拟输入 | GPIO无效,引脚直接接入内部ADC,它是ADC模数转换器的专属配置 |
| 开漏输出 | 数字输出 | 可输出引脚电平,高电平为高阻态,没用驱动能力,低电平接VSS |
| 推挽输出 | 数字输出 | 可输出引脚电平,高电平接VDD,低电平接VSS |
| 复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS |
| 复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS |
浮空/上拉/下拉输入

输入模式下,输出驱动器是断开的,端口只能输入而不能输出

上面这两个上拉电阻的开关就是上拉输入、下拉输入和浮空输入,然后输入通过施密特触发器进行波形整形后,连接到输入数据寄存器,另外,右边这个输入保护这里,上面写的是VDD或者VDD_FT,VDD_FT是对5V容忍IO脚是特殊的,它与VDD不同,容忍5V的引脚,它的上边保护二极管要做一下处理,要不然这里直接接VD 3.3V的话,外部再接入5V电压就会导致上边二极管开启,并且产生比较大的电流,这个是不太妥当的,
模拟输入

这里输出是断开的,输入的施密特触发器也算关闭的无效状态,整个GPIO的输出部分都是没用的,只剩一根线


所以,当我们使用ADC的时候,将引脚配置为模拟输入就行了,其他时候用不到模拟输入
开漏/推挽输出

这时候,输出是由输出数据寄存器控制的,这个P-MOS如果无效,就是开漏输出,如果P-MOS和N-MOS都有效,就是推挽输出,在输出模式下,输入模式是有效的,但是在输入模式下,输出都是无效的,这是因为,一个端口只能有一个输出,但可以有多个输入,所以当配置成输出模式的时候,内部也可以顺便输入以下,这个也算没啥影响的/
复用开漏/推挽输出

可以看到通过用的输出这里是没用连接的,引脚的控制权转移到了片上外设,由片上外设来控制

在输入部分,片上外设也可以读取引脚的电平,同时普通的输入也是有效的,顺便接收以下电平信号,其实在GPIO的这8种模式种,除了模拟输入这个模式会关闭数字的输入功能,在其他的7个模式中,所有的输入都是有效的
端口配置寄存器

这是一个64位寄存器,一个是端口配置低寄存器,一个是端口配置高寄存器

输出速度一般要求不高,配置50Mhz即可
端口输入数据寄存器(IDR)

这里面低16位对应16个引脚,高16位没有使用
端口输出数据寄存器(ODR)

同样,低16位对应16个引脚,高16位没有使用
端口位设置/清除寄存器(BSRR)

这个寄存器高16位进行位清除的,低16位是进行位设置的

端口位清除寄存器(BRR)

这个寄存器的低16位和端口位设置/清除寄存器高16位功能是一样的,进行位清除;这个寄存器主要是为了方便操作设置的,如果只单一进行位设置或者位清除,位设置的时候用端口位设置/清除寄存器(BSRR),位清除时,用下面端口位清除寄存器(BRR),因为在设置和清除时,使用的是低16位数据,这样方便一些,如果对多个端口同时进行位设置和位清除,那只使用位设置/清除寄存器(BSRR),如果对信号的同步性要求不高,先位设置再位清除也是没问题的。
端口配置锁定寄存器(LCKR)

它可以对端口进行锁定,防止修改

浙公网安备 33010602011771号