GPIO(General Purpose Input Output)通用输入输出端口,是STM32与外部世界交互的基本接口。
GPIO主要功能
-
输入模式:读取外部信号(按键、传感器)
-
输出模式:控制外部设备(LED、继电器)
-
复用功能:UART、SPI、I2C等外设
-
模拟功能:ADC输入
GPIO结构框图
┌─────────────────────────────────┐
│ GPIO │
│ │
输入 ───┤ ┌───┐ ┌────┐ ┌────┐ ├───► 输入数据寄存器
│ │保护│───►│上拉│───►│施密│ │ (IDR)
│ │二极│ │下拉│ │特触│ │
│ │管 │ │电阻│ │发器│ │
│ └───┘ └────┘ └────┘ │
│ │
输出 ───┤ ┌────┐ ┌────┐ ┌────┐ │
│ │输出│───►│推挽│───►│I/O │────┼───► 引脚
控制 ───┤ │数据│ │/开 │ │引脚│ │
│ │寄存│ │漏 │ │ │ │
│ │器 │ │ │ │ │ │
│ └────┘ └────┘ └────┘ │
│ │
└─────────────────────────────────┘
GPIO工作模式
8种工作模式
| 模式 | 说明 | 典型应用 |
|---|---|---|
| 浮空输入 | 无上下拉 | 外部按键 |
| 上拉输入 | 内部上拉电阻 | 按键检测 |
| 下拉输入 | 内部下拉电阻 | 按键检测 |
| 模拟输入 | ADC输入 | 电压采集 |
| 开漏输出 | 无驱动能力,需外接上拉 | I2C通信 |
| 开漏复用 | 复用功能开漏 | I2C SDA |
| 推挽输出 | 有驱动能力 | LED控制 |
| 推挽复用 | 复用功能推挽 | UART TX |
输出类型
推挽输出
-
可以输出高电平(VDD)和低电平(VSS)
-
驱动能力强
-
适用于LED、继电器等
开漏输出
-
只能输出低电平或高阻态
-
需要外接上拉电阻
-
适用于I2C、电平转换
GPIO配置步骤
使用HAL库配置
/* 1. 开启GPIO时钟 */
__HAL_RCC_GPIOC_CLK_ENABLE();
/* 2. 配置GPIO参数 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_13; // 引脚号
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 输出速度
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* 3. 控制GPIO输出 */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // 高电平
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // 低电平
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转
使用CubeMX配置
-
选择引脚
-
在芯片引脚图上点击要使用的引脚
-
选择GPIO_Output或GPIO_Input
-
-
配置参数
-
GPIO mode:输出模式
-
GPIO Pull-up/Pull-down:上下拉
-
Maximum output speed:输出速度
-
User Label:用户标签
-
-
生成代码
-
点击Generate Code
-
在main.c中查看初始化代码
-
实例1:LED控制
硬件连接
STM32 PC13 ─── LED ─── 330Ω ─── GND
代码实现
/* main.c */
#include "main.h"
#define LED_PIN GPIO_PIN_13
#define LED_PORT GPIOC
/* LED初始化 */
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 开启GPIOC时钟 */
__HAL_RCC_GPIOC_CLK_ENABLE();
/* 配置LED引脚 */
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
/* 默认熄灭 */
HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET);
}
/* LED控制函数 */
void LED_On(void)
{
HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET);
}
void LED_Off(void)
{
HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET);
}
void LED_Toggle(void)
{
HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
while (1)
{
LED_Toggle();
HAL_Delay(500);
}
}
实例2:按键检测
硬件连接
方法1:外部下拉
STM32 PA0 ─── 按键 ─── 3.3V
│
10kΩ
│
GND
方法2:内部上拉(推荐)
STM32 PA0 ─── 按键 ─── GND
(使用内部上拉电阻)
代码实现
/* main.c */
#include "main.h"
#define KEY_PIN GPIO_PIN_0
#define KEY_PORT GPIOA
#define LED_PIN GPIO_PIN_13
#define LED_PORT GPIOC
/* 按键初始化 */
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 开启GPIOA时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* 配置按键引脚 - 上拉输入 */
GPIO_InitStruct.Pin = KEY_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; /* 内部上拉 */
HAL_GPIO_Init(KEY_PORT, &GPIO_InitStruct);
}
/* 按键扫描(带消抖) */
uint8_t KEY_Scan(void)
{
static uint8_t key_flag = 0; /* 按键按下标志 */
/* 检测按键按下(低电平有效) */
if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == GPIO_PIN_RESET)
{
HAL_Delay(10); /* 消抖延时 */
if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == GPIO_PIN_RESET)
{
if (key_flag == 0)
{
key_flag = 1;
return 1; /* 返回按键按下 */
}
}
}
else
{
key_flag = 0; /* 按键释放 */
}
return 0; /* 无按键按下 */
}
int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
KEY_Init();
while (1)
{
if (KEY_Scan())
{
LED_Toggle(); /* 按键按下,LED翻转 */
}
}
}
按键消抖原理
按键按下时的抖动波形:
┌──┐ ┌┐ ┌─┐
────┘ └──┘└─┘ └────
↑
抖动区域(5-20ms)
解决方法:
1. 硬件消抖:RC滤波电路
2. 软件消抖:延时检测
实例3:多位LED控制
硬件连接
STM32 PC0-PC7 ─── 8个LED ─── 330Ω ─── GND
代码实现
/* 流水灯效果 */
void LED_Flow(void)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
/* 清除所有LED */
GPIOC->ODR &= 0xFF00;
/* 点亮当前LED */
GPIOC->ODR |= (1 << i);
HAL_Delay(200);
}
}
/* 跑马灯效果 */
void LED_HorseRace(void)
{
static uint8_t pos = 0;
GPIOC->ODR &= 0xFF00;
GPIOC->ODR |= (1 << pos);
pos = (pos + 1) % 8;
HAL_Delay(100);
}
GPIO寄存器详解
主要寄存器
| 寄存器 | 名称 | 功能 |
|---|---|---|
| CRL | 配置寄存器低 | 配置PIN0-PIN7 |
| CRH | 配置寄存器高 | 配置PIN8-PIN15 |
| IDR | 输入数据寄存器 | 读取输入状态 |
| ODR | 输出数据寄存器 | 设置输出状态 |
| BSRR | 置位/复位寄存器 | 快速设置/清除 |
| BRR | 复位寄存器 | 快速清除 |
直接操作寄存器
/* 设置PA5为高电平 */
GPIOA->BSRR = GPIO_PIN_5;
/* 设置PA5为低电平 */
GPIOA->BRR = GPIO_PIN_5;
/* 或 */
GPIOA->BSRR = (uint32_t)GPIO_PIN_5 << 16;
/* 读取PA5状态 */
if (GPIOA->IDR & GPIO_PIN_5)
{
/* PA5为高电平 */
}
练习题
-
实现一个按键控制两个LED的程序:
-
短按:LED1翻转
-
长按(>2s):LED2翻转
-
-
使用4个LED实现二进制计数器(0-15)
-
实现呼吸灯效果(使用延时模拟PWM)
-
设计一个简单的密码锁:
-
使用4个按键输入密码
-
正确密码点亮LED
-