STM32系统的GPIO原理与结构
一、GPIO接口原理
原理概述:GPIO是通用输入输出接口,是单片机的一些引脚,可以控制LED灯、蜂鸣器,也可用于按键输入、ADC采样等,从而实现STM32单片机与外部硬件之间的连接与数据交互。通用I/O(GPIO)是STM32微处理器非常重要的一种接口,具有使用灵活、可配置、多功能等优点。
STM32系列微处理器最多可以有7组GPIO端口,每组端口有16个I/O接口,每个接口包含下列四种寄存器:
二、GPIO的基本结构
2.1 四种输入模式
输入模式 | 应用特点 |
模拟输入 | 直接连接到内部ADC模块,可以实现对模拟信号的采样。 |
浮空输入 | 优点:输入阻抗高,MCU采集的状态是单纯的外部信号;缺点:完全浮空,状态不稳定。由于浮空阻抗大,一般由于IIC\USART等通信协议。 |
上拉输入 | I/O信号线连接到一个电阻到VCC上,当外部不接信号的时候,管脚默认为高电平。当输入信号比较弱时,容易受到干扰不稳定,选择上拉。 |
下拉输入 | I/O信号线连接到一个电阻到地上,当外部不接信号的时候,管脚默认为低电平。 |
2.2 四种输出模式
输出模式 | 应用特点 |
开漏输出 | 优点:可实现电平转换,输出电平取决于上拉电阻电源;缺点:高电平驱动能力差,取决于外部上拉电阻。 |
推挽输出 | 输出高低电平与电源电压j基本没有压差,可以提供较强的高电平与低电平驱动能力。 |
复用开漏 | 片上外设功能,比如IIC的SDL、SCL引脚等。 |
复用推挽 | 片上外设功能,比如SPI的SCK、MISO、MOSI引脚,串口等。 |
2.3 GPIO内部结构原理
GPIO每个I/O口都有上拉和下拉二极管,当外部电压过高时,上拉二极管导通,从而起到保护端口的作用;反之同理。
1. 输入模式
GPIO支持4种输入模式:浮空输入、上拉输入、下拉输入、模拟输入,所有模式有寄存器CNFy[1:0]控制,该寄存器和控制着对应开关。
(1)模拟输入
打开输入通道上拉和下拉开关,施密特触发器关闭,信号从模拟通道输入到内部AD采样电路。
(2)浮空输入
打开输入通道上拉和下拉开关,模拟通道关闭,施密特触发器能把输入畸形信号转换成标准的方波输入高低电平。浮空输入模式下,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。
(3)上拉输入
上拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。默认情况下,上拉电阻连接VDD,无信号输入时,IDR读入高电平。
(4)下拉输入
下拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。无信号输入时,IDR读入低电平。
2. 输出模式
4种输出模式:开漏输出、复用开漏输出、推挽输出、复用推挽输出。输出控制电路和MOS驱动关都有相应速度,因此,输出模式有10Hz,2MHz,50MHz三种频率可选择。
(1)开漏输出
如图,输出端口上拉P-MOS管截止,下拉N-MOS管受数据的控制。当ODR寄存器的数据为0时,下拉N-MOS管导通,输出低电平;当ODR寄存器输出数据为1时,下拉N-MOS管截止,端口出现浮空模式,因此,需要外接上拉电阻。优点是:可以实现线与功能,如IIC通信。
(2)复用开漏输出
复用开漏输出模式与开漏输出类似。输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
(3)推挽输出
上拉P-MOS管和下拉N-MOS管交替工作。当ODR寄存器输出为0时,下拉N-MOS管导通,P-MOS管截止,输出0;当ODR寄存器输出为1时,下拉N-MOS管截止,P-MOS管导通,输出1。这样即提高电路的负载能力,又提高开关速度,且导通损耗小,效率高。
(4)复用推挽输出
复用推挽输出模式与推挽输出类似。输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
三、GPIO库函数
函数名 | 描述 |
GPIO_DeInit | 将外设GPIO寄存器重设为缺省值 |
GPIO_AFIODeInit | 将复用功能(重映射事件控制和EXTI设置)重设为缺省值 |
GPIO_Init | 根据GPIO_StructInit中指定的参数初始化外设GPIOx寄存器 |
GPIO_StructInit | 把GPIO_StructInit中的每一个参数按缺省值填入 |
GPIO_ReadInputDataBit | 读取指定端口管脚的输入 |
GPIO_ReadInputData | 读取指定的GPIO端口输入 |
GPIO_ReadOutputDataBit | 读取指定端口管脚的输出 |
GPIO_ReadOutputData | 读取指定的GPIO端口输出 |
GPIO_SetBits | 设置指定的数据端口位 |
GPIO_ResetBits | 清除指定的数据端口位 |
GPIO_WriteBit | 设置或清除指定的数据端口位 |
GPIO_Write | 向指定的GPIO数据端口写入数据 |
GPIO_PinLockConfig | 锁定GPIO管脚设置寄存器 |
GPIO_EventOutputConfig | 选择GPIO管脚用作事件输出 |
GPIO_EventOutputCmd | 使能或使能事件输出 |
GPIO_PinRemapConfig | 改变指定管脚的映射 |
GPIO_EXTILineConfig | 选择GPIO管脚用作外部中断线路 |
(1)GPIO_SetBits()(与 GPIO_ResetBits函数相同)
功能描述:设置指定的数据端口位;
函数原形:GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
输入参数1:GPIOx可以是A、B、C、D或E,该参数用来选择GPIO外设;
输入参数2:GPIO_Pin,待设定的端口位,该参数可以取GPIO_Pin_x(x可以是0~15)的任意组合;
例如:把GPIOA端口的第1和第5引脚置1
GPIO_SetBits(GPIOA, GPIO_Pin_1 | PIO_Pin_5); //置 1
GPIO_ResetBits(GPIOA, GPIO_Pin_1 | PIO_Pin_5); //清 0
(2)根据GPIO_InitStruct中指定的参数初始化外设GPIOx寄存器的函数GPIO_Init();
函数原形:GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
输入参数1:GPIOx可以是A、B、C、D或E,该参数用来选择GPIO外设;
输入参数2:GPIO_InitStruc,指向结构体GPIO_InitTypeDef的指针,包含了外设GPIO的配置信息,GPIO_InitTypeDef 定义于文件"stm32f10x_gpio.h"中;
typedef struct
{uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured.This parameter can be any value of @ref GPIO_pins_define */GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins.This parameter can be a value of @ref GPIOSpeed_TypeDef */GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins.This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
GPIO_Pin:该参数选择待设置的GPIO管脚,使用操作符" | "可以一次选中多个管脚,该参数有:
- GPIO_Pin_0:选中管脚0;
- GPIO_Pin_All:选中所有管脚;
- GPIO_Pin_None:无管脚被选中;
GPIO_Speed:用以设置选中管脚的频率,取值有:
- GPIO_Speed_10MHz:最高输出频率10MHz;
- GPIO_Speed_2MHz:最高输出频率2MHz;
- GPIO_Speed_50MHz:最高输出频率50MHz;
GPIO_Mode:用以设置选中管脚的工作状态,取值有:
- GPIO_Mode_AIN :模拟输入
- GPIO_Mode_IN_FLOATING :浮空输入
- GPIO_Mode_IPD :下拉输入
- GPIO_Mode_IPU :上拉输入
- GPIO_Mode_Out_OD :开漏输出
- GPIO_Mode_Out_PP :推挽输出
- GPIO_Mode_AF_OD :复用开漏输出
- GPIO_Mode_AF_PP :复用推挽输出
例如,配置GPIOB为推挽输出模式
GPIO_InitTypeDef GPIO_InitStructure; // 定义结构体GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 管脚5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出频率为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); // 把参数写入寄存器