尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

STM32寄存器开发练习(二):GPIO的工作模式

STM32寄存器开发练习(二):GPIO的工作模式
📅 发布时间:2026/7/2 1:12:13

前言

上篇文章,我们点亮了LED,用的是推挽输出模式。

当我们去查STM32的参考手册时,会发现GPIO有8种工作模式!那这么多模式,什么时候该用哪个?

这篇文章,我们就来梳理一下GPIO的8种工作模式,以及它们的应用场景。


为什么要了解GPIO的工作模式?

你可能会问:我只想点亮一个LED,为什么要了解这么多模式?

原因是:

  • 不同的外设,需要不同的GPIO模式
  • 按键输入、PWM输出、I2C通信、ADC采集……每种应用场景,都有对应的最佳GPIO模式
  • 如果模式选错了,外设可能不工作,或者工作不稳定

所以,了解GPIO的工作模式,是STM32开发的基础。


STM32 GPIO的8种工作模式

STM32的GPIO,可以分为两大类:输出模式和输入模式,每类各有4种。

输出模式(4种)

模式说明典型应用
推挽输出(Push-Pull)能主动输出高、低电平LED控制、普通数字信号输出、驱动芯片使能脚
开漏输出(Open-Drain)只能输出低电平,高电平需要外接上拉电阻I2C总线、电平转换
复用推挽输出GPIO 被外设接管,引脚功能由片上外设决定(如PWM、串口TX)PWM输出、USART_TX
复用开漏输出GPIO 被外设接管,引脚功能由片上外设决定(如I2C)I2C_SDA、I2C_SCL

输入模式(4种)

模式说明典型应用
浮空输入(Floating)引脚电平不确定,易受干扰外部信号输入(外部已有明确电平驱动)
上拉输入(Pull-up)内部上拉电阻,无外部信号时为高电平按键输入(按键另一端接GND)、I²C 总线输入
下拉输入(Pull-down)内部下拉电阻,无外部信号时为低电平按键输入(按键另一端接VCC)、检测高电平有效的触发信号
模拟输入(Analog)关闭数字缓冲器,直接连接ADC或比较器电压采集、传感器信号采集

输出模式详解

1. 推挽输出(Push-Pull)

原理:

  • 引脚可以主动输出高电平(3.3V)或低电平(0V)
  • 内部有两个MOS管(PMOS + NMOS):一个接VCC,一个接GND
  • 输出高电平时,上管导通;输出低电平时,下管导通

特点:

  • ✅ 驱动能力强(能输出20mA左右)
  • ✅ 高低电平切换快
  • ✅ 不需要外接上拉电阻

应用场景:

  • LED控制、继电器控制、蜂鸣器控制
  • 普通数字信号输出
  • 驱动芯片使能脚

配置方法(寄存器编程):

c

// 配置PA0为推挽输出、50MHz GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x3 << 0); // CNF0=00(推挽输出),MODE0=11(50MHz)

2. 开漏输出(Open-Drain)

原理:

  • 引脚只能主动输出低电平,高电平需要外接上拉电阻
  • 输出低电平时,内部MOS管导通,引脚被拉到低电平
  • 输出高电平时,MOS管截止,引脚靠外部上拉电阻拉到高电平

特点:

  • ✅ 可以实现电平匹配(比如用5V上拉,就能输出5V电平)
  • ✅ 支持线与(多个开漏输出接在一起,任意一个输出低电平,总线就是低电平)
  • ❌ 高电平切换速度慢(受上拉电阻影响)

应用场景:

  • I2C总线(SDA和SCL都是开漏输出)
  • 电平匹配(3.3V MCU控制5V设备)
  • 多个设备共享一根信号线

配置方法(寄存器编程):

c

// 配置PA0为开漏输出、50MHz GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x7 << 0); // CNF0=01(开漏输出),MODE0=11(50MHz)

3. 复用推挽输出 / 复用开漏输出

原理:

  • 和普通的推挽/开漏输出一样,但输出信号来自外设,不是来自GPIOx_ODR寄存器
  • 比如:PWM信号来自定时器,串口TX信号来自USART模块

应用场景:

  • PWM输出(TIMx_CHx)
  • 串口发送(USARTx_TX)
  • SPI时钟和数据(SPIx_SCK、SPIx_MOSI)

配置方法(寄存器编程):

c

// 配置PA8为复用推挽输出、50MHz(TIM1_CH1) GPIOA->CRH &= ~(0xF << 0); // 清除CNF8和MODE8位 GPIOA->CRH |= (0xB << 0); // CNF8=10(复用推挽输出),MODE8=11(50MHz)

输入模式详解

1. 浮空输入(Floating)

原理:

  • 引脚内部既不上拉,也不下拉
  • 引脚电平完全由外部电路决定
  • 如果外部没有接任何东西,电平是不确定的(可能是高,也可能是低)

特点:

  • ✅ 外部可以灵活控制电平
  • ❌ 如果外部信号不稳定,容易误触发

应用场景:

  • 外部有上拉/下拉电阻的场合
  • 用于读取数字传感器的输出(如DHT11)

配置方法(寄存器编程):

c

// 配置PA0为浮空输入 GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x4 << 0); // CNF0=01(浮空输入),MODE0=00(输入模式)

2. 上拉输入(Pull-up)

原理:

  • 引脚内部有一个上拉电阻(约40kΩ),把引脚拉到高电平
  • 如果外部把引脚拉到低电平,引脚就读到低电平

特点:

  • ✅ 默认高电平,适合按键接GND的场合
  • ✅ 抗干扰能力强

应用场景:

  • 按键输入(按键另一端接GND)
  • 读取开关状态

配置方法(寄存器编程):

c

// 配置PA0为上拉输入 GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x8 << 0); // CNF0=10(上拉/下拉输入),MODE0=00(输入模式) GPIOA->ODR |= (1 << 0); // ODR0=1,选择上拉

或者:

c

// 配置PA0为上拉输入 GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x8 << 0); // CNF0=10(上拉/下拉输入),MODE0=00(输入模式) GPIOA->BSRR = (1 << 0); // 置位 ODR(ODR写 1),选择上拉

更推荐第二种的写法,因为操作ODR的过程是"读-改-写",在中断或多任务中可能被打断,而BSRR是原子操作,不会被中断打断。


3. 下拉输入(Pull-down)

原理:

  • 引脚内部有一个下拉电阻(约40kΩ),把引脚拉到低电平
  • 如果外部把引脚拉到高电平,引脚就读到高电平

特点:

  • ✅ 默认低电平,适合按键接VCC的场合
  • ✅ 抗干扰能力强

应用场景:

  • 按键输入(按键另一端接VCC)
  • 读取开关状态

配置方法(寄存器编程):

c

// 配置PA0为下拉输入 GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x8 << 0); // CNF0=10(上拉/下拉输入),MODE0=00(输入模式) GPIOA->BRR |= (1 << 0); // 清除 ODR(ODR写 0),选择下拉

4. 模拟输入(Analog)

原理:

  • 引脚直接连到ADC模块,用于采集模拟电压
  • 数字输入缓冲器被禁止,引脚的电平变化不会触发中断

特点:

  • ✅ 专门用于ADC采集
  • ✅ 功耗低

应用场景:

  • 电位器读数
  • 温度传感器
  • 电池电压检测

配置方法(寄存器编程):

c

// 配置PA0为模拟输入 GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 // CNF0=00,MODE0=00(模拟输入模式)

如何用寄存器配置GPIO模式?

关键寄存器

配置GPIO模式,主要用这两个寄存器:

  1. GPIOx_CRL(配置低8位引脚,Pin0~Pin7)
  2. GPIOx_CRH(配置高8位引脚,Pin8~Pin15)

每个引脚占用4位:

  • CNF[1:0]:配置模式(输入/输出、推挽/开漏等)
  • MODE[1:0]:配置速度(输入模式下,这两位为00)

实际代码示例

示例:按键输入(上拉输入模式)

c

#include "stm32f10x.h" int main(void) { // 1. 开启GPIOA时钟 RCC->APB2ENR |= (1 << 2); // 2. 配置PA0为上拉输入(假设按键接在PA0,另一端接GND) GPIOA->CRL &= ~(0xF << 0); // 清除CNF0和MODE0位 GPIOA->CRL |= (0x8 << 0); // CNF0=10(上拉/下拉输入),MODE0=00(输入模式) GPIOA->BSRR = (1 << 0); // 置位 ODR(ODR写 1),选择上拉 // 3. 主循环:检测按键 while(1) { if ((GPIOA->IDR & (1 << 0)) == 0) { // PA0为低电平(按键按下) // 做点什么... } } }

将上述代码改成使用官方宏定义的形式:

c

#include "stm32f10x.h" int main(void) { // 1. 开启GPIOA时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 2. 配置PA0为上拉输入(假设按键接在PA0,另一端接GND) GPIOA->CRL &= ~GPIO_CRL_CNF0; // 清除CNF0位 GPIOA->CRL |= GPIO_CRL_CNF0_1; // CNF0=10(上拉/下拉输入) GPIOA->CRL &= ~GPIO_CRL_MODE0; // MODE0=00(输入模式) GPIOA->BSRR = GPIO_BSRR_BS0; // 置位 ODR(ODR写 1),选择上拉 // 3. 主循环:检测按键 while(1) { if ((GPIOA->IDR & GPIO_IDR_IDR0) == 0) { // PA0为低电平(按键按下) // 做点什么... } } }

总结

这篇文章,我梳理了STM32 GPIO的8种工作模式:

输出模式:

  • 推挽输出:最常用,能输出高/低电平
  • 开漏输出:用于I2C、电平匹配
  • 复用推挽/开漏:用于外设功能

输入模式:

  • 浮空输入:外部有上拉/下拉时用
  • 上拉输入:按键接GND时用
  • 下拉输入:按键接VCC时用
  • 模拟输入:用于ADC采集

作者:一个焊板子的人,欢迎关注获取更多硬件工程师学习笔记

如果觉得有帮助,欢迎点赞收藏,也欢迎在评论区交流讨论!

相关新闻

  • LLM上下文工程:从Prompt设计到记忆系统的架构演进
  • 基于STM32与Si4732的高性能数字收音机设计
  • systemctl daemon-reload systemctl restart docker 解释并说明下这个命令

最新新闻

  • STM32与Si4731实现FM收音机开发全解析
  • 工业 IoT 项目为什么死在协议适配,而不是死在联网
  • Linux网络配置指南
  • delete from `后宫佳丽` where age>18
  • [RandomRange节点]原理解析与实际应用
  • React路由开发

日新闻

  • Python Playwright录制功能:从零到一构建自动化测试脚本
  • 如何用开源工具永久保存你心爱的小说:novel-downloader全攻略
  • In-Context Learning不是教知识,而是模式对齐:从5个示例到100个工业级样本的真相

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号