目录
GPIO通用输入输出口
GPIO的基本结构
I/O端口位的基本结构
输入部分
输出部分
推挽模式
开漏模式
GPIO的8种工作模式
STM32手册GPIO和AFIO大致介绍
STM32外部的设备和电路
声明:本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记,我之所以记录下来是为了方便自己日后复习。如果你也是跟着江科大的视频学习的,可以配套本专栏食用,如有问题可以QQ交流群:963138186
温馨提示:理论部分先做个大概了解即可,初学时先不要花费太多时间深究,重点在代码实现部分。理论部分等我跟着江科大的视频学完后还会自查网上的其他资料完善,订阅本专栏的学习者可以跟着学完之后再回看理论部分就会很清晰了。
GPIO通用输入输出口
GPIO(General Purpose Input Output)通用输入输出口;
可以根据应用场景配置为8种输入输出模式;
引脚电平:0V~3.3V,部分引脚可容忍5V,容忍5V的意思是可以在这个端口输入5V的电压,也认为是高电平,但是对于输出而言,最大就只能输出3.3V,因为供电就只有3.3V,具体哪些端口能容忍5V,可以参考一下STM32的引脚定义,也就是我上一篇博客上介绍那个引脚定义的表格:
表中带FT(Five Tolerate)的,就是可以容忍5V的,不带FT的就只能接入3.3V的电压。
GPIO在输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等。另外在其他的应用场景,只要是可以用高低电平来进行控制的地方,都可以用GPIO来完成,如果控制的是功率比较大的设备,只需要再加入驱动电路即可。
GPIO在输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等。这个输入模式最常见的就是读取按键,用来捕获我们按键按下的事件。另外也可以读取带有数字输出的一些模块,比如我们套件里的光敏电阻模块,热敏电阻模块等,如果这个模块输出的是模拟量,那GPIO还可以配置成模拟输入的模式,再配合内部的ADC外设,就能直接读取端口的模拟电压了。
GPIO的基本结构
左边的是APB2外设总线,也就是这个STM32系统结构图的这个位置:
在STM32中,所有的GPIO都是挂载在APB2外设总线上的。
其中GPIO外设的名称是按照GPIOA,GPIOB,GPIOC等等这样来命名的:
每个GPIO外设总共有16个引脚,编号是从0到15
GPIOA的第0号引脚,我们一般把它称作PA0,接着第1号就是PA1,然后PA2,依次类推,一直到PA15。
GPIOB也是一样,从PB0,一直到PB15,这样来命名的。
在每个GPIO模块内,主要包含了寄存器和驱动器这些东西。寄存器就是一段特殊的存储器,内核可以通过APB2总线对寄存器进行读写,这样就可以完成输出电平和读取电平的功能了。
寄存器的每一位对应一个引脚
其中输出寄存器写1,对应的引脚就会输出高电平,写0,就输出低电平。
输入寄存器读取为1,就证明对应的端口目前是高电平,读取为0,就是低电平。
因为STM32是32位的单片机,所以STM32内部的寄存器都是32位。
但是端口只有16位,所以这个寄存器只有低16位对应的有端口,高16位是没有用到的。
里面的驱动器是用来增加信号的驱动能力的。寄存器只负责存储数据,如果要进行点灯这样的操作的话,还是需要驱动器来负责增大驱动能力。
I/O端口位的基本结构
接下来我们再看一下这个GPIO中的每一位的具体电路结构
其中左边这三个就是寄存器,
中间这一部分是驱动器,
最右边这个就是某一个IO的引脚了。
整体结构可以分为两个部分,上面是输入部分,下面是输出部分。
我们先来看一下输入部分:
输入部分
首先是这个IO引脚,
这里接了两个保护二极管,这个是对输入电压进行限幅的,上面这个二极管接VDD,3.3伏,下面接VSS,0伏。
如果输入电压比3.3伏还要高,那上方这个二极管就会导通输入电压,产生的电流就会直接流入VDD,而不会流入内部电路。这样就可以避免过高的电压对内部这些电路产生伤害。
如果输入电压比0伏还要低(这个电压是相对于VSS的电压,所以是可以有负电压的),那这时下方这个二极管就会导通,电流会从VSS直接流出去,而不会从内部电路汲取电流,也是可以保护内部电路的。
如果输入电压在0~3.3伏之间,那两个二极管均不会导通,这是二极管对电路没有影响,这就是保护二极管的用途。
接下来这根线就到了这个地方,这里连接了一个上拉电阻和一个下拉电阻,
上拉电阻是VDD,下拉电阻是VSS,开关是可以通过程序进行配置的。 如果上面导从下面断开,就是上拉输入模式,如果下面导从上面断开,就是下拉输入模式,如果两个都断开,就是浮空输入模式。
那这个上拉和下拉有什么作用呢?
这个其实是为了给输入提供一个默认的输入电平的。 因为对于一个数字的端口,输入不是高电平就是低电平,那如果输入引脚啥都不接,那到底是算高电平还是低电平呢?这就不好说了。实际情况是,如果输入啥都不接,这时输入就会处于一种浮空的状态,引脚的输入电平极易受外界干扰而改变,就像是一个物体悬浮在太空一样,它的位置是不确定的,受到一点扰动就会变化。为了避免引脚悬空导致的输入数据不确定,我们就需要在这里加上拉或者下拉电阻。如果接入上拉电阻,当引脚悬空时,还有上拉电阻来保证引脚的高电平。所以上拉输入又可以称作是默认为高电平的输入模式,下拉也是同理,就是默认为低电平的输入方式。这就像是在太空的物体来到了地球上,如果不施加外力,由于重力的下拉作用,默认还是回到地面的。这个上拉电阻和下拉电阻的阻值都是比较大的,是一种弱上拉和弱下拉。目的是尽量不影响正常的输入操作。
接着我们继续往下看,这里是一个肖特基触发器。
注:实际上这个应该是施密特触发器,肖特基触发器应该是一个翻译错误。 这个斯密特触发器的作用就是对输入电压进行整形的。 它的执行逻辑是,如果输入电压大于某一阈值,输出就会瞬间升为高电平,如果输入电压小于某一阈值,输出就会瞬间降为低电平。 那举个例子,因为这个引脚的波形是外界输入的,虽然是数字信号,实际情况下可能会产生各种失真,比如有这样一个波形:
这是一个夹杂了波动的高低变化电平信号,如果没有斯密特触发器,那很有可能因为干扰而导致误判。如果有了斯密特触发器,那比如定一个这样的阈值上限和下限:
高于上限输出高,低于下限输出低,这样斯密特触发器的输出就是首先是低于下限输出低,然后在这个位置高于上限输出立即变为高。
虽然在这里信号由于波动再次低于上限了,但是对于施密特触发器来说,只有高于上限或者低于下限输出才会变化。
所以此时低于上限的情况,输出并不会变化,而是继续维持高电平。然后直到下次低于下限时才会转为低电平。
这里信号即使在下限附近来回横跳,因为没有跳到上限上面去,所以输出仍然是稳定的,
直到下一次高于上限,输出才会变为高,
那这就是斯密特触发器的输出信号。 可以看到,相比较输入信号,经过整形的信号就很完美了。
在这里使用了两个比较阈值来进行判断,中间留有一定的变化范围,这样可以有效的避免因信号波动造成的输出抖动现象。
接下来,经过施密特触发器整形的波形就可以直接写入输入数据寄存器了,我们再用程序读取输入数据寄存器对应某一位的数据,就可以知道端口的输入电平了。
最后上面这还有两路线路,
这些就是连接到片上外设的一些端口,其中有模拟输入,这个是连接到ADC上的,因为ADC需要接收模拟量,所以这根线是接到斯密特触发器前面的。
另一个是复用功能输入,这个是连接到其他需要读取端口的外设上的,比如串口的输入引脚等。这根线接收的是数字量,所以在斯密特触发器后面。
接着我们再来看一下输出的部分:
输出部分
数字部分可以由输出数据寄存器或片上外设控制,两种控制方式,通过这个数据选择器接到了输出控制部分。
如果选择通过输出数据寄存器进行控制,就是普通的IO口输出,写这个数据寄存器的某一位就可以操作对应的某个端口了。
那左边还有一个叫做位设置清除寄存器,
这个可以用来单独操作输出数据寄存器的某一位,而不影响其他位。
因为这个输出数据寄存器同时控制16个端口,并且这个寄存器只能整体读写,所以如果想单独控制其中某一个端口而不影响其他端口的话,就需要一些特殊的操作方式。
第一种方式是先读出这个寄存器,然后用按位与和按位或的方式更改某一位,最后再将更改后的数据写回去。在C语言中就是与等于和或等于的操作。 这种方法比较麻烦,效率不高,对于IO口的操作而言不太合适。
第二种方式是通过设置这个位设置和位清除寄存器,如果我们要对某一位进行置1的操作,在位设置寄存器的对应位写1即可,剩下不需要操作的位写0,这样它内部就会有电路自动将输出数据进行器对应位置为1,而剩下写0的位置保持不变,这样就保证了只操作其中某一位而不影响其他位,并且这是一步到位的操作。
如果想对某一位进行清零的操作,就在位清除寄存器的对应位写1即可,这样内部电路就会把这一位清零。
另外还有第三种操作方式,就是读写STM32中的“位带”区域。 这个“位带”的作用就跟51单片机的位寻址作用差不多,在STM32中专门分配的有一段地址区域,这段地址映射了RAM和外设寄存器所有的位。 读写这段地址中的数据就相当于读写所映射位置的某一位,这就是“位带”的操作方式。
第三种方式我们暂时不会用到,我们主要使用的是库函数来操作的,库函数使用的就是读写位设置和位清除寄存器的方法。
那我们继续看,接下来输出控制之后,就接到了两个MOS管,上面是PMOS,下面是NMOS。
这个MOS管就是一种电子开关,我们的信号来控制开关的导通和关闭,开关负责将IO口接到VDD或者VSS。
在这里可以选择推挽、开漏或关闭三种输出方式。
推挽模式
在推挽输出模式下,P-MOS和N-MOS均有效。
数据寄存器为1时,上管导通,下管断开,输出直接接到VDD,就是输出高电平,
数据寄存器为0时,上管断开,下管导通,输出直接接到VSS,就是输出低电平。
这种模式下,高低电平均有较强的驱动能力,所以推挽输出模式也可以叫强推输出模式。在推挽输出模式下,STM32对IO口具有绝对的控制权,高低电平都由STM32说了算。
开漏模式
在开漏输出模式下,这个P-MOS是无效的,只有N-MOS在工作。
数据寄存器为1时,下管断开,这时输出相当于断开,也就是高阻模式,
数据寄存器为0时,下管导通,输出直接接到VSS,也就是输出低电平。 这种模式下只有低电平有驱动能力,高电平是没有驱动能力的。
那这个模式有什么用呢?
这个开漏模式可以作为通信协议的驱动方式,比如I2C通信的引脚就是使用的开漏模式。 在多机通信的情况下,这个模式可以避免各个设备的相互干扰。另外开漏模式还可以用于输出5伏的电平信号,比如在IO口外接一个上拉电阻到5伏的电源,
当输出低电平时,由内部的N-MOS直接接VSS
当输出高电平时,由外部的上拉电阻拉高至5伏,这样就可以输出5伏的电平信号,用于兼容一些5伏电平的设备。
这就是开漏输出的主要用途。
剩下的一种状态就是关闭,这个是当引脚配置为输入模式的时候,这两个MOS管都无效,也就是输出关闭,端口的电平由外部信号来控制。
那这些就是GPIO位结构的全部介绍了。
GPIO的8种工作模式
接下来我们就来看一下GPIO的8种工作模式
通过配置GPIO的端口配置寄存器,上面这个位结构的电路就会根据我们的配置进行改变。比如开关的通断,N-MOS和P-MOS是否有效,数据选择器的选择等,这个端口的电路就可以配置成这8种模式,
首先是前三个浮空输入、上拉输入和下拉输入,这三个模式的电路结构基本是一样的,区别就是上拉电阻和下拉电阻的连接。它们都属于数字的输入口,那特征就是都可以读取端口的高低电平。当引脚悬空时,上拉输入默认是高电平,下拉输入默认是低电平,而浮空输入的电平是不确定的,所以在使用浮空输入时,端口一定要接上一个连续的驱动源,不能出现悬空的状态。下图是这三种模式的电路结构:
这里可以看到,在输入模式下,输出驱动计程器是断开的,端口只能输入而不能输出。
上面这两个电阻可以选择为上拉工作、下拉工作或者都不工作,对应的就是上拉输入、下拉输入和浮空输入。
然后输入通过斯密特触发器进行波形整形后,连接到输入数据寄存器。
另外右边这个输入保护,这里上面写的是VDD或者VDD-FT。
这就是3.3伏端口和容忍5伏端口的区别,下面可以看到,这里说VDD-FT对5伏容忍IO脚是特殊的,我们只要知道一下这个容忍5伏的引脚,它的上边保护二极管要做一下处理,要不然这里直接接VDD 3.3伏的话,外部再接入5伏电压就会导致上边二极管开启。并且产生比较大的电流,这个是不太妥当的。
接着我们再来看一下模拟输入,特征是GPIO无效引脚直接接入内部ADC,这个模拟输入可以说是ADC模数转换器的专属配置了。
我们看一下模拟输入的结构,输出是断开的,输入的斯密特触发器也是关闭的,无效状态。
所以整个GPIO的这些都是没用的,
那就只剩下从引脚直接接入片上外设,也就是ADC这一条线了,所以当我们使用ADC的时候,将引脚配置为模拟输入就行了,其他时候一般用不到模拟输入。
接着我们再来看一下开漏输出和推挽输出,这两个电路结构也基本一样,都是数字输出口,可以用于输出高低电平。
区别就是开漏输出的高电平呈现的是高阻态,没有驱动能力,而推挽输出的高低电平都是具有驱动能力的。这两种模式电路结构就是这样的:输出是由输出数据寄存器控制的,
这个P-MOS如果无效,就是开漏输出,
如果PMOS和NMOS都有效,就是推挽输出。
另外我们还可以看到,在输出模式下,输入模式也是有效的,但是我们刚才的两个电路图,在输入模式下输出都是无效的,这是因为一个端口只能有一个输出,但可以有多个输入。
所以当配置成输出模式的时候,内部也可以顺便输入一下,这个也是没啥影响的。
最后我们再来看一下复用开漏输出和复用推挽输出,
这两模式跟普通的开漏输出和推挽输出也差不多,只不过是复用的输出,引脚电平是由片上外设控制的,那我们看一下这两个模式的结构:
可以看到,通用的输出这里是没有连接的,
引脚的控制权转移到了片上外设,由片上外设来控制
在输入部分,片上外设也可以读取引脚的电平,同时普通的输入也是有效的,顺便接收一下电平信号。
其实在GPIO的这8种模式中,除了模拟输入这个模式会关闭数字的输入功能,在其他的7个模式中,所有的输入都是有效的。
那这些就是STM32 GPIO的全部介绍了。
STM32手册GPIO和AFIO大致介绍
接着我们再大概看一下STM32手册GPIO和AFIO这部分。AFIO以后再说。那我们可以看到这个手册上来就说了GPIO的8种工作模式。
刚才也给大家讲过,剩下的还有一些没讲到的点,大家可以再看一下手册。
然后这里有外设的GPIO配置,当我们使用这些片上外设的引脚时,可以参考这个表里给的配置(这里截图不全,用到的时候可以自己看看手册)
最后就是GPIO的寄存器描述,首先是GPIO配置寄存器,每一个端口的模式由4位进行配置。16个端口就需要64位,所以这里的配置寄存器有两个,一个是端口配置低寄存器,一个是端口配置高寄存器。
具体怎么配置的可以参考一下下面这个介绍
另外这里还多出来一项GPIO输出的速度,
在结构图里并没有说这个速度这个参数。GPIO的输出速度可以限制输出引脚的最大翻转速度,这个设计出来是为了低功耗和稳定性的。我们一般要求不高的时候,直接配置成50MHz就可以了。
然后是端口输入数据寄存器,也就是这个寄存器:
里面的低16位对应16个引脚,高16位没有使用
然后是端口输出数据寄存器,也就是这个寄存器:
同样低16位,对应16个引脚,高16位,没有使用
接下来是端口位设置/清除寄存器,也就是这个寄存器:
这个寄存器的高16位是进行位清除的,低16位是进行位设置的,写1就是设置或者清除,写0就是不产生影响
下面这里还有一个端口位清除寄存器:
这个寄存器的低16位和上面端口位设置/清除寄存器的高16位功能是一样的。 那为啥还要有这个寄存器呢?这个是为了方便操作设置的,如果你只想单一的进行位设置或者位清除,那位设置时用上面端口位设置/清除寄存器,位清除时用下面端口位清除寄存器。因为在设置和清除时使用的都是低16位的数据,这样就方便一些。 如果想对多个端口同时进行位设置和位清除,那就使用端口位设置/清除寄存器就行了,这样可以保证位设置和位清除的同步性。
当然你要对信号的同步性要求不高的话,先进行位设置,再进行位清除也是没问题的。
最后一个就是端口配置锁定寄存器,
这个可以对端口的配置进行锁定,防止意外更改。这个我们暂时用的不多。
STM32外部的设备和电路
接下来我们再来看一下STM32外部的设备和电路
首先是led和蜂鸣器介绍这些,学过51单片机的相信大家对这些东西应该已经比较熟悉了,就不再赘述,不懂的可以到我博客主页去找找51单片机的专栏介绍。
然后我们来看一下led和蜂鸣器的硬件电路
这下面两个图是使用STM32的GPIO口驱动LED的电路:
其中第一张图是低电平驱动的电路,Led正极接3.3伏,负极通过一个线流电阻接到PA0上,当PA0输出低电平时,Led两端就会产生电压差,就会形成正向导通电流,这样led就会点亮了。
当PA0输出高电平时,因为led两端都是3.3伏的电压,不会形成电流,所以高电平led就是熄灭。注意:这里的限流电阻一般都是要接的,一方面它可以防止led因为电流过大而烧毁,另一方面它也可以调整led的亮度。如果你觉得led太亮比较刺眼的话,可以适当的增大限流电阻的阻值(注:我们将要学习的使用面包板插接led,为了简化电路,就省去了这个限流电阻,大家自己设计电路的时候要注意加上)。
下面这个图就是高电平驱动的电路,LED负极接到GND,正极通过一个限流电阻接到PA0上,这时就是高电平电量低电平熄灭了。
那这两种驱动方式应该如何选择呢?
这就得看这个IO口高低电平的驱动能力如何的。我们刚才介绍这个GPIO在推挽输出模式下,高低电平均有比较强的驱动能力。所以在这里这两种接法均可,但是在单片机的电路里,一般倾向使用第一种接法,因为很多单片机或者芯片都使用了高电平弱驱动,低电平强驱动的规则,这样可以一定程度上避免高低电平打架。所以如果高电平驱动能力弱,那就不能使用第二种连接方法了。
接着看右边的蜂鸣器电路,
这里使用了三极管开关的驱动方案。三极管开关是最简单的驱动电路,对于功率稍微大一点的,直接用IO口驱动会导致STM32负担过重,这时就可以用一个三极管驱动电路来完成驱动的任务。
上面这个图是PNP三极管的驱动电路,(注意:这里需要一定的模电基础知识才能看得懂!)。
它左边基极给低电平三极管就会导通,那通过3.3伏和GND就可以给蜂鸣提供驱动电流了,
基极给高电平三极管截止,蜂鸣器就没有电流。
下面这个图是NPN三极管的驱动电路,
它的驱动逻辑跟PNP三极管的驱动电路是相反的。基极给高电平导通,低电平断开。
注意,这个PNP的三极管最好接在负载的上边,NPN的三极管最好接在负载的下边,这是因为三极管的通断是需要在发射极和基极之间产生一定的开启电压的,比如如果你把负载接在发射极这边,可能会导致三极管不能开启。
那这些就是STM32外部的设备和电路。
本篇就到这里,下一篇开始正式用面包板组装电路进行点灯操作了。
以上先做个基本的了解,不要求记忆,以后学完了就熟悉了。
QQ交流群:963138186
本篇就到这里,下篇继续!欢迎点击下方订阅本专栏↓↓↓