GPIO简介(GPIO输出)
GPIO简介
GPIO(General Purpose Input Output)通用输入输出口
可配置为8种输入输出模式
引脚电平:0V~3.3V,部分引脚可容忍5V
输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等
输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等
补充:对于输出而言,最大只能输出3.3V,因为供电只有供电就只有3.3V,具体哪些端口可容忍5V,可以参考STM32的引脚定义。这在STM32简介中有提到如下图:
这里带FT的(Five TOCerate)的,就是可以容忍5V的。不带FT的就只能接入3.3V的电压。
例外在其他的应用场景,只要是可以用高低电平来进行控制的地方,都可以用GPIO来完成,如果控制的是功率比较大的设备,只要再加入驱动电路即可。除此之外,我们还可以用GPIO来模拟通信协议,比如I^2C、SPI或者某个芯片特定的协议。我们都可以用GPIO的输出模式来模拟其中的输出时序部分。
读取按键是最常见的功能。用来捕获我们的按键按下时间,另外也可以读取带有数字输出的一些模块,比如STM32套件中的光敏电阻模块,热敏电阻模块等。如果这个模块输出的定模拟量,那GPIO还可以配置模拟输入的模式,再配合内部的ADC外设,就能直接读取端口的模拟电压了。
除此之外,模拟通信协议:接受通信线上的数据,也是靠GPIO的输入来完成的。
GPIO基本结构
下面这有一个框图:
这就是GPIO的整体构造。
其中左边的是APB2外设总线,也就是这个STM32系统结构图的左下位置。
其中GPIO外设的名称是按照GPIOA、GPIOB、GPIOC等这样来命名的。
每个GPIO外设总共有16的引脚。编号是从0~15.那GPIOA的第0号引脚,我们一般把它称作PA0,接着就是PA1、PA2一直到PA15这样来命名的。
在每个GPIO模块内,主要包含了寄存器的驱动器这些东西。
寄存器就是一般特殊的存储器,内核可以通过APB2总线对寄存器进行读写,这样就可以完成输出电平和读取电平的功能了。
这个寄存器的每一个位对应一个引脚。其中输出寄存器写1,对应的引脚就会输出高电平,写0,就输出低电平。
输入寄存器读取为1,就证明对应的端口目前是高电平,读取为0,就是低电平。
因为STM32是32位的单片机,所以STM32内部的寄存器都是32位的。
但这个端口只有16位,所以这个寄存器只有低16位对应的有端口,高16位的是没有用到的。
这个驱动器是用来增加信号的驱动能力的。
寄存器只负责存储数据,如果要进行电灯这样的操作的话,还是需要驱动器来负责增大驱动能力的,那这些就是GPIO的整体基本结构了。
GPIO位结构
接下来我们再来看一下这个GPIO中每一位的具体电路结构。
那这个图就是STM32参考手册中的GPIO位结构的电路图。其中左边3个就是寄存器,中间部分是驱动器,右边是某一个IO口的引脚。
整体结构可分为上下两部分,上半部分是输入部分,下半部分是输出部分。
我们先来看一下输入部分
收i按时这个IO引脚,这里接了两个保护二极管,这个是对输入电压进行限幅的。
上个免得二极管接VDD,3.3V,下面的接VSS,0V。如果输入电压比3.3V还要高,那上方的二极管就会导通。输入电压产生的电流就会直接流入VDD而不会流入内部电路。这样可以避免过高的电压对内部这些电路产生伤害。
如果输入电压比0V还要低,这个电压时相对于VSS的电压,所以是可以有负电压的。那这时下方的二极管就会导通,电流会从VSS直接溜出去,而不会从内部电路汲取电流。也是可以保护内部电路的。
如果输入电压在0~3.3V之间,那两个二极管均不会导通。这时二极管对电路没有影响,这就是保护二极管的用途。
接下来IO引脚中间连的线,就到了两处开关的地方。这里连接了一个上拉电阻和一个下拉电阻。上拉电阻至VDD,下拉电阻至VSS。这个开关时可以通过程序进行配置的。
如果上面导通,下面断开,就是上拉输入模式;如果下面导通,上面断开,就是下拉输入模式。
如果两个都断开,就是浮空输入模式。
那这个上拉和下拉有什么用呢?
这个其实是为了给输入提供一个默认的输入电平,因为对应一个数字的端口,输入不是高电平就是低电平。
那如果输入引脚啥都不接,那到底是算高电平还是低电平呢。这就不好说了。实际情况是,如果输入啥都不接,这时输入就会处于一种浮空的状态,引脚的输入电平极易受外界干扰而改变。就像是一个物体悬浮在太空一样,它的位置是不确定的,收到一点扰动就会变化。
为了避免引脚悬空导致的输入数据不稳定,我们就需要在这里加上上拉或者下拉电阻了。
如果街上上拉电阻,当引脚悬空时,还有上拉电阻来保证引脚的高电平。所以上拉输入又可以称作是默认为低电平的的输入方式。这个上拉电阻和下拉电阻的组织都是比较大的,目的是尽量不影响正常的输入操作。
视线左移会发现有一个肖特基触发器,实际上这应该是施密特触发器,英文原文档写的是施密特触发器,图中应该是翻译错误。
这个施密特触发器的作用就是对输入电压进行整形的。它的执行逻辑是(如果输入电压大于某一阈值,输出就会瞬间升为高电平;如果输入电压小于某一阈值,输出就会瞬间降为低电平)。
举个例子:因为这个(IO)引脚的波形是外界输入的,虽然是数字信号,实际情况下可能会产生各种失真。比如有这样一个波形:
这是一个夹杂了波动的高低变化电平信号。
如果没有施密特触发器,那很可能因为干扰而导致误判。
如果有施密特触发器,那比如定一个这样的阈值上限和下限。高(低)于上限输出高(低)。
这样施密特触发器的输出就是,首先是低于下限,输出低电平,然后再(蓝色线)这个位置高于上限,输出立即变为高电平。虽然在这里(蓝色小圆圈),信号由于波动再次低于上限了。但是对于施密特触发器来说,只有高于上限或低于下限,输出才会变化。所以此时低于上限的情况,输出并不会变化,而是继续维持高电平,然后知道下次低于下限时,才会转为低电平。
这里(蓝色右下圈)信号即使在下限附近来回横条,因为没有跳到上限上面去,所以输出仍是稳定的。直到下一次高于上限,输出才会变为高电平。
那这就是施密特触发器的输出信号。可以看出相比较输入信号,经过整形的信号就很了。
在这里使用了两个比较阈值来进行判断,中间留有一定的变化范围,可以有效地避免因信号波动造成的输出抖动现象。
接下来经过施密特触发器整型的波形就可以直接写入输入数据寄存器了。我们再用程序读取输入数据寄存器对应某一位的数据,就可以知道端口的输入电平了。
最后上面(左上角)这还有两条线路,这些就是连接到片上的外设的一些端口。其中有模拟输入,这个是连接接到ADC上的。因为ADC需要接受模拟量。所以这根线时接到施密特触发器前面的。
另一个是复用功能输入,这个是连接到其他需要读取端口的外设上的。比如串口的输入引脚等,这根线接受的时数字量,所以在施密特触发器后面。
接着我们再来看输出的部分。
数字部分可以由输出数据寄存器或片上外设控制,两种控制方式通过这个数据选择器,找到了输出控制部分。
乳沟选择通过输出数据进行控制,就是普通的IO口输出。写这个数据寄存器的某一位就可以通过操作对应的某个端口了。
那左边还有个叫做位设置/清楚寄存器。这个可以用来单独操作输出数据寄存器的某一位而不是影响其他位。
因为这个输出寄存器同时控制16个端口,并且这个寄存器只能整体读写,所以如果想单独控制器中某一个端口而不影响其他端口的话,就需要一些特殊的方式。
1.先读出这个寄存器,然后用按位与和按位或的方式更改某一位,最后再将更改后的数据写回去。
在C语言种就是&=和|=的操作,这种方法比较麻烦,效率不高,对于IO口的操作而言不太合适。
2.通过设置这个位位置和位清楚寄存器。如果我们要对某一位进行置1的操作,在位设置寄存器的对应位写1即可,剩下不需要操作的位置写0。这样它内部就会有电路,自动将输出数字寄存器种对应位置为1,剩下写0的为则保持不变。这样就保证了只操作其中某一位而不影响其他位,并且这是一步到位的操作。如果相对某一位进行清0的操作,就在位清除寄存器的对应位置写1即可。这样内部电路就会把这一位清0了。
这就是第二种方式,也就是这个位设置和位清除寄存器的作用,另外还有第三种操作方式,就是读写STM32中的“位带领域”,这个位带的作用就是跟51单片机的位寻址的作用差不多。
在STM32中,专门分配的有一段地址区域,这段地址映射了RAM和外设寄存器所有的位。
读写这段地址中的数据,就相当于读写所映射位置的某位,这就是位带的操作方式,这个暂时用不上,主要还是使用库函数来操作。
库函数是使用的是读写位设置和位清除寄存器的方法,那我们继续看,接下来输出控制之后就接到了下面两个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,也就是输出低电平。这种模式下,只有低电平有驱动能力,高电平没有。
那这个模式有啥作用呢?这个开漏模式可以作为通协的驱动方式。比如I^2C通信的情况下,这个模式可以避免各个设备的相互干扰,另外开漏模式还可以用于输出5V的电平信号,比如在IO口外接一个上拉电阻到5V的电源,当输出低电平时,由内部的N-MOS直接接VSS。当输出高电平时,由外部的上拉电阻拉高至5V,这样就可以输出5V的电平信号,用于兼容一些5V电平的设备,这就是开漏输出模式的主要用途。
剩下的一种状态就是关闭,这个是当引脚配置为输入模式的时候,两个MOS管都无效,也就是输出关闭,端口的电平由外部信号来控制。
那这些就是GPIO位结构的全部介绍了。
GPIO模式
那通过配置GPIO的端口配置寄存器,上面这个位结构的电路就会根据我们的配置进行改变。比如开关的通断,N-MOS和P-MOS是否有效,数字选择器的选择等。
那这个端口的电路就可以配置成以下8种模式:
首先是前三个,浮空输入,上拉输入,下拉输入。这三个模式的电路结构基本是一样的,区别就是上拉电阻和下拉电阻的连接。它们都属数字的输入口。那特征就是,都可以读取端口的高低电平。
当引脚悬空时,上拉输入默认是高电平;下拉输入,默认是低电平;而浮空输入的电平是不确定的,所以在使用浮空输入时,端口一定要街上一个连续的驱动源,不能出现悬空的状态。
那我们来看一下这三种模式的电路结构:
这里可以看到,在输入模式下,输出驱动器是断开的,端口只能输入而不能输出。
上面两个电阻可以选择为上拉工作,下拉工作或都不工作。对应的就是上拉输入,下拉输入和浮空输入。然后输入通过是施密特触发器进行波形整合后,连接到输入数据寄存器。另外,右边这个输入保护这里,上面写的是VDD或者VDD_FT,这就是3.3V端口和容忍5V端口的区别。
下面可以看到,这里说VDD——FT对5V容忍,IO脚是特殊的,它与VDD不同。
这个容忍5V的引脚,它的上边保护二极管要做一下处理。要不然这里直接VDD3.3V的话,外部再接入5V电压就会导致上边二极管开启,并且产生比较大的电流,这个是不太妥当的。
接着我们再来看一下下面这个模拟输入,特征是GPIO无效,引脚直接接入内部ADC。这个模拟输入可以说是ADC模数转换器的专属配置了。
看一下模拟输入结构:
这里输出是断开的,输入的施密特触发器是关闭的无效的状态。所以整个GPIO的IO引脚左边全部部分都是没用的。就只剩下IO引脚这里的一根线了。也就是从引脚直接接入片上外设,也就是ADC。所以当我们使用ADC的时候,将引脚配置位模拟输入就行了,其他时候一般用不到模拟输入。
接着看开漏模式输入和推挽输出。这两个电路结构也基本一样。都是数字输出口,可以用于输出高低电平。区别就是开漏输出的高电平呈现的是高阻态,没有驱动能力。而推挽输出的高低电平都是具有驱动能力的。
那这两种模拟的电路结构就是这样的。这时候输出是电输出数据寄存器控制的。
这个P-MOS如果无效,就是开漏,如果P-MOS和N-MOS都有效,就是推挽。另外我们还可以看到,在输出模式下,输入模式也是有效的。但是浮空输入/上拉输入/下拉输入电路图,再输入模式下, 输出都是无效的。这是因为,一个端口只能有一个输出,但可以有多个输入。所以当配置成输出模式的时候,内部也可以顺便输入一下,这个也是没啥影响的。
最后我们来看一下复用开漏、推挽输出。
这两模式跟普通的开漏和推挽输出也差不多,只不过是复用的输出。引脚电平是由片上外设控制的,那我们看一下这两个模式的结构:
可以看到通用的输出这里是没有链接的。引脚的控制权转移到了片上外设,由片上外设来控制,在输入部分,片上外设也可以读取引脚的电平,同时普通的输入也是有效的,顺便接受一下电平信号。其中在GPIO的这8种模式中,除了模拟输入这个模式会关闭数字的输入功能,在其他的7个模式下中,所有的输入都是有效的。
那这些就是STM32GPIO(输出)的全部部分了。
除以上内容外, 还有部分内容在手册中可以查看,我就不一一说明了。
接下来我们再来看一下STM32外部的设备和电路。
LED和蜂鸣器简介
首先是LED和蜂鸣器的介绍:
LED:发光二极管,正向通电点亮,反向通电不亮
有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定
无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音
图片说明:
1.这个就是LED的电路符号,左边是正极,右边是负极。
2.这个是LED的实物图,如果是引脚没有剪过的LED,那其中长脚是正极,短脚是负极。通过LED内部也可以看出正负极,较小的是正极,较大的是负极。
3.这就是蜂鸣器了,分为有源和无源,该图为有源蜂鸣器。右边是它的内部电路,这里用了一个三极管开关来进行驱动。我们在VCC和GND分别接上正负极的供电。然后中间这个引脚接低电平,蜂鸣器就会响,接高电平,蜂鸣器就会关闭。那这图的右侧位置也有文字说明,写的是低电平触发,这就是有源蜂鸣器的用法。
硬件电路
接下来我们来看一下LED和蜂鸣器的硬件电路。
左边两个图是使用STM32的GPIO口驱动LED的电路。其中上面这个是低电平驱动的电路。LED正极接3.3V,负极通过一个限流电阻接到PA0上。当PA0输出低电平时,LED两端就会产生电压差,就会形成正向导通电流,这样LED就会点亮了。
当PA0输出高电平时,因为LED两端都是3.3V的电压,不会形成电流,所以高电平LED就是熄灭。
这里的限流电阻一般都是要接的,一方面可以防止LED因为电流过大而烧毁,另一方面它也可以通过调整LED的亮度。如果你觉得LED太亮比较刺眼的话,可以适当的增大限流电阻的阻值。
下面图就是高电平驱动的电路,LED负极接到GND,正极通过一个先留点则接到PA0上,这时就是高电平点亮,低电平熄灭。
那这两种驱动方式一个该如何选择呢?
这就得看这个IO口高低电平的驱动能力如何了。
上面说到,这个GPIO在推挽输出模式下,高低电平均有比较强的驱动能力。所以在这里二者均可。但是在单片机的电路里,一般倾向使用第一种接法。因为很多单片机或者芯片,都使用了高电平弱驱动,低电平强驱动的规则。这样可以一定程度上避免高低电平打架。所以如果高电平驱动能力弱,那就不能使用第二种连接方法。
接着看右边的蜂鸣器电路。这里使用了三极管开关的驱动方案。三极管开关时最简单的驱动电路,对于功率稍大一点的,直接用IO口驱动会导致STM32负担过重,这时就可以用一个三极管驱动电路来完成驱动的任务。
上面这个图是PNP三极管的驱动电路。三极管左边是基极,带箭头的是发射极,剩下的是集电极。它左边的基极经低电平,三极管就会导通。那通过3.3V和GND,就可以给蜂鸣器提供驱动电流。基极给高电平,三极管截止,蜂鸣器没有电流。
下面这个图是NPN三极管的驱动电路。
同样,左边是基极,带箭头的是发射极,剩下的是集电极。它的驱动逻辑跟上面的是相反的。基极给高电平导通,低电平断开。
另外注意一下,这个PNP的三极管最好接在上边。NPN的三极管最好接在下便。这是因为三极管的通断,是需要在发射极和基极直接产生一定的开启电压的。如果你把负载接在发射极这边,可能导致三极管不能开启。
那这些就是STM32外部的设备和电路的相关内容了。