3.1.STM32-GPIO通用输入输出口
本节课分为两个部分,四个小节
第一部分主要学习GPIO的输出
第二部分主要学习GPIO的输入,附带一些C语言的知识
第一部分总共有三个程序,第一个时LED闪烁,第二个时LED流水灯,第三个是蜂鸣器

- GPIO就是我们俗称的IO口\
- 这8种模式有点多,在后文提及
- 数据0就是低电平,也就是0V,数据1就是高电平,也就是3.3V,容忍5V的意思就是可以在这个端口输入5V的电压,也是高电平
//具体是哪些端口能容忍5V,可以参考STM32的引脚定义,
这里带FT(Five Tolerate)的,就是可以容忍5V的

- 只要是可以用高低电平来进行控制的地方,都可以用GPIO来完成,如果控制的是功率比较大的设备,只需要再加入驱动设备即可.
//我们还可以用GPIO模拟通信协议输出时序,比如I2C,SPI等芯片的协议
5.输入模式最常见的就是读取按键了.用来捕获我们的按键按下事件,另外也可以读取带有数字输出的一些模块,比如STM32套件里的光敏电阻模块 , 热敏电阻模块等.如果这个模块输出的是模拟量,那GPIO还可以配置成模拟输入的模式,再配合内部的ADC外设,就能直接读取端口的模拟电压了
//除此之外,模拟通信协议时,接受通信线上的数据,也是靠GPIO的输入来完成的
GPIO的基本结构

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

GPIO位结构

左边是寄存器,中间是驱动器,右边是某一个IO口的引脚
整体可以分为两部分,上面是输入部分,下面是输出部分
二极管钳位电压
首先看这个IO引脚,这里接了两个保护二极管,这个是对输入电压进行限幅的.上面这个二极管接VDD,3V3,下面接VSS,0V
// 如果输入电压比3.3V还要高 ,那上方这个二极管就会导通,输入电压产生的电流就会直接流入VDD而不会流入内部电路,避免高电压对电路的破坏
// 如果输入电压比0V还要低 (相对于VSS的电压来说,是可以出现负电压的),那这时下方的电极管就会导通,电流会从VSS直接流出去,而不会从内部汲取电流
//如果输入电压在0~3.3V之间,那两个二极管均不会导通,这时二极管对电路没有影响,这就是保护二极管的用途
接下来到这里

这里连接了一个上拉电阻和一个下拉电阻,上拉电阻至VDD,下拉电阻至VSS,这个开关是可以通过程序进行配置的
//如果上面导通,下面断开,就是上拉输入模式
//如果下面导通,上面断开,就是下拉输入模式
//如果两个都断开,就是浮空输入模式
那这个上拉和下拉有什么作用呢,这个其实是为了给输入提供一个默认的输入电平的
对应一个数字的端口,输入不是高电平就是低电平,那如果输入引脚啥都不接,那到底算高电平还是低电平呢?
这时输入就会处于一种浮空状态,引脚的输入电平极易受外界干扰而改变
为了避免引脚悬空导致的输入数据不确定,我们就需要在这里加上上拉或者上拉电阻了
//如果接入上拉电阻,当引脚悬空时,还有上拉电阻来保证引脚的高电平,所以上拉输入又可以称作是默认为高电平的输入模式
//下拉也是同理,就是默认为低电平的输入方式

接着看,这里是一个肖特基(这里是翻译错误)施密特 触发器
这个施密特触发器的作用就是对输入电压进行整形的,它的执行逻辑是,
如果输入电压大于某一阈值,输出就会瞬间升为高电平
如果输入电压小于某一阈值,输出就会瞬间降为低电平
举个例子,引脚的波形是外界输入的,虽然是数字信号,实际情况下可能会产生各种失真
比如有这样一个波形,这是一个夹杂了波动的高低变化电平信号
如果没有施密特触发器,那很有可能因为干扰而导致误判,如果有了施密特触发器,那比如定一个这样的阈值上限和下限
只有高于上限或者低于下限,输出才会有变化
高于上限—>输出高
低于下限—>输出低

可以看到,相比较输入信号,经过整形的信号就很完美了,在这里使用了两个比较阈值来进行判断,中间留有一定的变化范围,这样可以有效的避免因信号波动造成的输出抖动现象
接下来经过施密特触发器整形后的波形就可以直接写入输入数据寄存器了,我们再用程序读取输入数据寄存器对应某一位的数据,就可以直到端口的输入电平了

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

接下来我们看数字部分,数字部分可以由输出数据寄存器或片上外设控制,两种控制方式通过这个数据选择器接到了输出控制部分 -
如果选择通过输出数据寄存器进行控制,就是普通的IO口输出,写这个数据寄存器的某一位就可以操作对应的某个端口了
// 左边还有个叫做位设置/清除寄存器,这个可以用来单独操作输出数据寄存器的某一位,而不影响其他位
// 因为这个输出数据寄存器同时控制16个端口,并且这个寄存器只能整体读写,所以像单独控制其中某一个端口而不影响其他端口的话,就需要一些特殊的操作方式
-
第一个方式是先读出这个寄存器,然后用按位与,按位或的方式更改某一位,最后再将更改后的数据写回去,在C语言中就是 &= 和 |= 的操作
-
第二个方式是通过设置这个位设置和位清除寄存器(库函数使用的就是读写位设置和位清除寄存器的方法),如果我们要对某一位进行置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,也就是输出低电平,这种模式下,只有低电平有驱动能力,高电平是没有驱动能力的
开漏模式可以作为通信协议的驱动方式,比如I2C通信的引脚,就是使用的开漏模式。在多机通信的情况下,这个模式可以避免各个设备的互相干扰

另外开漏模式还可以用于输出5V的电平信号,比如在IO口外接一个上拉电阻到5V的电源,当输出低电平时,由内部的N-MOS直接接VSS;当输出高电平时,由外部的上拉电阻拉高至5V,这样就可以输出5V的电平信号,用于兼容一些5V电平的设备,这是开漏输出的主要用途

剩下的一种状态就是关闭,这个是当引脚配置为输入模式的时候,这两个MOS管都无效,也就是输出关闭,端口的电平由外部信号来控制
以上就是GPIO位结构的全部介绍了
接下来看一下GPIO的8种工作模式
通过配置GPIO的端口配置寄存器,端口可以配置成以下8种模式,上面这个位结构的电路就会根据我们的配置进行改变,比如开关的通断、N-MOS和P-MOS是否有效、数据选择器的选择等

前三个模式
这三个模式的电路结构基本是一样的,区别就是上拉电阻和下拉电阻的连接,他们都属于数字的输入口,那特征就是,都可以读取端口的高低电平
当引脚浮空时,上拉输入默认时高电平,下拉输入默认是低电平,而浮空输入的电平是不确定的,所以在使用浮空输入时,端口一定要接上一个连续的驱动源,不能出现悬空状态,

那我们来看一下这三种模式的电路结构,这里可以看到,在输入模式下,输出驱动器是断开的,端口只能输入而不能输出,上面这两个电阻可以选择为上拉工作、下拉工作或者都不工作,对应的就是上拉输入、下拉输入和浮空输入,然后输入通过施密特触发器进行波形整形之后,连接到输入数据寄存器

右边这个输入保护这里,上面写的是VDD或者VDD_FT,这就是3V3和容忍5V端口的区别下面可以看到,这里说VDD_FT对5V容忍引脚是特殊的,它与VDD不同
这个5V的引脚,它上边的保护二极管要做一下处理,要不然这里直接接VDD3.3V的话,外部再接入5V电压就会导致上边二极管开启,并且产生比较大的电流,这不太合适

模拟输入
,特征是GPIO无效,引脚直接接入内部ADC,这个模拟输入可以说是ADC模数转换器的专属配置了

我们看一下模拟输入的结构,这里输出是断开的,输入的施密特触发器也是关闭的无效状态,所以整个GPIO的这些都是没用的

被红色框选出来的都是没用的

那就只剩下这根线了,也就是从引脚直接接入片上外设,也就是ADC,所以当我们使用ADC的时候,将引脚配置为模拟输入就行了

开漏输出和推挽输出

这两个电路结构也基本一样,都是数字输出端口,可以用于输出高低电平
区别就是开漏输出的高电平呈现的是高阻态,没有驱动能力
而推挽输出的高低电平都是具有驱动能力的

这时候,输出是由输出数据寄存器控制的
这个P-MOS如果无效,就是开漏输出
如果P-MOS和N-MOS都有效,就是推挽输出
另外我们还可以看到,在输出模式下,输入模式也是有效的(没有那种断开的开关)
但是我们刚才的电路图,在输入模式下,输出都是无效的,这是因为,一个端口只能有一个输出,但可以有多个输入
复用开漏输出和复用推挽输出
这两模式跟普通的开漏输出和推挽输出差不多,只不过是复用的输出,引脚电平是由片上外设控制的
我们来看一下他们的电路结构,可以看到通用输出这里是没有连接的,引脚的控制权转移到了片上外设,由片上外设来控制,在输入部分,片上外设也可以读取引脚的电平,同时普通的输入也是有效的,顺便接受一下电平信号


其实在GPIO的这8种模式中,除了模拟输入这个模式会关闭数字的输入功能,在其他的7个模式中,所有的输入都是有效的
这些就是STM32 GPIO的全部介绍了
接下来我们再来看一下STM32外部的设备和电路
LED

看到LED的实物图,如果是引脚没有剪过的LED,那其中长脚是正极,短脚是负极,通过LED内部也可以看正负极,这里较小的一半是正极,较大的一半是负极,这就是LED
蜂鸣器

这是它的内部电路,这里用了一个三极管开关来进行驱动,我们在VCC和GND分别接上正、负极的供电,然后
中间这个引脚接低电平,蜂鸣器就会响,接高电平,蜂鸣器就关闭
LED和蜂鸣器的硬件电路

左边两个图是使用STM32的GPIO口驱动LED的电路
低电平驱动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的三极管最好接在上边1,NPN的三极管最好接在下边,这是因为三极管的通断,是需要在发射极和基极直接产生一定的开启电压的
如果把负载接在发射极这边,可能会导致三极管不能开启
以上就是STM32外部的设备和电路了
面包板

上面是面包板的正面,下面是把面包板背面的双面胶撕掉之后的样子。这里一条一条的就是面包板内部的金属爪,右边这个图就是金属爪的示意图,当我们把元件的引脚插到面包板的孔里后,它内部的金属爪就会夹住引脚

中间的金属爪是竖着放的,上下四排是连在一起的四个整体的金属爪,那就对应着这个面包板的连接关系。
竖着的5个孔内部都是连接在一起的,这样我们元件插在一纵排的不同孔位时,内部的金属爪就实现了线路的连接

而上下四排孔整体是连在一起的,这四排是用于供电的,第一排是正极,第二排是负极,第三排是正极,第四排是负极
如果我们需要供电,就从上下的孔位中,用跳线引出来即可
下节预告:用面包板连接电路,点灯正式开始
