前言
对于STM32的GPIO,可以算是最基础的功能,但是大家可能还是分不清每一种模式之间到底有什么区别,又或者该怎么去设置这些模式,这篇文章我们就一张图讲清楚GPIO的八种模式。
GPIO的结构图
下图是官方手册上面GPIO的结构图,接下来我们一起来读懂她!
首先,先让我们聚焦在最右侧的I/O pin口,我们可以先假设这是一个GPIOA0,这既可以作为一个输出口也可以是一个输入口。
我们可以通过配置寄存器来配置是输入还是输出。
这是端口配置低寄存器GPIOx_CRL,用来配置GPIOx的0~7位Pin。(高八位通过端口配置高寄存器来配置)我们通过每四位来配置一个Pin口,比如0、1、2、3位来配置Pin0口的模式,4、5、6、7位来配置Pin1口的模式。
输入状态下
GPIOA_CRL = (unsigned int)0x00;
//这就是令0位和1位分别置0,使其为输入模式。此时输出就是关闭的。
当作为一个输入口使用时,信号进入这个Pin口,如果这个信号的电压大于VDD,那么上面二极管导通,小于VSS,则下面二极管导通,这也是对信号的一个限制,用来保护单单片机的内部电路,以防被烧坏。
之后这个信号到达了标记的①点,这里如果闭合上面的开关,断开下面的开关,那么如果没有信号传进来的时候,默认的信号就是VDD,但是由于这个上拉电阻很大,所以一旦信号进来,就是I/O口的信号传下去。如果下面的开关闭合,上面断开,则默认VSS信号。如果都断开也就是浮空状态,此时电平信号极易受到波动,所以这个时候我们需要保证信号的连续性。
GPIOA_CRL &= ~(unsigned int)0x08;
GPIOA_CRL |= (unsigned int)0x04;
//这就是将3位和2位分别置01,将两个开关都断开,此时GPIOA0就是浮空输入模式
GPIOA_CRL |= (unsigned int)0x08;
GPIOA_CRL &= ~(unsigned int)0x04;
/*这就是将3位和2位分别置10,此时GPIOA0就是上拉/下拉输入模式
根据数据手册,我们可以根据GPIOx_ODR寄存器进一步来设置是上拉还是下拉。
输入模式下,输出是关闭的,所以这个端口输出寄存器是不需要存储输出数据的。(但是输出模式下,输入也是打开的)
此时如果ORD对应位置0就是下拉,对应位置1就是上拉模式。*/
GPIOA_ODR &= ~(unsigned int)0x01;//下拉输入模式,也就是将下面开关闭合
GPIOA_ODR |= (unsigned int)0x01;//上拉输入模式,也就是将上面开关闭合
之后这个信号到达标记的②,如果我们需要直接使用模拟信号,我们就不处理信号,直接通过那个Analog Input输入到单片机内部,这一步我们一般用于ADC,我们后面讲。这个模式也就是将配置寄存器的0、1、2、3位都设置为0即可。(这个状态下上拉电阻和下拉电阻之前的开关都是断开的,也不能经过施密特触发器,因为我们要获取最原始的模拟信号,不能经过任何的处理。)
之后我们的信号就经过一个施密特触发器,它的作用就是将高于一定值的信号输出为1,低于一定值的信号输出为0,可以完美的将模拟信号转化为数字信号,也就到达了标记③。这个时候可以用作片上外设输出,也可以存入到Input Data Registe—端口输入数据寄存器(GPIOx_IDR)中。
我们可以直接对这个寄存器的数据进行读取,也就是获取到I/O口的值。
unsigned short int Input_Data;
Input_Data = (unsigned short int)GPIOA->IDR; //我们读取了GPIOA的16个Pin的值,其中0位也就是GPIOA0的值。
//这个寄存器直接读取的32位,但是一共就16个Pin,前面16位也是空的,所以直接转成short来节约空间。
输出状态下
GPIOA_CRL = (unsigned int)0x01;
/*这就是令1位和0位分别为01,使其为输出模式。
其实01,10,11只是输出速率不同,一般情况下没有任何影响,只是特定情况下用于节约单片机的功耗。*/
我们首先看Output control,它的前面是一个选择器,它可以用来选择输出的数据是外设上面的还是端口输出数据寄存器GPIOx_ODR上的。选择其他外设也就是复用模式,选择GPIOx_ODR作为数据来源也就是通用模式。
不管选择哪个作为信号来源,都是数字信号。如果选择推挽输出,那么P-MOS和N-MOS都是有效的 。此时如果需要输出的数据为1的话,Output control会使P-MOS导通,使N-MOS截至,那么VDD直接通过I/O口输出;如果需要输出的数据为0的话,Output control会使N-MOS导通,使P-MOS截至,那么VSS直接通过I/O口输出。如果选择开漏输出模式,那么P-MOS是无效的,N-MOS是有效的,此时如果需要输出的数据为1的话,Output control会使N-MOS截至,那么I/O口既不能导通VDD也不能导通VSS,此时属于高阻状态,也就是数字信号里面的X;如果需要输出的数据为0的话,Output control会使N-MOS导通,那么VSS直接通过I/O口输出。(在这种开漏模式下,我们应该也发现高阻模式下输出“1”是没有驱动能力的了,所以开漏模式通常用于通讯协议的驱动方式或者在I/O口上拉一个5V用来输出5V的电平信号。)
此时我们通过排列组合发现输出模式下有四种模式,分别是通用推挽输出、通用开漏输出、复用推挽输出、复用开漏输出。
GPIOA_CRL &= ~(unsigned int)0x08;
GPIOA_CRL &= ~(unsigned int)0x04;
/*这就是令配置寄存器的3位和2位分别置0,选择器选择ODR寄存器里面的数据作为输出的信号,P-MOS、N-MOS都有效。
此时也就是通用推挽输出模式*/
GPIOA_CRL &= ~(unsigned int)0x08;
GPIOA_CRL |= (unsigned int)0x04;
/*这就是令配置寄存器的3位和2位分别置01,选择器选择ODR寄存器里面的数据作为输出的信号,
P-MOS无效、N-MOS有效。
此时也就是通用开漏输出模式*/
GPIOA_CRL |= (unsigned int)0x08;
GPIOA_CRL &= ~(unsigned int)0x04;
/*这就是令配置寄存器的3位和2位分别置10,选择器选择外设上的数据作为输出的信号,P-MOS、N-MOS都有效。
此时也就是复用推挽输出模式*/
GPIOA_CRL |= (unsigned int)0x08;
GPIOA_CRL |= (unsigned int)0x04;
/*这就是令配置寄存器的3位和2位分别置1,选择器选择外设上的数据作为输出的信号,P-MOS无效、N-MOS有效。
此时也就是复用开漏输出模式*/
总结
我们可以通过配置寄存器来改变硬件电路的不同状态,用来形成八种输入输出模式。我们现在也应该很清楚每一种模式下电路的结构状态,可以进一步对寄存器直接操作用来输出或者获取信号。