GPIO简介
GPIO:即General Purpose Input/Output,通用目的输入/输出。就是一种片上外设(内部模块)。
对于STM32的芯片来说,周围有一圈引脚,有时需要对引脚进行读写(读:从外部输入一个信号,连接到IO引脚上,我们去读取输入电平;写:通过IO引脚向外输出电平),但CPU本身不能直接读写IO引脚,它必须通过GPIO帮它去执行这个功能。
每一组IO引脚对应一个GPIO,例如:PA0~15,对应GPIOA;PB0~15,对应GPIOB。
GPIO的寄存器组
配置寄存器GPIOx_CR
功能:用来设置IO引脚的参数,共16份,每一份(4个比特位)用来设置单个IO引脚的参数。
CR15 | CR14 | CR13 | CR12 |
CR11 | CR10 | CR9 | CR8 |
CR7 | CR6 | CR5 | CR4 |
CR3 | CR2 | CR1 | CR0 |
比如CR0这4个比特位,它负责设置Px0这个引脚的参数(x=A、B、...G)。
输入数据寄存器GPIOx_IDR
这个寄存器共有16个比特位,即对应了一组GPIO的16个引脚。
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
IDR 15 | IDR 14 | IDR 13 | IDR 12 | IDR 11 | IDR 10 | IDR 9 | IDR 8 | IDR 7 | IDR 6 | IDR 5 | IDR 4 | IDR 3 | IDR 2 | IDR 1 | IDR 0 |
功能:读取外部输入电平。
例如:IDR0比特位对应Px0引脚,负责读取这个引脚上外部输入信号的电平。如果IDR0为0,则外部输入为低电平;如果IDR0为1,则外部输入为高电平。所以我们可以通过读取输入数据寄存器的值,来判断外部输入信号的电平。
输出数据寄存器GPIOx_ODR
功能:控制IO引脚输出电平
同样是一个16位寄存器,每一位对应一个IO引脚。例如ODR0对应Px0引脚,我们向ODR0写入一个0,则Px0引脚输出一个低电平。我们通过向这个输入数据寄存器写入一个值,来控制IO引脚的输出电平。
GPIO的8种工作模式
为什么会有8种工作模式
STM32的功能比较复杂,需要芯片周围这一圈的IO引脚能够适应不同的工作场景。为了适应不同的工作场景,IO引脚就需要不同工作方式。
对于同一个IO引脚,它既可以作为输入,也可以作为输出;既可以是通用,也可以是复用。从不同角度组合后,具体8个模式如下:
输出 | 输入 |
输出推挽 | 输入上拉 |
输出开漏 | 输入下拉 |
复用推挽 | 输入浮空 |
复用开漏 | 模拟模式 |
工作模式分类分析
分类标准1:输入与输出;
分类标准2:通用与复用;
分类标准3:推挽与输出;
分类标准4:上拉、下拉和浮空;
分类标准1:输入与输出
输入:通过IO引脚读取外部输入电平的高低;
输出:通过IO引脚向外输出高低电平
分类标准2:通用与复用
通用:CPU直接控制GPIO进行编程;
复用:CPU通过其他的片上外设,去间接控制GPIO引脚的输出;
对于输入模式没有通用和复用之分,对于CPU和片上外设,它们读取GPIO的输入值的时候,多个对象之间同时读取也不会产生干扰。
分类标准3:推挽和开漏
对于开漏:PMOS管始终断开(可去掉),当输入为1时,为高阻态;输入为0时,为低电平。
分类标准4:上拉、下拉和浮空
针对输入模式,分为上拉、下拉和浮空三种模式。对于IO引脚而言,工作在输入模式下的时候,相当于测量外部电压,所以其内阻为无穷大。
对于某个引脚,当外部为高电平时引脚为高电平,外部为低电平时引脚为低电平。但当外部输入信号断开后,此时IO引脚悬空,会在空间中接收电磁波,IO引脚上的信号会随着电磁波抖动,制造一些杂乱无章的信号。此时为输入浮空模式。
因此,我们可以给IO引脚添加上拉电阻或者加一个下拉电阻。(当IO引脚悬空的时候,给一个默认的电平)
模拟模式
对于C8T6芯片,内部有一个ADC模块,此模块会采集外部的输入信号(通过IO口)。ADC模块有10个通道,故需要10个引脚进行采集。当我们使用ADC的时候,就需要将对应的IO引脚来设置成模拟模式。
IO的最大输出速度
最大输出速度:IO允许输出电平的最大切换频率。(仅对于输出模式)
IO引脚的切换频率不能无限大,因为IO引脚的最大切换速度受限于引脚的电平切换的上升时间和下降时间,以及有效输出时间。
对于STM32,其IO引脚最大输出速度有3档可选,考虑功耗,实际应用通常选取能满足要求的最小值。如下所示:
附GPIO内部结构图:
GPIO的标准库编程接口
初始化
void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_TypeDef*GPIO_InitStruct)
//用于IO引脚的初始化
此函数用于IO引脚的初始化,实际上就是配置CR寄存器里的比特位。
读IDR
UINT8_t GPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
//读取IDR的一个比特位
UINT8_t GPIO_ReadInputData(GPIO_TypeDef*GPIOx)
//读取整个IDR寄存器
读ODR
UINT8_t GPIO_ReadOutputDataBit(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
//读取ODR的一个比特位
UINT8_t GPIO_ReadOutputData(GPIO_TypeDef*GPIOx)
//读取整个ODR寄存器
写ODR
void GPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
//将ODR的某一位置1
void GPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
//将ODR的某一位置0
void GPIO_WriteBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin,BitAction BitVal)
//将ODR的某个比特位写0或写1
void GPIO_Write(GPIO_TypeDef*GPIOx,uint16_t PortVal)
//写ODR寄存器