Skip to main content

单片机-GPIO

GPIO(General-purpose input/output),通用型之输入输出的简称,功能类似8051的P0—P3,其接脚可以供使用者由程控自由使用,PIN脚依现实考量可作为通用输入或通用输出或通用输入与输出

GPIO是STM32最基本的外设之一,下面我们从三个角度来介绍STM32的GPIO,分别是:①GPIO原理、②相关寄存器、③库函数编程

2.GPIO工作原理

GPIO是通用输入输出端口(General-purpose input/output)的英文简写,是所有的微控制器必不可少的外设之一,可以由STM32直接驱动从而实现与外部设备通信、控制以及采集和捕获的功能。STM32单片机的GPIO被分为很多组,每组有16个引脚,不同型号的MCU的GPIO个数是不同的,比如STM32F103C8T6只有PA、PB以及个别PC引脚而STM32F103ZET6拥有PA~PG的全部112个引脚。所有的GPIO都有基本的输入输出功能,同时GPIO还可以作为其它的外设功能引脚。

作为STM32最基本的外设,GPIO最基本的输出功能是由STM32控制 引脚输出高低电平,比如可以把GPIO接LED灯来控制其亮灭,也可以接继电器或者三极管,通过继电器或三极管来控制外部大功率电路的通断。

GPIO最基本的输入功能是检测外部电平变化,比如把GPIO引脚连接到按键电路,通过电平的高低变化来识别按键是否被按下。

1669171246435

这是GPIO的硬件结构框图,可以从这个框图中清晰的了解GPIO外设极其各种应用模式,最右端的I/O引脚就是STM32芯片引出的GPIO引脚,其它的部件都位于芯片内部。

2.1 保护二极管及上下拉电阻

为了防止芯片被外部过高或者过低的输入电压烧坏,STM32内置保护二极管,当引脚输入电压高于VDD-FT(FT标识代表可以容忍5V电压,不同的引脚对电压的容忍值不同,需要在芯片数据手册上查找,见下图)时上方的二极管导通,当引脚电压低于Vss时,下方的二极管导通,这样就可以防止不正常的电压引入芯片导致芯片烧毁。

2.2 GPIO工作模式

STM32的GPIO共有8种工作模式,分别是输入模式的模拟输入、上拉输入、下拉输入和浮空输入以及输出模式的推挽输出、开漏输出、推挽复用输出和开漏复用输出

为了便于理解,使用结构框图来详细讲解每一种模式:

2.4 GPIO端口复用

为了最大限度的利用端口资源,STM32的大部分端口都具有复用功能。

所谓复用,就是一些端口不仅仅可以做为通用IO口,还可以复用为一些外设引脚,比如PA9,PA10可以复用为STM32的串口1引脚。复用情况可以查找数据手册,如下表所示: 1669172015422

从表格种可以看出,PA9和PA10引脚不仅可以作为GPIO还可以作为串口1的收发引脚使用。

2.5 GPIO端口重映射

为了方便布线 ,STM32配有端口重映射功能,所谓重映射就是可以把某些功能引脚映射到其他引脚。比如串口1默认引脚是PA9,PA10可以通过配置重映射映射到PB6,PB7。

端口的映射情况也可以通过查找数据手册来获得,如下表所示:

1669172029831

3.GPIO相关寄存器

STM32的每组GPIO都包含7个寄存器,分别是:

-  GPIOx_CRL :端口配置低寄存器

- GPIOx_CRH:端口配置高寄存器

- GPIOx_IDR:端口输入寄存器

- GPIOx_ODR:端口输出寄存器

- GPIOx_BSRR:端口位设置/清除寄存器

- GPIOx_BRR :端口位清除寄存器

- GPIOx_LCKR:端口配置锁存寄存器

每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问) 。

3.1 端口配置低寄存器(GPIOx_CRL )

3.2 端口配置高寄存器(GPIOx_CRH )

3.3 端口输入数据寄存器(GPIO_IDR)

3.4 端口输出数据寄存器(GPIO_ODR)

3.5 端口位设置/清除寄存器(GPIO_BSRR)

3.6 端口位清除寄存器(GPIO_BRR)

4.GPIO库函数配置

4.1 重要函数

GPIO标准外设库接口函数

1669174745835

初始化函数:

void GPIO_Init(GPIO_TypeDef GPIOx, GPIO_InitTypeDef GPIO_InitStruct);

2个读取输入电平函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

2个读取输出电平函数:

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

4个设置输出电平函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

4.2 初始化函数

void GPIO_Init(GPIO_TypeDef GPIOx, GPIO_InitTypeDef GPIO_InitStruct);

作用:初始化一个或者多个IO口(同一组)的工作方式和速度。

该函数主要是操作GPIO_CRL(CRH)寄存器,在上拉或者下拉的

时候有设置BSRR或者BRR寄存器

GPIOx: GPIOA~GPIOG

GPIO_InitTypeDef结构体:

typedef struct {

uint16_t GPIO_Pin; //指定要初始化的IO口

GPIOSpeed_TypeDef GPIO_Speed; //设置IO口输出速度

GPIOMode_TypeDef GPIO_Mode; //设置工作模式:8种中的一个

}

注意:外设(包括GPIO)在使用之前,几乎都要先使能对应的时钟。

RCC_APB2PeriphColckCmd();

GPIO输出速度:

typedef enum {

GPIO_Speed_10MHz,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

}

GPIOSpeed_TypeDef;

GPIO模式:

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;

GPIO_Init函数初始化样例:

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; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5

可以一次初始化一个IO组下的多个IO,前提是这些IO口的配置方式一样。

4.3 两个读取输入电平函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输入电平

作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。

4.3 四个设置输出电平函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

作用:设置某个IO口输出为高电平(1)。实际操作BSRR寄存器

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

作用:设置某个IO口输出为低电平(0)。实际操作的BRR寄存器。

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

这两个函数不常用,也是用来设置IO口输出电平。