STM32 CubeIDE(四) GPIO标准通用输入/输出端口
STM32 GPIO
GPIO是标准通用输入/输出端口的简称,是STM32可控制的引脚。GPIO的引脚与外部硬件设备连接,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。
STM32F407ZGT6是LQFP144封装的芯片,共有144个引脚,共有140个标准通用输入/输出端口(GPIO),包括7个标准通用输入/输出端口(GPIO)组,分别为GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOG,通常简略称为PAx、PBx、PCx、PDx、PEx、PFx、PGx,其中x为0-15。STM32的大部分引脚除了当GPIO使用之外,还可以复用位外设功能引脚,这部分在后面具体用到某个模块时再做介绍。
根据数据手册中列出的每个 I/O 端口的特性,可通过软件将GPIO端口的各个端口位分别配置为多种模式:
● GPIO_MODE_INPUT,输入模式
● GPIO_MODE_ANALOG, 模拟输入
● GPIO_MODE_OUTPUT_OD,开漏输出
● GPIO_MODE_OUTPUT_PP,推挽输出
● GPIO_MODE_AF_PP,复用功能推挽
● GPIO_MODE_AF_OD,复用功能开漏
也可以对每个IO进行上拉电阻或者下拉电阻操作:
● GPIO_NOPULL,浮空电阻
● GPIO_PULLUP,上拉电阻
● GPIO_PULLDOWN,下拉电阻
同时,GPIO还支持四种最大翻转速度:
● GPIO_SPEED_FREQ_LOW,2MHz
● GPIO_SPEED_FREQ_MEDIUM,25MHz
● GPIO_SPEED_FREQ_HIGH,50MHz
● GPIO_SPEED_FREQ_VERY_HIGH,100MHz
在STM32中一般如何选择GPIO工作模式?
● 浮空输入,用于检测标准信号输入,例如按键识别
● 模拟输入,用于ADC的输入
● 推挽输出,用于标准高低电平输出
● 开漏输出,用于实现“线与”逻辑
● 复用推挽,用于片内外设
● 复用开漏,用于片内外设
STM32 GPIO实验
本次实验基于野火STM32F407-霸天虎V2开发板实现,使用按键控制RGBLED的状态,涉及GPIO的推挽输出与浮空输入两种模式,并以此介绍基于CubeMX环境下,使用HAL库对GPIO进行配置的方法。
HAL库对于GPIO的结构体定义如下:
typedef struct
{
uint32_t Pin; /* 引脚,GPIO_Pin_0~15 */
uint32_t Mode; /* GPIO模式 */
uint32_t Pull; /* GPIO上/下拉电阻 */
uint32_t Speed; /* GPIO翻转速度 */
uint32_t Alternate; /* GPIO复用功能引脚映射 */
}GPIO_InitTypeDef;
HAL库对于GPIO的操作基本函数如下:
/**
* @brief GPIO初始化
* @param 具体的端口,引脚
* @arg GPIOx:GPIOA~G
* @arg GPIO_Init: GPIO结构体
*/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
/**
* @brief 在GPIO初始化之后的引脚恢复成默认的状态,即各个寄存器复位时的值
* @param 具体的端口,引脚
* @arg GPIOx:GPIOA~G
* @arg GPIO_PIN: GPIO_PIN_0~15
*/
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
/**
* @brief 读取引脚的电平状态、函数返回值为0或1
* @param 具体的端口,引脚
* @arg GPIOx:GPIOA~G
* @arg GPIO_PIN: GPIO_PIN_0~15
* @retval 返回值
* @arg 1:高电平返回1
* @arg 0:低电平返回0
*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/**
* @brief GPIO引脚输出电平
* @param 具体的端口,引脚,输出电平状态
* @arg GPIOx:GPIOA~G
* @arg GPIO_PIN: GPIO_PIN_0~15
* @arg PinState:GPIO_PIN_SET高电平,GPIO_PIN_RESET低电平
*/
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
/**
* @brief GPIO引脚电平翻转
* @param 具体的端口,引脚
* @arg GPIOx:GPIOA~G
* @arg GPIO_PIN: GPIO_PIN_0~15
*/
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/**
* @brief GPIO引脚当前电平锁定
* @param 具体的端口,引脚
* @arg GPIOx:GPIOA~G
* @arg GPIO_PIN: GPIO_PIN_0~15
*/
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
由开发板原理图可知,RGBLED对应PF6、PF7、PF8,低电平点亮;按键KEY1对应PA0,按下为低电平。因此我们新建一个工程,对如下IO进行配置,每个IO都有如下参数:
GPIO outp level:初始化后IO的输出电平,选择High高电平
GPIO mode:初始化后IO的工作模式,选择Output Push Pull推挽输出
GPIO Pull-up/Pull-down:初始化后IO上下拉电阻使能,选择No浮空
Maximum output speed:初始化后IO的翻转速度,选择Low 2MHz
User Label:用户标签,配置为KEY1、LED_Red、LED_Green、LED_Blue
设置完成后点击Device Configuration Tool Code Generation
自动生成代码。
打开main.h头文件,在相应位置添加/修改为如下内容:
/* USER CODE BEGIN EFP */
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define LED_Red_Pin GPIO_PIN_6
#define LED_Red_GPIO_Port GPIOF
#define LED_Green_Pin GPIO_PIN_7
#define LED_Green_GPIO_Port GPIOF
#define LED_Blue_Pin GPIO_PIN_8
#define LED_Blue_GPIO_Port GPIOF
#define KEY1_Pin GPIO_PIN_0
#define KEY1_GPIO_Port GPIOA
/* USER CODE BEGIN Private defines */
#define LED_Red_OFF HAL_GPIO_WritePin(LED_Red_GPIO_Port,LED_Red_Pin,GPIO_PIN_SET);
#define LED_Red_ON HAL_GPIO_WritePin(LED_Red_GPIO_Port,LED_Red_Pin,GPIO_PIN_RESET);
#define LED_Green_OFF HAL_GPIO_WritePin(LED_Green_GPIO_Port,LED_Green_Pin,GPIO_PIN_SET);
#define LED_Green_ON HAL_GPIO_WritePin(LED_Green_GPIO_Port,LED_Green_Pin,GPIO_PIN_RESET);
#define LED_Blue_OFF HAL_GPIO_WritePin(LED_Blue_GPIO_Port,LED_Blue_Pin,GPIO_PIN_SET);
#define LED_Blue_ON HAL_GPIO_WritePin(LED_Blue_GPIO_Port,LED_Blue_Pin,GPIO_PIN_RESET);
#define KEY_Touch 1
#define KEY_NOTouch 0
/* USER CODE END Private defines */
打开main.c头文件,在相应位置添加/修改为如下内容:
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t LED_Flag = 0;
/* USER CODE END PV */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(Key_Scan(KEY1_GPIO_Port,KEY1_Pin) == KEY_Touch)
LED_Flag++;
switch(LED_Flag)
{
case 0:LED_Red_OFF;LED_Green_OFF;LED_Blue_OFF;break;
case 1:LED_Red_ON;LED_Green_OFF;LED_Blue_OFF;break;
case 2:LED_Red_OFF;LED_Green_ON;LED_Blue_OFF;break;
case 3:LED_Red_OFF;LED_Green_OFF;LED_Blue_ON;break;
case 4:LED_Red_ON;LED_Green_ON;LED_Blue_OFF;break;
case 5:LED_Red_ON;LED_Green_OFF;LED_Blue_ON;break;
case 6:LED_Red_OFF;LED_Green_ON;LED_Blue_ON;break;
case 7:LED_Red_ON;LED_Green_ON;LED_Blue_ON;break;
case 8:LED_Flag=0;break;
}
HAL_Delay(30);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
/**
* @brief 检测是否有按键按下
* @param 具体的端口和端口位
* @arg GPIOx: x可以是(A...G)
* @arg GPIO_PIN 可以是GPIO_PIN_x(x可以是0...15)
* @retval 按键的状态
* @arg KEY_Touch:按键按下
* @arg KEY_NOTouch:按键没按下
*/
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/*检测是否有按键按下 */
if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == KEY_Touch )
{
/*等待按键释放 */
while(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin) == KEY_Touch);
return KEY_Touch;
}
else
return KEY_NOTouch;
}
/* USER CODE END 4 */