当前位置: 首页 > news >正文

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

前言

上篇文章,我们点亮了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采集

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

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

http://www.jsqmd.com/news/1105754/

相关文章:

  • 基于BP神经网络的交通标志识别系统设计与实现
  • MH迈汇:从执行效率切入的标准评估
  • LLM上下文工程:从Prompt设计到记忆系统的架构演进
  • 基于STM32与Si4732的高性能数字收音机设计
  • paperxie 论文智能创作工具实测:按页面指引走,轻松搞定全类型学术文稿
  • PPP中 ERP 文件使用说明
  • AI 辅助:异步高并发调优:uvloop 不是最后一颗银弹
  • systemctl daemon-reload systemctl restart docker 解释并说明下这个命令
  • paperxie 论文智能写作全拆解|一步一步看懂学术创作完整操作逻辑
  • 谷歌起个大早赶个晚集:巨头病晚期还有救吗?
  • 2026全国网站建设公司排行榜:品牌官网与企业门户深度评测
  • 零基础企业线上运营落地,好客搜配套完整工具 + 落地指导服务体系
  • ISS 间歇更新稳定性证明 — 穷举收紧路径
  • RevokeMsgPatcher防撤回补丁原理与版本适配实战指南
  • STC3115+PIC24FJ64GB004电池监控系统设计与优化
  • 做云图存储用的
  • 计算机二级知识点总结(含资料)
  • 企业官网做 FAQPage 和 Article JSON-LD,字段应该怎么设计?
  • 基于TPAFE0808与PIC18F96J65的多通道高精度数据采集系统设计
  • 2026全国企业软件定制开发公司排行榜:ERP、CRM与业务系统怎么选
  • 基于MCP协议构建跨平台移动自动化测试框架:5分钟实现iOS与Android统一测试
  • 软件集成ROS2(支持离线示教机械臂)逻辑记录
  • YOLOv10模型改进-注意力机制-第33篇:YOLOv10改进策略【注意力机制】| EfficientAttention高效注意力
  • 2026上海APP开发公司实力榜:哪家好?深度评测与项目避坑
  • IDEA AI Assistant 真实性能压测报告:代码补全准确率92.7%、上下文理解延迟≤380ms,但93%开发者忽略了这3个关键配置
  • 化工易燃易爆区域普通测风设备有隐患?防爆风速风向仪防爆结构安全可靠
  • 如何3分钟掌握全网小说离线阅读:novel-downloader终极指南
  • 好吧,既然是概述,那么就先说点什么,光一个表格个人感觉表现力太有限了。如果对笔者的自报家门没啥兴趣的话,可以直接跳到下一节。
  • 3分钟将智能手机变成专业直播摄像头:DroidCam OBS插件全攻略
  • 基于Si4731与PIC18F86J10的DIY数字收音系统开发指南