第3章:GPIO基础——从模式到实战,点亮你的第一颗LED

各位同学,欢迎来到第三章。前面我们聊了STM32的整体架构和开发环境搭建,今天终于要动手了。这一章我们聚焦GPIO——说白了,就是芯片上那些可以编程控制的引脚。你想想看,一个单片机要跟外界打交道,靠的就是这些引脚。GPIO是基础中的基础,但也是坑最多的地方之一。

3.1 GPIO模式详解:别小看这几种配置

STM32的GPIO模式,比你想的要复杂。我刚开始用的时候,以为就是简单的输入输出。结果第一次做项目,就因为模式选错,折腾了一整天。嗯,这里我给大家梳理一下。

3.1.1 输出模式

  • 推挽输出(Push-Pull):最常用的输出模式。可以输出高电平或低电平,驱动能力较强。我个人习惯,驱动LED、蜂鸣器这类外设,首选推挽。
  • 开漏输出(Open-Drain):只能输出低电平,高电平要靠外部上拉电阻。I2C总线就是典型应用。我在项目中遇到过,如果忘了加上拉电阻,总线死活拉不高。

3.1.2 输入模式

  • 浮空输入:引脚电平完全由外部决定,内部没有上下拉。这种模式容易受干扰,我一般不用。
  • 上拉/下拉输入:内部有弱上拉或弱下拉电阻。读取按键时,我习惯用上拉输入,按键按下就是低电平,逻辑清晰。

3.1.3 复用功能与模拟模式

复用功能,就是把引脚交给片上外设(比如USART、SPI)去控制。模拟模式则用于ADC采集。这两种模式,说白了就是GPIO模块退居二线,让专业的人干专业的事。

核心要点:配置GPIO时,先想清楚你要干什么。输出?输入?还是交给外设?选错了,轻则功能异常,重则烧坏引脚。

3.2 核心API:HAL_GPIO_WritePin与HAL_GPIO_ReadPin

HAL库封装好了两个最常用的函数。我刚开始学的时候,觉得这俩函数太简单了,后来才发现,用得好不好,直接关系到代码的健壮性。

3.2.1 HAL_GPIO_WritePin

void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

参数说明:

  • GPIOx:GPIO组,比如GPIOA、GPIOB
  • GPIO_Pin:引脚编号,比如GPIO_PIN_0
  • PinState:电平状态,GPIO_PIN_SET(高)或GPIO_PIN_RESET(低)

举个例子,点亮LED就是:

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);  // PB0输出高电平

我的小技巧:不要直接用数字0或1来赋值,一定要用GPIO_PIN_SET和GPIO_PIN_RESET。这样代码可读性高,别人一看就懂。

3.2.2 HAL_GPIO_ReadPin

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

这个函数返回引脚当前的电平状态。读取按键时常用:

if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
    // 按键被按下(假设是上拉输入)
}

我曾经踩过的坑:读取引脚前,一定要确认GPIO模式配置正确。有一次我配置成了输出模式,然后去读引脚电平,结果读回来的值完全不对。折腾了半天才发现是模式搞错了。

3.3 点亮LED实战:从原理到代码

好了,理论知识讲完了,我们来动手。点亮LED,是嵌入式开发的"Hello World"。我当年第一次点亮LED时,那种成就感至今难忘。

3.3.1 硬件连接

假设我们使用STM32F103C8T6最小系统板,LED正极通过一个220Ω电阻连接到PB0,负极接地。为什么加电阻?限流,防止烧坏LED和引脚。

3.3.2 代码实现

第一步,配置GPIO。在STM32CubeMX中,将PB0设置为推挽输出模式,速度选Low(低速就够用)。然后生成代码。

第二步,在主循环中控制LED:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();  // 初始化GPIO

    while (1)
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);   // 点亮
        HAL_Delay(500);                                        // 延时500ms
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 熄灭
        HAL_Delay(500);                                        // 延时500ms
    }
}

就这么简单。下载到板子上,你应该能看到LED以1秒的周期闪烁。

注意:HAL_Delay依赖于SysTick中断。如果你的代码中关闭了全局中断,延时就会失效。我在一个项目中就因为这个原因,LED死活不闪,排查了好久才发现是中断被关了。

3.4 知识体系总览

下面这张图,是我自己画的GPIO知识体系。你把它记在脑子里,以后用GPIO就不会乱了。

GPIO基础 GPIO模式 • 推挽输出 • 开漏输出 • 上拉/下拉输入 • 浮空输入 • 复用功能 • 模拟模式 核心API • HAL_GPIO_WritePin • HAL_GPIO_ReadPin • HAL_GPIO_TogglePin 点亮LED实战 • 硬件连接 • CubeMX配置 • 代码编写 • 下载验证 掌握GPIO = 掌握STM32与外界的沟通方式

3.5 避坑指南与个人经验

最后,分享几个我这些年积累的经验:

  1. 配置完GPIO后,先测量引脚电平。用万用表测一下,确认输出对不对。我曾经因为焊接问题,引脚虚焊,程序怎么调都没用。
  2. 注意引脚耐压。STM32的GPIO耐压一般是3.3V,别直接接5V。我在一个项目中,客户要求接5V传感器,结果忘了加电平转换,烧了两个引脚。
  3. 调试时多用HAL_GPIO_TogglePin。这个函数可以翻转引脚电平,用来做调试指示非常方便。比如在某个关键代码段前后翻转一个引脚,用示波器一看就知道执行时间。
  4. 不要迷信默认配置。每次新建工程,我都会手动检查一遍GPIO配置。CubeMX生成的代码有时候会遗漏某些设置,尤其是复用功能。

我的习惯:每个GPIO引脚,我都会在代码注释里写明用途。比如 // PB0 - LED指示灯,低电平点亮。这样过几个月回头看代码,不用重新翻原理图。

好了,这一章就到这里。GPIO看似简单,但它是所有外设驱动的基础。你把它吃透了,后面学USART、I2C、SPI都会轻松很多。动手试试吧,把LED点亮的那一刻,你会爱上这种感觉的。


专注资料整理