GPIO简介
GPIO(General Purpose Input Output)通用输入输出口
可配置为8种输入输出模式
引脚电平:0V~3.3V,部分引脚可容忍5V
输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等
输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等
关于这个 可容忍5V的意思是,最大的输入电压为5V,但是输出电压最大还是3.3V
下面是stm32的引脚定义图:
这个FT,就是five tolerate,可以容忍最大的5V输入
GPIO简单结构
在输出模式下输入有效,输入下输出无效,因为一个port只能由一个输出,可以有多个输入
首先看引脚部分
保护二级管是给输入电压限伏的
若相对于VDD的电压大于3.3V上面的电路导通
若相对于VSS的电压小于0V下面的电路导通
若输入电压在0~3.3之间就是走中间那条路
对于输入部分
存在这个的目的就是为了给输入提供一个默认的输入电平,对于只有一个数字的端,不是高就是低,若输入引脚啥也不接,那这是高电平还是低电平呢?处于浮空状态的引脚电平极易受到外界干扰而改变,要上拉或者下拉,若上面接通就是上拉电阻,若下面接通就是下拉电阻
波浪折线就是指电阻,电阻值很大为了不影响正常的输入操作
这个触发器写错了,这里应该是施密特触发器,为了对输入电压整形
模拟输入一般是接在ADC上面,然后可以给信号进行整形
复用功能输入,这是数字量,接其他需要读外设的端口量,不需要整形
对于输出部分
位设置寄存器和位清除寄存器是为了单独操作输出R的某一位,而不影响其他位
位设置寄存器:001000000(将第三位设置为1,其他位不变)
位清除寄存器:001000000(将第三位设置为0,其他位不变)
这是咱们编程函数操作的方式
第二种方法:将输出数据寄存器读出来,按位与/或的方式更改某一位&=,|=
第三种方法:位带方式(不推荐)
在推挽模式下P/N都有效,当数据控制R为1时候,P导通,N断开,直接VDD,输出高电平,这个模式又叫强推输出模式,这个模式下STM32对I/O口有绝对的控制权
在开漏模式下N工作,P断开,为1时候N断开,P那边相当于高阻值模式,为0时候街接到VSS,输出低电平,这种mode只有低电平有驱动能力
配置GPIO的端口配置寄存器,端口可以配置成以下8种模式
模式名称 | 性质 | 特征 |
---|---|---|
浮空输入 | 数字输入 | 可读取引脚电平,若引脚悬空,则电平不确定 |
上拉输入 | 数字输入 | 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平 |
下拉输入 | 数字输入 | 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平 |
模拟输入 | 模拟输入 | GPIO无效,引脚直接接入内部ADC |
开漏输出 | 数字输出 | 可输出引脚电平,高电平为高阻态,低电平接VSS |
推挽输出 | 数字输出 | 可输出引脚电平,高电平接VDD,低电平接VSS |
复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS |
复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS |
浮空输入时,端口一定要接一个连续的驱动源,不能出现悬空的状态
编程控制LED闪烁
分三步
第一步:使用RCC开启GPIO的时钟
后面打开定时器我们主要是要用到这三个函数
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
这里我们需要用到APB2的这个函数
第二步:使用GPIO_init函数初始化IO口
GPIO全部库函数为:
void GPIO_DeInit(GPIO_TypeDef* GPIOx); //gpio外设复位
void GPIO_AFIODeInit(void);//复位AFIO外设
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//重要
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);//把结构体变量赋一个默认值
//x
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
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);//同时对16个port执行写入操作
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);//重要
用结构体函数初始化GPIO口
第三步:使用函数控制GPIO口
先去main函数里面新建一个结构体的局部变量
然后GPIO_InitStructure.
按照编辑器的提示来把三个变量写出来
然后在变量类型GPIO_InitTypeDef上go to definition
知道结构体需要这三个变量,这三个变量的类型一个是16位整型,另外两个都是枚举类型
16位整型只是掩饰
搜索@ref后面的字符串
Pin_0代表接PA0
typedef enum
{ GPIO_Mode_AIN = 0x0, //Analog IN模拟输入
GPIO_Mode_IN_FLOATING = 0x04,//IN_FLOATING浮空输入
GPIO_Mode_IPD = 0x28,//In Pull Down下拉输入
GPIO_Mode_IPU = 0x48,//In Pull Up上拉输入
GPIO_Mode_Out_OD = 0x14,//Out Open Drain开漏输出
GPIO_Mode_Out_PP = 0x10,//Out Push Pull推挽输出(点灯)
GPIO_Mode_AF_OD = 0x1C,//Atl Open Drain复用开漏
GPIO_Mode_AF_PP = 0x18//Atl Push Pull复用推挽
}GPIOMode_TypeDef;
总结
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);