STM32 GPIO
时间:2023-11-18 14:37:02
STM32 的 IO 口相比 51 要复杂得多,所以使用起来要困难得多。 STM32 的 IO 软件配置如下 8 种模式:
1、输入浮空
2、输入上拉
3、输入下拉
4、模拟输入
5、开漏输出
6、推挽输出
7、推挽式复用功能
8.开漏复用功能
每个 IO 但是 IO 必须按口寄存器 32 访问位字。STM32 的很多 IO 口都是 5V 兼容,这些 IO 口在与 5V 电平外设连接有很大的优势,具体是什么? IO 口是 5V 兼容的,可以从芯片的数据手册管脚描述章中找到(I/O Level 标 FT 的就是 5V 电平兼容)。
STM32 的每个 IO 端口都有 7 控制寄存器他们分别是:
配置模式的 2 个 32 位的端口
配置寄存器 CRL 和 CRH;
2 个 32 位数据寄存器 IDR 和 ODR;
1 个 32 位置/复位寄存器BSRR;
一个 16 复位寄存器的位置 BRR;
1 个 32 锁定寄存器的位置 LCKR。
如果您想了解每个寄存器的详细使用方法,请参考《STM32 中文参考手册 V10》P105~P129。
注:CRL 和 CRH 控制着每个 IO 口模式及输出速率。
I/O端口位置的基本结构:
5伏兼容I/O端口位置的基本结构:
一、输入模式
四种输入模式:浮空输入、上拉输入、下拉输入、模拟输入
(1) GPIO_Mode_AIN 模拟输入
(2) GPIO_Mode_IN_FLOATING 浮空输入
(3) GPIO_Mode_IPD 下拉输入
(4) GPIO_Mode_IPU 上拉输入
施密特触发器在输入模式下打开,禁止输出。可以输入数据寄存器GPIOx_IDR 读取I/O 状态。模拟、上拉、下拉、下拉和浮空模式。上拉和下拉输入很容易理解,默认电平由上拉或下拉决定。浮动输入的电平是不确定的,完全由外部输入决定,这种模式接按钮时可以使用此模式。用于模拟输入ADC 采集。每隔一个数据寄存器AHB可通过数据寄存器更新1时钟周期一次GPIOx_IDR读取I/O状态。其中AHB按默认配置时钟180MHz。
1.GPIO_MODE_AIN 模拟输入 大多数情况下,应用于ADC模拟输入或低功耗省电,模拟输入模式可读取非常微妙的变化值。
2.GPIO_MODE_IN_FLOATING 浮空输入 是指IO评论状态不确定,完全由外部输入决定。如果引脚悬挂,读取的端口电平不确定
3.GPIO_MODE_IPD 下拉输入 IO输入内部下拉电阻 如果IO口外无信号输入或引脚悬空,IO默认为低电平 如果I/O口输入高电平,引脚为高电平,MCU读取的是高电平
4.GPIO_MODE_IPU 上拉输入 IO内部上拉电阻输入 如果IO口外部没有信号输入或者引脚悬空,IO默认为高电平 如果I/O口输入低电平,引脚为低电平,MCU读取的是低电平
二、输出模式
四种输出模式:开漏输出、开漏复用功能、推挽输出、推挽复用功能
(1) GPIO_Mode_Out_OD 开漏输出
(2) GPIO_Mode_Out_PP 推挽输出
(3) GPIO_Mode_AF_OD 复用开漏输出
(4) GPIO_Mode_AF_PP 复用推挽输出
输出使能在输出模式中推动模式MOS输出数据寄存器GPIOx_ODR可控制I/O输出高低点评。只有在泄漏模式下N-MOS输出数据寄存器可以控制工作I/O输出高阻或低电平。可配置输出速度,2MHz\25MHz\50MHz\100MHz的选项。这里的输出速度是I/O支持的高低电平状态切换频率最高,支持频率越高,功耗越大。如果功耗要求不严格,可以将速度设置为最大。
此时,通过输入数据寄存器打开施密特触发器GPIOx_IDR可读取I/O实际状态。 上拉、下拉或悬挂模式可用于输出模式。但此时由于输出模式时引脚电平会收到ODR而寄存器的影响ODR寄存器对应的引脚位置为0,即引脚初始化后默认输出低电平。因此,在这种情况下,上拉只能稍微提高输出电流能力,但不会影响引脚的默认状态。
1.推挽输出
可输出高、低电平、连接数字设备; 推拉结构一般是指两个三极管分别由两个互补信号控制,总是在一个三极管导通时另一个截止日期。高低电平由 IC 低电源。
推挽电路是两个参数相同的三极管或 MOSFET,以推拉的方式存在于电路中,负责正负半周波形放大任务
当电路工作时,两个对称的功率开关管每次只有一个导通,因此导通损耗小,效率高。输出可以向负载移动
灌装电流也可以从负载中提取。推拉输出级不仅提高了电路的负载能力,而且提高了开关速度。
推拉输出模式等效电路
2.开漏输出
无论输入是高电平还是低电平,P-MOS 管道总是关闭的。当低电平输入单元电路时,N-MOS 管导通,输出为低电平。输入高电平时,N-MOS 管截止时,引脚状态既不是高电平,也不是低电平,我们称之为高电阻。若要使引脚输出高电平,则引脚必须外接上拉电阻,由上拉电阻提供高电平。等效电路图如图所示。
在开漏输出模式中还有一个特点,引脚具有**“线与”**关系。也就是说,如果有很多漏输出模式的引脚连接在一起,只要一个引脚是低电平的,所有其他管脚都是低的,也就是说,所有引脚连接在一起的总线都被拉低了。只有当所有引脚输出高阻态时,总线的电平才会从上拉电阻VDD 决定。如果VDD 连接的是3.3V,所以引脚输出是3.3V,如果VDD 连接的是5V,那么引脚输出就是5V。所以如果你想让STM32 管脚输出5V,可选择泄漏输出模式,然后在外部拉电阻VDD 选择5V 可以,前提是这个STM32 引脚是容忍5V 的。一般采用开漏输出模式I2C、SMBUS 通信等需要线与功能的总线电路。也可用于电平不匹配的场合,如上述输出5V 一样。输出电平为0-3.3V 当开关状态需要高速切换时。除了必须使用泄漏输出模式外,我们通常选择推拉输出模式。配置引脚是泄漏输出还是推拉输出模式GPIOx_CRL 和GPIOx_CRH 寄存器。
三、复用功能输出
由于STM32 的GPIO 引脚具有第二功能,因此当使用复用功能的时候,也就是通过其他外设复用功能输出信号与GPIO 数据寄存器连接到一起MOS 管道电路的输入,梯形结构是用来选择复用功能还是普通功能?IO 口功能。
例如,我们使用它USART 串口通讯时,需要用到某个GPIO 引脚作为通信发送引脚,此时可以使用GPIO 引脚配置成USART 串口复用功能,引脚由串口外设控制,数据发送。
在再利用功能模式下,输出使能,输出速度可以配置,可以在泄漏和推拉模式下工作,但输出信号来自其他外设,输出数据寄存器GPIOx_ODR 无效;输入可用,可通过输入数据寄存器获得I/O 实际状态,但数据信号通常直接用外设寄存器获取。
在 STM32 中选用 IO 模型使用总结
(1) 浮空输入_IN_FLOATING ——可以做浮空输入 KEY 识别, RX1
(2)带上拉输入_IPU——IO 内部上拉电阻输入
(3)带下拉输入_IPD—— IO 输入内部下拉电阻
(4) 模拟输入_AIN ——应用 ADC 模拟输入或低功耗省电
(5)泄漏输出_OUT_OD ——IO 输出 0 接 GND, IO 输出 1.悬空需要外部上拉电阻才能实现输出
高电平。输出为 1 时, IO 口的状态由上拉电阻拉高,但由于是泄漏输出模式,因此 IO 口也就可以
从外部电路到低电平或不变。 IO 实现输入电平的变化 C51 的 IO 双向功能
(6)推拉输出_OUT_PP ——IO 输出 0-接 GND, IO 输出 1 -接 VCC,读输入值未知
(7)复用功能推拉输出_AF_PP ——片内外设功能(I2C 的 SCL,SDA)
(8)复用功能的泄漏输出_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)
三、GPIO的配置
端口位配置
输出模式位
1.输入配置
当I/O输入时端口配置:
● 禁止输出缓冲器
● 激活施密特触发输入
● 弱上拉和下拉电阻根据输入配置(上拉、下拉或浮动)连接
● 出现在I/O每个脚上的数据APB2时钟被采样到输入数据寄存器
● 可以获得输入数据寄存器的读取访问I/O状态
下图给出了I/O端口位置的输入配置
2.输出配置
当I/O当端口配置为输出时:
● 激活输出缓冲器
─ 泄漏模式:输出寄存器上的0激活N-MOS,输出寄存器上的1将端口置于高阻状态(PMOS从不被激活)。 ─ 推拉模式:输出寄存器上的0激活N-MOS,输出寄存器上的1将被激活P-MOS。
● 激活施密特触发输入
● 禁止弱上拉和下拉电阻
● 出现在I/O脚上的数在每个APB2时钟被采样到输入数据寄存器
● 在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
● 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。
下图给出了I/O端口位的输出配置
3.复用功能配置
当I/O端口被配置为复用功能时:
● 在开漏或推挽式配置中,输出缓冲器被打开
● 内置外设的信号驱动输出缓冲器(复用功能输出)
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器
● 开漏模式时,读输入数据寄存器时可得到I/O口状态
● 在推挽模式时,读输出数据寄存器时可得到最后一次写的值
下图示出了I/O端口位的复用功能配置。一组复用功能I/O寄存器允许用户把一些复用功能重新映象到不同的引脚。
4.模拟输入配置
当I/O端口被配置为模拟输入配置时:
● 输出缓冲器被禁止;
● 禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置
为’0’;
● 弱上拉和下拉电阻被禁止;
● 读取输入数据寄存器时数值为’0’。
下图示出了I/O端口位的高阻抗模拟输入配置:
GPIO相关配置寄存器
每组GPIO端口的寄存器包括:
两个32位配置寄存器(GPIOx_CRL ,GPIOx_CRH) ,
两个32位数据寄存器 (GPIOx_IDR和GPIOx_ODR),
一个32位置位/ 复位寄存器(GPIOx_BSRR),
一个16位复位寄存器(GPIOx_BRR),
一个32位锁定寄存器(GPIOx_LCKR)。
每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问) 。
是每组IO口含下面7个寄存器。也就是7个寄存器,
一共可以控制一组GPIO的16个IO口。
- GPIOx_CRL :端口配置低寄存器
- GPIOx_CRH:端口配置高寄存器
- GPIOx_IDR:端口输入寄存器
- GPIOx_ODR:端口输出寄存器
- GPIOx_BSRR:端口位设置/清除寄存器
- GPIOx_BRR :端口位清除寄存器
- GPIOx_LCKR:端口配置锁存寄存器
(1)端口配置低寄存器(GPIOx_CRL)
该寄存器的复位值为 0X4444 4444,从图 6.1.4 可以看到,复位值其实就是配置端口为浮空输入模式。从上图还可以得出:STM32 的 CRL 控制着每组 IO 端口(A~G)的低 8 位的模式。
每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。这里我们可以记住几个常用的配置,比如 0X0 表示模拟输入模式(ADC 用)、0X3 表示推挽输出模式(做输出口用,50M 速率)、0X8 表示上/下拉输入模式(做输入口用)、0XB 表示复用输出(使用 IO 口的第二
功能,50M 速率)。
CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8 位输出口,而 CRH 控制的是高 8位输出口。这里我们对 CRH 就不做详细介绍了。
下面我们讲解一下怎样通过固件库设置 GPIO的相关参数和输出
GPIO 相关的函数和定义分布在固件库文件 stm32f10x_gpio.c 和头文件 stm32f10x_gpio.h 文件中。
在固件库开发中,操作寄存器 CRH 和 CRL 来配置 IO 口的模式和速度是通过 GPIO 初始化函数完成:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
这个函数有两个参数,第一个参数是用来指定 GPIO,取值范围为GPIOA~GPIOG。
第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。
下面我们看看这个结构体的定义:
typedef struct
{
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
下面我们通过一个 GPIO 初始化实例来讲解这个结构体的成员变量的含义。
通过初始化结构体初始化 GPIO 的常用格式是:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度 50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);//根据设定参数配置 GPIO
上面代码的意思是设置 GPIOB 的第 5 个端口为推挽输出模式,同时速度为 50M。从上面初始化代码可以看出,结构体 GPIO_InitStructure 的第一个成员变量 GPIO_Pin 用来设置是要初始化哪个或者哪些 IO 口;第二个成员变量 GPIO_Mode 是用来设置对应 IO 端口的输出输入模式,这些模式是上面我们讲解的 8 个模式,在 MDK 中是通过一个枚举类型定义的:
typedef enum
{
GPIO_Mode_AIN = 0x0, //模拟输入
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
GPIO_Mode_IPD = 0x28, //下拉输入
GPIO_Mode_IPU = 0x48, //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //通用推挽输出
GPIO_Mode_AF_OD = 0x1C, //复用开漏输出
GPIO_Mode_AF_PP = 0x18 //复用推挽
}GPIOMode_TypeDef;
第三个参数是 IO 口速度设置,有三个可选值,在 MDK 中同样是通过枚举类型定义:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
(2)端口输入数据寄存器(GPIOx_IDR)
IDR 是一个端口输入数据寄存器,只用了低 16 位。该寄存器为只读寄存器,并且只能以16 位的形式读出。该寄存器各位的描述如图 6.1.7 所示:
要想知道某个 IO 口的电平状态,你只要读这个寄存器,再看某个位的状态就可以了。使用起来是比较简单的。
在固件库中操作 IDR 寄存器读取 IO 端口数据是通GPIO_ReadInputDataBit 函数实现的:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
比如我要读 GPIOA.5 的电平状态,那么方法是:
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);
返回值是 1(Bit_SET)或者 0(Bit_RESET);
(3)端口输出数据寄存器(GPIOx_ODR)
ODR 是一个端口输出数据寄存器,也只用了低 16 位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前 IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口的输出电平。该寄存器的各位描述如图 6.1.8 所示:
在固件库中设置 ODR 寄存器的值来控制 IO 口的输出状态是通过函数 GPIO_Write 来实现的:
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
该函数一般用来往一次性一个 GPIO 的多个端口设值。
(4)端口位设置/清除寄存器(GPIOx_BSRR)
BSRR 寄存器是端口位设置/清除寄存器。该寄存器和 ODR 寄存器具有类似的作用,都可以用来设置 GPIO 端口的输出位是 1 还是 0。下面我们看看该寄存器的描述如下图:
该寄存器通过举例子可以很清楚了解它的使用方法。例如你要设置 GPIOA 的第 1 个端口值为 1,那么你只需要往寄存器 BSRR 的低 16 位对应位写 1 即可:
GPIOA->BSRR=1<<1;
如果你要设置 GPIOA 的第 1 个端口值为 0,你只需要往寄存器高 16 位对应为写 1 即可:
GPIOA->BSRR=1<<(16+1)
该寄存器往相应位写 0 是无影响的,所以我们要设置某些位,我们不用管其他位的值。
(5)端口位清除寄存器(GPIOx_BRR)
BRR 寄存器是端口位清除寄存器。该寄存器的作用跟 BSRR 的高 16 位雷同,这里就不做详细讲解。在 STM32 固件库中,通过 BSRR 和 BRR 寄存器设置 GPIO 端口输出是通过函数GPIO_SetBits()和函数 GPIO_ResetBits()来完成的。
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
在多数情况下,我们都是采用这两个函数来设置 GPIO 端口的输入和输出状态。比如我们要设置 GPIOB.5 输出 1,那么方法为:
GPIO_SetBits(GPIOB, GPIO_Pin_5);
反之如果要设置 GPIOB.5 输出位 0,方法为:
GPIO_ResetBits (GPIOB, GPIO_Pin_5);
虽然 IO 操作步骤很简单,这里我们还是做个概括性的总结,操作步骤为:
1) 使能 IO 口时钟。调用函数为 RCC_APB2PeriphClockCmd()。
2) 初始化 IO 参数。调用函数 GPIO_Init();
3) 操作 IO。操作 IO 的方法就是上面我们讲解的方法。