STM32 GPIO输入输出操作指南
文章目录
1、GPIO介绍
GPIO(General Purpose Input Output)通用输入输出口,也就是我们平时所说的I/O口。
1.1 GPIO的基本结构
在STM32中,所有的GPIO都是挂载在APB2外设总线上的;其中GPIO所有的外设名称都是按照GPIOA、GPIOB、GPIOC等等这样来命名的。
每个GPIO外设总共有16个引脚,编号是0~15;例如GPIOA的第0号引脚,我们一般将其称之为PA0。
在每个GPIO模块内,主要包含了寄存器和驱动器。寄存器就是一段特殊的存储器,内核可以通过APB2总线对寄存器进行读写,这样来完成输出电平和读取电平的功能。
寄存器的每一位对应一个引脚,其中输出寄存器写1,对应的引脚就会输出高电平;写0,就输出低电平。输入寄存器读取为1,就证明对应的端口目前是高电平;读取为0,就是低电平。
STM32是32位的单片机,所有STM32内部寄存器都是32位的,但这个端口只有16位,因此这个寄存器只有低16位对应有端口,而高16位是没有被用到的。
驱动器主要是用来增加信号的驱动能力,寄存器只负责存储数据,若要进行点灯的操作,还是需要驱动器来负责增大驱动能力的。
1.1 GPIO的位结构
最右边的I/O引脚,接了两个保护二极管来对输入电压限幅。
上面的二极管VDD-3.3V,下面二极管接VSS-0V:
左上方一个上拉电阻,一个下拉电阻:
上拉电阻至VDD,下拉电阻至VSS,这个开关是可以通过程序进行配置的:
施密特触发器:
输入数据寄存器:
上面还有两路线路,这些就是连接到片上外设的一些端口:
2、 GPIO工作模式
通过配置GPIO的端口配置寄存器,端口可以配置位以下8种输入输出模式:
(1)浮空输入
引脚内部既不接上拉电阻也不接下拉电阻,直接经施密特触发器输入I/O引脚的信号。可以读取到引脚电平,若引脚悬空,则电平不确定。
(2)上拉输入(Input Pull-up)
引脚内部连接上拉电阻,通过开关连接到电源VDD,可读取引脚电平,引脚悬空默认为高电平。
(3)下拉输入(Input Pull-down)
与上拉输入模式相反,内部连接下拉电阻,引脚悬空默认为低电平。
(4)模拟输入
GPIO无效,引脚直接接入内部ADC,实现对外部信号的采集。
(5)开漏输出(Open-Drain,OD)
可输出引脚电平,高电平为高阻态,低电平接Vss。
(6)推挽输出(Push-Pull,PP)
可输出引脚电平,高电平接VDD,低电平接Vss。
(7)复用开漏输出(AF-OD)
由片上外设控制,高电平为高阻态,低电平接Vss。
(8)复用推挽输出(AF-PP)
由片上外设控制,高电平为接VDD,低电平接Vss。
3、GPIO标准外设库接口函数
3.1 RCC接口函数
我们可以在Library文件中找到rcc.h这个文件,其中里面我们最常用到的就是红框内的3个函数:
RCC APB外设时钟控制、RCC APB2外设时钟控制、RCC APB1外设时钟控制
其中上面常用的3个函数的操作方法都是一样的,第一个参数选择外设,第二个参数选择使能或失能。
3.2 GPIO接口函数
上图就是GPIO的全部库函数,其中红色方框内的函数用来实现读写GPIO口的功能,基本上常用的就是上面蓝色方框内的函数。
1.GPIO_DeInit,调用这个函数后,所指定的GPIO外设就会被复位。
2.GPIO_AFIODeInit,也是一样,可以复位AFIO外设。
3.GPIO_Init,用结构体的参数来初始化GPIO口。我们需要先定义一个结构体变量,然后再给结构体赋值,最后调用这个函数,这个函数内部就会自动读取结构体的值,然后自动把外设的各个参数配置好。这种Init函数在STM32中基本所有的外设都有,一般我们初始化外设都是使用这个Init函数来完成的。
4.GPIO_StructInit,这个函数可以把结构体变量赋一个默认值。
3.2.1 GPIO的读取函数
1.uint8_t GPIO_ReadInputDataBit,用来读取输入寄存器的某一个端口的输入值,参数是GPIOx和GPIO_Pin,用来指定某一个端口,返回值是uint8_t,代表这个端口的高低电平。
2.uint16_t GPIO_ReadInputData,读取整个输入寄存器,参数只有一个GPIOx,用来指定外设,返回值是uint16_t,一个16位的数据,每一位代表一个端口值。
3.uint8_t GPIO_ReadOutputDataBit,读取输出寄存器的某一个位,因此他并不是用来读取端口的输入数据的,一般用于输出模式下,用来查询字节输出的是什么。
4uint16_t GPIO_ReadOutputData,用来读取整个输出寄存器。
总结来说:若想读取GPIO口的话,需要用到ReadIput的这两个函数;若在输出模式下,想要看一下现在输出了什么,才需要用到ReadOutput这两个函数。
3.2.1 GPIO的写入函数
1.GPIO_SetBits,可以把指定的端口设置为高电平。
2.GPIO_ResetBits,可以把指定的端口设置为低电平。
3.GPIO_WriteBit,这个函数有三个参数,前两个也是指定端口;第三个是BitValue,可以根据第三个参数的值来设置指定的端口。
4.GPIO_Write,第一个参数GPIOx选择外设;PortValue,这个函数可以同时对16个端口进行写入操作。
4、GPIO的初始化
操作STM32的GPIO总共需要3个步骤,涉及了RCC和GPIO两个外设:
当我们需要控制一个LED的亮灭时,我们要先对GPIO端口进行初始化。
例如我们需要点亮PA0口的LED,首先新建一个LED.c的工程,用来存放LED驱动程序的主题代码,将我们所需要初始化的函数写入这个工程文件中。
首先我们需要调用的是RCC里面的APB2外设时钟控制函数:
跳转到定义后查看参数说明,他的第一个参数就应该为RCC_APB2Periph_GPIOA,第二个参数就为ENABLE,这样时钟就开启了。
接着调用GPIO_Init函数,跳转定义查询后可以写出第一个参数为GPIOA,第二个参数是一个结构体,我们先给第二个参数结构体重命名为GPIO_InitStructure,如下所示:
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启时钟
GPIO_InitTypeDef GPIO_InitStructure;//配置端口模式
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
接着我们通过结构体成员操作符“.”来引出结构体成员,如下所示:
GPIO_InitStructure.GPIO_Mode = ;
GPIO_InitStructure.GPIO_Pin = ;
GPIO_InitStructure.GPIO_Speed = ;
接着再配置其中所需要的参数,最后的初始化代码如下:
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启时钟
GPIO_InitTypeDef GPIO_InitStructure;//配置端口模式
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
当我们完成GPIO初始化后,写入主函数下载后就可以查看LED灯的变化。
上电后LED处于低电平状态,因此为常亮;若想上电为高电平,即LED熄灭的状态则在初始化函数后添加一个写入函数GPIO_SetBits即可。程序如下:
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启时钟
GPIO_InitTypeDef GPIO_InitStructure;//配置端口模式
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
}
作者:木木bit~