02-GPIO输出.md 7.0 KB

02-GPIO输出

GPIO 基本结构

graph TD
    subgraph APB2_BUS
        APB2["APB2 (72MHz)"]
    end
    
    subgraph GPIO_REG
        CRL["CRL (配置低8位)"]
        CRH["CRH (配置高8位)"]
        IDR["IDR (输入数据)"]
        ODR["ODR (输出数据)"]
        BSRR["BSRR (位设置/复位)"]
        BRR["BRR (位复位)"]
        LCKR["LCKR (锁定)"]
    end
    
    APB2 --> GPIO_REG
    GPIO_REG --> GPIO_PIN

GPIO 位结构

graph LR
    subgraph PIN_STRUCT
        PAD["I/O Pad"] --> D1["保护二极管\nVDD"]
        PAD --> D2["保护二极管\nVSS"]
        D1 --> PULL_UP["上拉电阻\n(~40kΩ)"]
        D1 --> PULL_DOWN["下拉电阻\n(~40kΩ)"]
        PAD --> SCHMITT["施密特触发器"]
        SCHMITT --> INPUT_REG["输入数据寄存器<br/>(IDR)"]
        
        OUTPUT_REG["输出数据寄存器<br/>(ODR)"] --> DRIVER["输出驱动器"]
        DRIVER --> MUX["复用功能输出"]
        MUX --> PAD
        
        OUTPUT_REG --> BIT_SET["位设置/复位<br/>(BSRR)"]
        BIT_SET --> DRIVER
    end
组件 作用
保护二极管 钳位电压,防止 VDD+0.3V / VSS-0.3V 烧毁 IO
上拉/下拉电阻 约 30kΩ~50kΩ,固定空闲电平
施密特触发器 整形,防抖动,有滞后特性(VT+ ≈ 0.4VDD, VT- ≈ 0.3VDD)
输出驱动器 推挽(Push-Pull) 或 开漏(Open-Drain)
BSRR 原子操作,一次写同时设置和复位不同位

8种 GPIO 模式

模式 GPIO_Mode 结构特点 典型用途
模拟输入 GPIO_Mode_AIN 关闭施密特触发器,不接上/下拉 ADC 采样输入
浮空输入 GPIO_Mode_IN_FLOATING 施密特触发,无上下拉 外部信号按键(需外部上拉)
上拉输入 GPIO_Mode_IPU 施密特触发 + 上拉电阻 按键(GND导通)
下拉输入 GPIO_Mode_IPD 施密特触发 + 下拉电阻 按键(VCC导通)
推挽输出 GPIO_Mode_Out_PP PMOS+NMOS, 高低电平 LED, 蜂鸣器, 总线控制
开漏输出 GPIO_Mode_Out_OD 仅NMOS, 低=GND, 高=高阻 I2C SDA/SCL, 电平转换
复用推挽 GPIO_Mode_AF_PP 外设驱动推挽输出 USART TX, SPI SCK/MOSI
复用开漏 GPIO_Mode_AF_OD 外设驱动开漏输出 I2C(STM32做主控)

输出速度

速度宏 频率 适用场景
GPIO_Speed_2MHz 2MHz 低频,EMI 最小的通用 IO
GPIO_Speed_10MHz 10MHz 常规通信
GPIO_Speed_50MHz 50MHz SPI/高速 PWM

EMI 随速度增大而增大,不用高频时用 GPIO_Speed_2MHz 即可。

API 表格

RCC 时钟使能

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO 初始化

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
GPIO_InitTypeDef 成员 取值 说明
GPIO_Pin GPIO_Pin_0 ~ GPIO_Pin_15 引脚号,支持 OR 组合
GPIO_Speed GPIO_Speed_2MHz / 10MHz / 50MHz 输出速率
GPIO_Mode 见上方 8 种模式 IO 工作模式

输出控制函数

函数 原型 说明
GPIO_SetBits GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) 指定引脚输出高
GPIO_ResetBits GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) 指定引脚输出低
GPIO_WriteBit GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal) 按 BitVal 输出
GPIO_Write GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) 写整个 ODR
GPIO_SetBits 用 BSRR 实现,原子操作 推荐使用

完整代码示例

LED 流水灯 (PC13~PC10)

#include "stm32f10x.h"
#include "Delay.h"

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 开启 GPIOC 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    // PC13 - PC10 推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    // 初始全部熄灭 (板载 LED 低电平亮)
    GPIO_SetBits(GPIOC, GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11 | GPIO_Pin_10);
    
    Delay_Init();
    
    while (1)
    {
        GPIO_ResetBits(GPIOC, GPIO_Pin_13);     // PC13 亮
        Delay_ms(500);
        GPIO_SetBits(GPIOC, GPIO_Pin_13);
        
        GPIO_ResetBits(GPIOC, GPIO_Pin_12);     // PC12 亮
        Delay_ms(500);
        GPIO_SetBits(GPIOC, GPIO_Pin_12);
        
        GPIO_ResetBits(GPIOC, GPIO_Pin_11);     // PC11 亮
        Delay_ms(500);
        GPIO_SetBits(GPIOC, GPIO_Pin_11);
        
        GPIO_ResetBits(GPIOC, GPIO_Pin_10);     // PC10 亮
        Delay_ms(500);
        GPIO_SetBits(GPIOC, GPIO_Pin_10);
    }
}

蜂鸣器驱动 (PC9)

电路连接:PC9 → NPN (S8050) Base → 集电极接蜂鸣器负极 → 蜂鸣器正极接 3.3V。

#include "stm32f10x.h"
#include "Delay.h"

int main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    GPIO_ResetBits(GPIOC, GPIO_Pin_9);      // 关闭 (低电平截止)
    
    while (1)
    {
        // 有源蜂鸣器: 高电平导通发声
        GPIO_SetBits(GPIOC, GPIO_Pin_9);
        Delay_ms(500);
        GPIO_ResetBits(GPIOC, GPIO_Pin_9);
        Delay_ms(500);
    }
}

常用板载 LED 引脚

开发板 LED 引脚 电平
STM32F103C8T6 蓝色板 PC13 低电平亮
STM32F103C8T6 红板(Mini) PA1 高电平亮
STM32F103ZET6 正点原子 PD2 (DS0) / PG15 (DS1) 低电平亮
STM32F103VET6 野火 PB5 低电平亮

常见坑点/注意事项

  1. 外设时钟必须先开启 — 不开启时钟读写寄存器会 HardFault
  2. GPIO 速度与 EMI — 不需要高速时用 GPIO_Speed_2MHz,过高速度引入 EMI 且增加功耗
  3. 开漏输出高阻Out_OD 输出高电平必须加外部上拉电阻,否则读不到高电平
  4. BSRR vs ODR — 多线程/中断中修改位用 BSRR 是原子操作,ODR 非原子(读-改-写)
  5. GPIO_SetBits 底层用 BSRR — 比 GPIO_WriteBit(用 ODR)更安全
  6. IO 初始化时默认电平 — 推挽输出初始化后 ODR 复位值 0x0000,引脚默认低电平
  7. PC13 特殊 — 部分型号 PC13 驱动能力弱,LED 亮度可能不如其他引脚
  8. BSRR 写入高位 Hi 复位,低位 Lo 置位BSRR[31:16]=BRx 复位, BSRR[15:0]=BSx 置位