学一个单片机我们首先得从如何点灯开始学,而学习点灯的过程就是对一个单片机的最基础的单元进行学习——GPIO(General-purpose input/outpu)
目录
一.GPIO模式。
基于stm32f103它的gpio有如下八种模式
4种输入模式
浮空输入模式:数据通道中仅接入TTL触发器(作用是将相对缓慢变化的模拟信号变成矩形信号)整形,随后输入输入数据寄存器,该种工作模式未接入任何上拉/下拉电阻。 模式特点:在该引脚悬空(无信号输入)的情况下,读取该端口的电平是不确定的。 适用场合:外部按键输入/USART RX引脚。
上拉输入模式:与浮空输入模式相比,仅仅是在数据通道前端接入了一个上拉电阻,其余无变化。 模式特点:在无信号输入时端口电位受上拉电阻钳制,I/O端口输入电平始终保持为高电平;而当端口输入电平为低电平时,I/O端口输入电平为低电平。 适用场合:需要IO内部上拉电阻输入时,器件的外部中断(IRQ)引脚触发中断条件为下降沿触发/低电平触发,这样在无信号输入时始终保持高电平,如果有事件触发中断IRQ可以输出一个低电平,进而可产生(下降沿/低电平)中断。例如单片无线收发器芯片NRF24L01的IRQ引脚的工作模式即为上拉输入模式。
下拉输入模式:与浮空输入模式相比,仅仅是在数据通道前端接入了一个下拉电阻,其余无变化。 模式特点:在无信号输入时端口电位受下拉电阻钳制,I/O端口输入电平始终保持为低电平;而当端口输入电平为高电平时,I/O端口输入电平为高电平。 适用场合:需要IO内部下拉电阻输入时,器件的外部中断(IRQ)引脚触发中断条件为上升沿触发/高电平触发时,该端口可以选择下拉输入模式。
模拟输入模式:数据通道不接入任何处理单元(TTL触发器/钳制电阻),直接输入MCU内部的处理单元。 模式特点:相较于其他输入模式只能读取到逻辑高/低电平(数字量),该模式能读取到细微变化的值(模拟量)。 适用场合:ADC模拟输入/低功耗下省电。
4种输出模式
推挽输出:输出具有驱动能力,当CPU输出逻辑’0’时,I/O端口输出低电平,而当CPU输出逻辑’1’时,I/O端口输出高电平,通常作为普通的GPIO用于驱动LED、数码管等电子元器件或输出控制某个信号。
开漏输出:适合做电流型的驱动,其吸收电流能力较强。当CPU输出逻辑’0’时,I/O端口输出低电平,而当CPU输出逻辑’1’时,该引脚处于开漏,也就是浮空状态(高阻态),如果想输出高电平则必须接入上拉电阻。同时IO口可以由外部电路改变为低电平或不变,即可读IO输入电平变化,实现了I/O端口的双向功能;此外,可以将多路开漏输出的引脚连接到一条线上,通过一个上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系,这也是I2C,SMBus,等总线判断总线占用状态的原理。
复用推挽输出:在STM32中,一个引脚通常可作为普通GPIO来使用,但通常有多个复用模块对应着同一个引脚,那么当这个GPIO作为内置外设引脚时,就叫做复用模式。 适用场合:常见片内外设(USART TX引脚/SPI/PWM输出等等)
复用开漏输出:与开漏输出特性一致,只不过引脚选择了复用功能。 适用场合:常见片内外设(I2C/SMBus等等)
注意事项:当GPIO引脚的主功能为驱动片上外设(如I2C)时,此时也可选择对应推挽/开漏输出模式而不启用复用引脚功能。此外如果有多个复用功能模块对应同一个引脚,只能使能其中之一,其它模块保持非使能状态。
———————————此处转载青渡QAQ关于GPIO模式于应用场合 ——————————— 原文链接:https://blog.csdn.net/weixin_48206270/article/details/123917776
二.标准库配置GPIO所需函数。
而想要使用一个gpio我们就得对其进行配置,由于常规的寄存器配置繁琐,我们在此使用库函数配置,这里我所采用的是基于标准库配置。
以下是标准库有关gpio的配置函数
其中以下几条代码是我们常用的最基础部分
/******GPIO外设初始化函数*******/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
/******GPIO外设读取函数*******/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/******GPIO外设设置函数*******/
//对选择引脚置高电平(设置所选引脚)
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//对选择引脚置低电平(清除所选引脚)
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//对所选引脚写0或者1(类似51的P0_1=0)
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
//对所选GPIO外设写字节(类似51的P0=0xff)
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
三.初始化GPIO。
知道了函数之后,我们就需要对其进行使用,如果你想使用一个引脚的话我们得需要进行以下操作。
1.开启我们所需要的外设时钟。
2.配置函数所需的外设结构体。
3.将结构体参数传入Init函数。
因为所有的外设都是挂载在时钟总线上的,所以我们操作外设之前都应先开启对应的时钟总线,所以gpio的结构如下图
所以想要使用GPIO外设我们需要如下代码:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA外设时钟
GPIO_InitTypeDef GPIO_InitStructure;//定义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);//初始化GPIOA
四.GPIO_InitTypeDef结构体含义。
对于这个结构体我们可以参考官方给出的源文件里的定义。
/*****结构体变量声明******/
typedef struct
{
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
1.其中GPIO_Pin需要的参数是GPIO_Pin_0~GPIO_Pin_All,这些参数其实对数据的宏定义。
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
2.GPIO_Speed参数是一个官方定义的枚举类型,这里我们默认采用50MHz。
/*****GPIO_Speed枚举参数******/
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
3.GPIO_Mode参数也是官方定义的枚举类型,就是我们最开始介绍的八种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_InitTypeDef结构体只需去官方声明处进行选择就可以实现功能了,至此有关GPIO基础部分就到此结束,上述有关素材来自学习江协科技STM32基础入门视频的个人理解