Skip to content

输入输出模式

输入模式 (Input)

1. GPIO_Mode_AIN (Analog In - 模拟输入)

  • 用途: ADC 专用。
  • 原理: 此时 GPIO 的数字电路全部断开,引脚直接连到内部的 ADC 模块。
  • 类比: Stream 流。不处理数据,直接管道传输。

2. GPIO_Mode_IN_FLOATING (Floating In - 浮空输入)

  • 用途: 串口接收 (RX) 或 I2C 数据线。
  • 原理: 上下都不接电阻,电压完全由外部电路决定。
  • 类比: 没有任何默认值的变量 let a;。

3. GPIO_Mode_IPD (Input Pull-Down - 下拉输入)

  • 用途: 外部设备接高电平时用。
  • 原理: 内部接个电阻到 GND。
  • 类比: function(a = false)

4. GPIO_Mode_IPU (Input Pull-Up - 上拉输入)

  • 用途: 外部设备接低电平时用(比如按钮)。
  • 原理: 内部接个电阻到 3.3V。
  • 类比: function(a = true)

输出模式 (Output)

输出模式是初学者最容易晕的地方。你只需要把它看作 “控制权” 和 “电路结构” 的排列组合。

组合维度

  • 维度 A:谁来控制引脚?

    • 通用 (General): CPU 写代码 (GPIO_SetBits) 控制 \rightarrow 手动挡。复用 (Alternate
    • Function - AF): 片上外设 (串口、I2C、PWM) 自动控制 \rightarrow 自动挡。
  • 维度 B:电路性格是啥?

    • 推挽 (Push-Pull): 强硬 (0/1)。
    • 开漏 (Open-Drain): 软弱 (0/悬空)。

1. GPIO_Mode_Out_PP (通用推挽输出) —— 最常用

  • 组合: 手动挡 + 强硬。
  • 场景: 点灯、继电器、蜂鸣器。CPU 说亮就亮,说灭就灭。

2. GPIO_Mode_Out_OD (通用开漏输出) —— 较少用

  • 组合: 手动挡 + 软弱。
  • 场景: 软件模拟 I2C。或者是你希望输出 5V(外部接上拉电阻到 5V),但 CPU 只能出 3.3V 时。

3. GPIO_Mode_AF_PP (复用推挽输出) —— 常用

  • 组合: 自动挡 + 强硬。
  • 场景: 串口发送 (TX)、PWM 输出、SPI。
  • 解释: 你把控制权交给了“串口控制器”,它内部也是数字电路,也需要强电平来传输信号,所以是 PP。

4. GPIO_Mode_AF_OD (复用开漏输出)

  • 组合: 自动挡 + 软弱。
  • 场景: 硬件 I2C。
  • 解释: I2C 协议要求总线必须是“开漏”的(防止短路),同时你又想用 STM32 内部的“I2C 硬件控制器”来自动发波形,所以必须选这个模式。

总结图表

序号宏定义中 文 名核心逻辑 (谁控制 + 怎么输出)典型场景
1AIN模拟输入关闭数字功能ADC 电压采集
2IN_FLOATING浮空输入随波逐流串口 RX / 必须外部有电阻
3IPD下拉输入默认为 0按键 (另一端接3.3V)
4IPU上拉输入默认为 1按键 (另一端接GND)
5Out_PP通用推挽CPU 控制 + 强输出LED / 蜂鸣器 / 继电器
6Out_OD通用开漏CPU 控制 + 弱输出软件模拟 I2C / 电平转换
7AF_PP复用推挽外设控制 + 强输出PWM / 串口 TX / SPI
8AF_OD复用开漏外设控制 + 弱输出硬件 I2C

“避坑指南”

坑1:开漏输出 (OD) 忘了接上拉电阻

  • 现象:你写 GPIO_SetBits 想输出高电平,结果用万用表一量,电压只有 0.x 伏,或者完全没电压。
  • 原因:选了 GPIO_Mode_Out_OD,但外部没接电阻。单片机此时处于“断路”状态,当然没电。
  • 解决:改成推挽输出,或者外部加电阻。

坑2:读引脚状态,读错了寄存器

  • 场景:你想知道自己刚才让这个引脚输出了什么。
  • 错误:去读 IDR (Input Data Register)。
    • 虽然大部分时候读 IDR 也能读到输出状态,但如果外部电路短路了(比如你输出高,外部被强行拉低),IDR 读到的是实际电压(低),而不是你想输出的(高)。
  • 正确:应该读 ODR (Output Data Register)。

坑3:原子操作 (BSRR vs ODR)

  • 场景:你要同时控制 8 个 LED 里的第 3 个。
  • 普通写法ODR = ODR | 0x04; (读-改-写)。
    • 风险:如果在“读”和“写”之间发生了中断,中断里修改了其他 LED 的状态,等你回来写入时,会把中断里的修改覆盖掉。
  • 高手写法:使用 BSRR (Bit Set/Reset Register)
    • 这是一个“只写”寄存器。写 1 有效,写 0 无效。
    • BSRR = 0x04; 这一句指令直接生效,不需要读回原来的值,完全避免了被中断打断的风险。这就是原子操作

坑4:速度配置 (GPIO Speed)

  • GPIO 初始化结构体里通常有个 GPIO_Speed (2MHz, 10MHz, 50MHz)。
  • 误区:所有都选最快的 50MHz!
  • 真相:速度越快,信号边沿越陡峭,噪声和电磁干扰 (EMI) 越大,功耗也越高。
  • 建议:点个 LED 用 2MHz 足够了;只有 SPI、PWM 这种高速信号才开 50MHz。

总结

  1. GPIO 没标志位,除非当外部中断用(看 EXTI_PR)。
  2. 推挽 (Push-Pull) 是大力士,能推能拉,通用首选。
  3. 开漏 (Open-Drain) 是软脚虾,只能拉低,输出高电平要靠外部电阻(I2C 专用)。
  4. BSRR 是操作 GPIO 的神器,保证操作不会被中断搞乱。