GPIO基本概念

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配置

  1. 选择引脚

    • 在芯片引脚图上点击要使用的引脚

    • 选择GPIO_Output或GPIO_Input

  2. 配置参数

    • GPIO mode:输出模式

    • GPIO Pull-up/Pull-down:上下拉

    • Maximum output speed:输出速度

    • User Label:用户标签

  3. 生成代码

    • 点击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为高电平 */
}

练习题

  1. 实现一个按键控制两个LED的程序:

    • 短按:LED1翻转

    • 长按(>2s):LED2翻转

  2. 使用4个LED实现二进制计数器(0-15)

  3. 实现呼吸灯效果(使用延时模拟PWM)

  4. 设计一个简单的密码锁:

    • 使用4个按键输入密码

    • 正确密码点亮LED

相关推荐
不悔哥3 天前
开源OV-Watch:怎么做一个智能手表
单片机·开源·嵌入式
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
深圳老胡3 天前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
女神下凡3 天前
嵌入式设计的各种存储芯片的硬件/软件设计规范,非常全面。
arm开发·单片机·嵌入式硬件
梅梅9663 天前
一款mipi转lvds的lcd调试(LT8912B)
单片机·计算机外设·电脑·显示器·pd芯片
开发笔记-阿牛3 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
从零开始的嵌入式之旅3 天前
day47
arm开发·经验分享·笔记·嵌入式硬件
恒锐丰科技林技术员3 天前
EG1164 高压大电流升压同步整流芯片解析
经验分享·嵌入式硬件·硬件工程
CHENKONG_CK3 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
祖力553 天前
ARM时钟
嵌入式硬件·arm·时钟·imx6ull