GPIO(通用输入/输出)是一种用于与外部设备进行数字通信的通用硬件接口。它允许微控制器或其他数字电路的引脚以灵活的方式配置为输入或输出,并在运行时进行动态控制。GPIO可用于连接和控制各种外围设备,如LED、按钮、传感器、显示器、通信设备等。
GPIO引脚的工作可以配置为输入还是输出,以及其他相关的特性。STM32微控制器提供了多个寄存器来配置每个GPIO引脚的工作模式,包括MODER(模式寄存器)、OTYPER(输出类型寄存器)、OSPEEDR(输出速度寄存器)、PUPDR(上拉/下拉寄存器)等。
以STM32F407为例,它的5 V 容忍 I/O 端口位的基本结构如下
以下是STM32的GPIO引脚的几种基本模式:
输入模式 (Input Mode):
输出模式 (Output Mode):
在使用STM32的HAL库进行GPIO输入输出配置时,主要使用的API包括HAL_GPIO_Init
、HAL_GPIO_DeInit
、HAL_GPIO_WritePin
、HAL_GPIO_ReadPin
等。
HAL_GPIO_Init
函数:
HAL_StatusTypeDef HAL_GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_Init);
用于初始化指定的GPIO引脚。其中,GPIOx
是指定的GPIO端口(如GPIOA
、GPIOB
等),GPIO_Init
是一个结构体,包含了GPIO引脚的配置信息(如模式、速度、上拉下拉等)。
例如,将PA5配置为推挽输出:
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_DeInit
函数:
void HAL_GPIO_DeInit(GPIO_TypeDef* GPIOx, uint32_t GPIO_Pin);
用于反初始化指定的GPIO引脚。其中,GPIOx
是指定的GPIO端口,GPIO_Pin
是指定的GPIO引脚。
例如,反初始化PA5引脚:
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5);
HAL_GPIO_WritePin
函数:
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
用于设置指定的GPIO引脚的输出状态。其中,GPIOx
是指定的GPIO端口,GPIO_Pin
是指定的GPIO引脚,PinState
是要设置的状态(GPIO_PIN_SET
表示高电平,GPIO_PIN_RESET
表示低电平)。
例如,将PA5设置为高电平:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_GPIO_ReadPin
函数:
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
用于读取指定GPIO引脚的输入状态。其中,GPIOx
是指定的GPIO端口,GPIO_Pin
是指定的GPIO引脚。
例如,读取PA5引脚的状态:
GPIO_PinState state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
STM32F407芯片连接了一个LED到PA5引脚
#include "stm32f4xx_hal.h"
void SystemClock_Config(void);
static void GPIO_Init(void);
int main(void) {
// 初始化HAL库
HAL_Init();
// 配置系统时钟
SystemClock_Config();
// 初始化GPIO
GPIO_Init();
while (1) {
// 点亮LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
// 延时
HAL_Delay(1000);
// 关闭LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
// 延时
HAL_Delay(1000);
}
}
// 系统时钟配置函数,使用HAL库的CubeMX生成的代码
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
Error_Handler();
}
}
// GPIO初始化函数
static void GPIO_Init(void) {
// 启用GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// 初始化PA5引脚为推挽输出
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化引脚状态为低电平
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
假设按键连接到PA0引脚,LED连接到PA5引脚
#include "stm32f4xx_hal.h"
void SystemClock_Config(void);
static void GPIO_Init(void);
int main(void) {
// 初始化HAL库
HAL_Init();
// 配置系统时钟
SystemClock_Config();
// 初始化GPIO
GPIO_Init();
while (1) {
// 读取按键状态
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
// 按键按下,点亮LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
} else {
// 按键未按下,关闭LED
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
}
}
// 系统时钟配置函数,使用HAL库的CubeMX生成的代码
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
Error_Handler();
}
}
// GPIO初始化函数
static void GPIO_Init(void) {
// 启用GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// 初始化PA0引脚为上拉输入(按键连接到地,按下时引脚电平为低)
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化PA5引脚为推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化引脚状态为低电平
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
// 错误处理函数
void Error_Handler(void) {
while (1) {
// 程序错误时停在这里
}
}