STM32-GPIO
介绍
什么是GPIO?
GPIO(通用输入/输出)是一种用于与外部设备进行数字通信的通用硬件接口。它允许微控制器或其他数字电路的引脚以灵活的方式配置为输入或输出,并在运行时进行动态控制。GPIO可用于连接和控制各种外围设备,如LED、按钮、传感器、显示器、通信设备等。
GPIO模式
GPIO引脚的工作可以配置为输入还是输出,以及其他相关的特性。STM32微控制器提供了多个寄存器来配置每个GPIO引脚的工作模式,包括MODER(模式寄存器)、OTYPER(输出类型寄存器)、OSPEEDR(输出速度寄存器)、PUPDR(上拉/下拉寄存器)等。
以STM32F407 为例,它的5 V 容忍 I/O 端口位的基本结构如下
以下是STM32的GPIO引脚的几种基本模式:
-
输入模式 (Input Mode):
- Analog Mode(模拟模式): 用于连接模拟传感器。
- Floating Input(浮空输入): 没有内部上拉或下拉电阻,需要外部电路提供电平。
- Pull-up / Pull-down(上拉/下拉输入): 配置内部上拉或下拉电阻,用于消除浮空输入的不确定性。
-
输出模式 (Output Mode):
- Push-Pull Output(推挽输出): 可以提供高电平和低电平输出。
- Open-Drain Output(开漏输出): 用于连接多个设备,需要外部上拉电阻来提供高电平。
- Push-Pull with Pull-up/Pull-down(推挽输出带上拉/下拉): 输出高电平或低电平时,同时配置上拉或下拉电阻。
常用API
在使用STM32的HAL库进行GPIO输入输出配置时,主要使用的API包括HAL_GPIO_Init
、HAL_GPIO_DeInit
、HAL_GPIO_WritePin
、HAL_GPIO_ReadPin
等。
-
HAL_GPIO_Init
函数:cHAL_StatusTypeDef HAL_GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_Init);
用于初始化指定的GPIO引脚。其中,
GPIOx
是指定的GPIO端口(如GPIOA
、GPIOB
等),GPIO_Init
是一个结构体,包含了GPIO引脚的配置信息(如模式、速度、上拉下拉等)。例如,将PA5配置为推挽输出:
cGPIO_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
函数:cvoid HAL_GPIO_DeInit(GPIO_TypeDef* GPIOx, uint32_t GPIO_Pin);
用于反初始化指定的GPIO引脚。其中,
GPIOx
是指定的GPIO端口,GPIO_Pin
是指定的GPIO引脚。例如,反初始化PA5引脚:
cHAL_GPIO_DeInit(GPIOA, GPIO_PIN_5);
-
HAL_GPIO_WritePin
函数:cvoid 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设置为高电平:
cHAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
-
HAL_GPIO_ReadPin
函数:cGPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
用于读取指定GPIO引脚的输入状态。其中,
GPIOx
是指定的GPIO端口,GPIO_Pin
是指定的GPIO引脚。例如,读取PA5引脚的状态:
cGPIO_PinState state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
项目实训
点亮一颗led
STM32F407芯片连接了一个LED到PA5引脚
cpp
#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);
}
按键控制LED亮灭
假设按键连接到PA0引脚,LED连接到PA5引脚
cpp
#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) {
// 程序错误时停在这里
}
}