4. GPIO输出:点亮第一颗LED

点亮LED,是嵌入式开发者的"Hello World"。别看它简单,这里面藏着GPIO输出的核心逻辑。今天我们就用Rust Embedded HAL,把第一颗灯点亮。

4.1 从原理图到代码

拿到一块开发板,第一件事是什么?看原理图。你得知道LED接在哪个引脚上,是高电平点亮还是低电平点亮。

我习惯先画个简单的连接图:

LED 硬件连接示意 MCU GPIO Pin PA5 330Ω LED GND 说明:PA5 通过 330Ω 限流电阻驱动 LED,低电平点亮(共阳极接法) 如果 LED 另一端接 GND,则为高电平点亮(共阴极接法)

嗯,这里要注意:限流电阻不能省。我曾经见过新手直接把LED怼在引脚上,结果引脚驱动电流过大,芯片直接冒烟。330Ω到1kΩ是常用值。

4.2 OutputPin trait:GPIO输出的灵魂

在Rust Embedded HAL里,GPIO输出靠的是OutputPin这个trait。它定义了两个核心方法:

方法 行为 典型应用
set_high() 引脚输出高电平(VDD) 点亮LED、使能外设
set_low() 引脚输出低电平(GND) 熄灭LED、关闭外设
toggle() 翻转当前电平 闪烁LED、产生方波

说白了,你只需要调用这三个方法,就能控制引脚电平。但底层硬件怎么实现的?这就是推挽输出和开漏输出的区别了。

4.3 推挽输出 vs 开漏输出

这两个概念,我当年学的时候也绕了一阵。咱们用一张图说清楚:

推挽输出 vs 开漏输出 推挽输出 (Push-Pull) PMOS NMOS 输出 VDD GND 开漏输出 (Open-Drain) 上拉R NMOS 输出 VDD GND 推挽:PMOS+NMOS互补导通,能主动输出高低电平,驱动能力强 开漏:只有NMOS,只能拉低,高电平靠外部上拉电阻,适合多设备共用总线

核心区别一句话:

  • 推挽输出:既能灌电流也能拉电流,输出高低电平都干脆利落
  • 开漏输出:只能拉低,高电平靠外部上拉电阻,适合I²C等总线场景

4.4 实战:点亮LED

好,理论说完了,咱们直接上代码。以STM32F4系列为例,用stm32f4xx_hal库:

use stm32f4xx_hal::{
    pac,
    prelude::*,
    gpio::GpioExt,
};

fn main() -> ! {
    // 获取外设实例
    let dp = pac::Peripherals::take().unwrap();
    let cp = pac::CorePeripherals::take().unwrap();

    // 初始化时钟
    let rcc = dp.RCC.constrain();
    let clocks = rcc.cfgr.freeze();

    // 初始化GPIOA
    let gpioa = dp.GPIOA.split();
    
    // 配置PA5为推挽输出
    let mut led = gpioa.pa5.into_push_pull_output();

    // 主循环:闪烁LED
    loop {
        led.set_high().unwrap();   // 点亮
        delay(1000);
        led.set_low().unwrap();    // 熄灭
        delay(1000);
    }
}

fn delay(ms: u32) {
    // 简单的延时循环
    for _ in 0..ms * 8000 {
        cortex_m::asm::nop();
    }
}

这段代码里,into_push_pull_output()就是关键。它把引脚配置成推挽输出模式。你想想看,如果换成into_open_drain_output(),LED还能亮吗?能,但需要外部上拉电阻,而且高电平的上升沿会变慢。

我的习惯:

驱动LED、继电器这类需要明确高低电平的场景,一律用推挽输出。开漏输出我只在I²C总线、电平转换这类场景用。

4.5 避坑指南

做嵌入式这么多年,我在GPIO输出上踩过的坑,说出来都是泪:

  • 电流超限:我曾经直接把LED接在引脚上,没加限流电阻。结果LED倒是亮了,但引脚内部的驱动管烧了。后来查手册才知道,STM32单个引脚最大灌电流是25mA,但所有引脚总和不能超过120mA。
  • 模式选错:有次调试一个I²C设备,死活通信不上。查了半天,发现我把引脚配成了推挽输出。开漏输出才能实现线与逻辑,推挽输出会直接打架。
  • 初始化顺序:先配置时钟,再配置GPIO。这个顺序错了,引脚根本不会工作。

重要提醒:

开漏输出模式下,如果外部上拉电阻阻值太大,高电平的上升时间会变长。高速通信时(比如I²C的400kHz模式),上拉电阻一般选4.7kΩ左右。阻值太小又会导致灌电流过大。这是个平衡艺术。

4.6 推挽 vs 开漏:选型速查表

场景 推荐模式 原因
驱动LED 推挽输出 高低电平明确,驱动能力强
I²C总线 开漏输出 支持线与逻辑,多设备共用
驱动MOSFET栅极 推挽输出 需要快速充放电栅极电容
电平转换(3.3V→5V) 开漏输出+外部上拉到5V 输出电平由外部上拉决定
按键输入(输出模式) 推挽输出 输出固定电平驱动按键检测

嗯,到这里你应该对GPIO输出有了清晰的认识。推挽输出就像你的左右手,能推能拉;开漏输出就像一只手,只能往下拉,往上得靠别人帮忙。选对模式,你的嵌入式开发之路会顺畅很多。