目录
复用功能推挽/开漏输出( Alternate Function, AF)
按键:输入 LED:输出
【GPIO输入模式详解】
输入浮空(GPIO_Mode_IN_FLOATING)
输入引脚即不接高电平,也不接低电平,用于标准的通讯协议,比如IIC、USART的等,如果想用做按键检测等功能,需外部使用上拉或下拉电阻
输入上拉(GPIO_Mode_IPU)
相当于输入浮空用来按键检测外加上拉电阻,只不过这个是内部上拉,省去了外部电路
输入下拉(GPIO_Mode_IPD)
相当于输入浮空用来按键检测外加下拉电阻,只不过这个是内部下拉,省去了外部电路
模拟输入(GPIO_Mode_AIN)
信号进入后不经过上拉电阻或者下拉电阻,关闭施密特触发器,经由另一线路把电压信号传送到片上外设模块。比如传送给ADC模块,由ADC采集电压信号。所以可以理解为模拟输入的信号是未经处理的信号
读管脚上的信息时,设置为输入上拉(GPIO_Mode_IPU)
【GPIO输出模式详解】
STM32的GPIO有8种输入输出模式:
4种输入:上拉输入、下拉输入、浮空输入、模拟输入
4种输出:开漏输出、推挽输出、开漏复用输出、推挽复用输出
推挽输出(Push Pull Output,PP)
推挽输出的结构是由两个三极管或者MOS管受到互补信号的控制,两个管子始终保持一个处于截止,另一个处于导通的状态。
推挽输出的最大特点是可以真正能真正的输出高电平和低电平,在两种电平下都具有驱动能力,可以输出强高低电平
开漏输出(Open Drain Output,OD)
开漏输出无法真正输出高电平,即高电平没有驱动能力,需借助外部上拉电阻完成对外驱动
因为输出电平完全由上拉电阻连接的电源电平决定。所以常用在需要进行电平转换的地方
复用功能推挽/开漏输出( Alternate Function, AF)
GPIO引脚除了作为通用输入/输出引脚使用外,还可以作为片上外设( USART、 I2C、 SPI等)专用引脚,即一个引脚可以有多种用途,但同一时刻一个引脚只能使用复用功能中的一个。
当引脚设置为复用功能时,可选择复用推挽输出模式或复用开漏输出模式,在设置为复用开漏输出模式时,需要外接上拉电阻
【GPIO常用函数】
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
功能: GPIO初始化
实例:HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
功能:读取引脚的电平状态、函数返回值为0或1
实例:HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
功能:引脚写0或1 、 GPIO_PIN_RESET 或 GPIO_PIN_SET
实例:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4,0);
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
翻转引脚的电平状态
实例:HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_4); 常用在LED上
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
功能: 中断回调函数,可以理解为中断函数具体要响应的动作。
实例:HAL_GPIO_EXTI_Callback(GPIO_PIN_4);
// 结构体 GPIO_InitTypeDef 定义
typedef struct
{
uint32_t Pin;
uint32_t Mode;
uint32_t Pull;
uint32_t Speed;
} GPIO_InitTypeDef;
【STM32CubeMx GPIO配置】
1)GPIO output level:只有当引脚设置为“GPIO_Output”时才需要设置
High:GPIO输出初始化为高电平
Low:GPIO输出初始化为低电平
2)GPIO mode
Output Push Pull:推挽输出,能输出高低电平,且高低电平都有驱动能力,对应标准库函数中的“GPIO_Mode_Out_PP”
Output Open Drain:开漏输出,只能输出低电平,需要借助外部上拉电阻才能输出高电平,对应标准库函数中的“GPIO_Mode_Out_OD”
Analog mode:模拟输入,ADC采样信号输入引脚的配置模式,对应标准库函数中的“GPIO_Mode_AIN”
Alternate Function Push Pull:推挽式复用功能,对应标准库函数中的“GPIO_Mode_AF_PP”
Input mode:输入模式,配合No pull-up/pull-down可形成GPIO_Mpde_IN_FLOATING、GPIO_Mode_IPD、GPIO_Mode_IPU等不同工作模式
3)GPIO Pull-up/Pul-down
No pull-up/pull-down:无内部上拉或下拉
Pull-up:内部上拉,默认高电平
Pull-down:内部下拉,默认低电平
4)Maximum output speed
Low:低速,对应标准库函数中的“GPIO_Speed_2MHz”
Medium:中速,对应标准库函数中的“GPIO_Speed_10MHz”
High:高速,对应标准库函数中的“GPIO_Speed_50MHz”
5)User Label:用户标签,可以按照需要给引脚命名
【demo · GPIO点灯】
关于.h的引用问题:
● main.h中引入stm32f1xx_hal.h(CubeMx会自动生成)
● main.c中引入用户所有自建的.h文件
● 每个用户自建的.h文件仅需引用main.h
● 用户自建.c文件引用对应自身的.h
● 用户自建.c文件中所有函数都应该在对应.h文件中声明
● 共享变量定义在.c中,并在对应的.h中使用extern声明(extern时不可赋值)
共享的宏定义一般直接定义在.h中
需要引用该共享变量的.c文件需引用该.h文件
● 若在.c中需要用另一个.c的函数,可使用extern声明,或在.c中引用目标.c文件的.h文件
如:在a.c中需要用b.c的函数led(),则a.c中写入:#include<b.h>
或者:在a.c前面声明extern void led(); 后面再调用led()
● 若在.c中需要用另一个.c的变量(定义在.c中而不是.h),可使用extern声明
如:在a.c中需要用b.c的变量int m,则在a.c前面声明extern int m; 后面再使用m
/* main.h */
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f1xx_hal.h"
#define LED_Pin GPIO_PIN_13
#define LED_GPIO_Port GPIOC
#define KEY_Pin GPIO_PIN_1
#define KEY_GPIO_Port GPIOA
#define KEY_OFF 0
#define KEY_ON 1
#endif /* __MAIN_H */
/* key.h */
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"
uint8_t key(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
#endif /*__ KEY_H__ */
/* led.h */
#ifndef __LED_H__
#define __LED_H__
#include "main.h"
void led(uint8_t KEY_FLAG);
#endif /*__ LED_H__ */
/* key.c */
#include "key.h"
uint8_t key(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
uint8_t KEY_FLAG = KEY_OFF;
if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin)==GPIO_PIN_RESET) //判断KEY引脚是否为低电平
{
HAL_Delay(20); //延时20ms
}
if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin)==GPIO_PIN_RESET) //再次判断KEY引脚是否为低电平
{
KEY_FLAG = KEY_ON;
}
while(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin)==GPIO_PIN_RESET); //等待按键松开
return KEY_FLAG;
}
/* led.c */
#include "led.h"
void led(uint8_t KEY_FLAG)
{
if(KEY_FLAG == KEY_ON)
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}
/* main.c */
#include "main.h"
#include "gpio.h"
#include "key.h"
#include "led.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
if(key(KEY_GPIO_Port,KEY_Pin)==KEY_ON) led(KEY_ON);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
扩展说明:
① 按键模块可以直接替换为振动模块、触摸模块等(本质和按键一样,都是人为施加信号时,模块信号引脚输出低电平),程序中仅需根据实际情况调整消抖的延迟时间
② LED可替换为继电器模块,下图所用的继电器规格为DC 5V,Low level trigger
注意:JQC继电器需要开漏模式(若发现继电器不能正常动作,切换一下开漏/推挽模式试试)
继电器:
继电器上二极管的作用:续流
【工程师必备】为什么继电器需要反向并联一个二极管_哔哩哔哩_bilibili