STM32F103 GPIO 端口配置寄存器 CRL / CRH 详解

摘要

STM32F103 的 GPIO 所有模式:上拉输入、浮空输入、推挽输出、开漏输出、复用功能、模拟输入,全部由 CRL、CRH 两个端口配置寄存器 控制。绝大多数新手只会调用 GPIO_Init() 库函数,不清楚引脚模式本质就是修改 CRL/CRH 的对应比特位,遇到按键乱跳、串口无波形、I2C 通信失败根本无从排查。本文抛开枯燥手册话术,结合寄存器位结构、手册截图、Keil 内存调试截图,掰开揉碎讲解 CRL、CRH 结构、位定义、组合模式、配置写法、易错点。 关键词:STM32F103,CRL,CRH,GPIO 配置寄存器,CNF,MODE

一、什么是 CRL、CRH 配置寄存器

每组 GPIO(GPIOA/GPIOB/GPIOC...)都拥有两个配置寄存器:

  1. GPIOx_CRL :Configuration Register Low,端口配置低寄存器 管控当前端口 Pin0 ~ Pin7 共 8 个引脚。
  2. GPIOx_CRH :Configuration Register High,端口配置高寄存器 管控当前端口 Pin8 ~ Pin15 共 8 个引脚。

二者结构完全一致,只是管控引脚范围不同,均为 32 位寄存器

📸【截图位置 1:STM 参考手册寄存器映射表】 截取手册中 GPIO 寄存器偏移地址:CRL 偏移 0x00,CRH 偏移 0x04

核心规则:每 4 bit 控制 1 个引脚

不管是 CRL 还是 CRH,规则统一: 4 个二进制位 = 控制 1 个 IO 引脚 32 位寄存器 ÷ 4 位 = 8 组,刚好管控 8 个引脚。

以 CRL 举例分配关系:

表格

寄存器比特区间 管控引脚
Bit3 ~ Bit0 Pin0
Bit7 ~ Bit4 Pin1
Bit11 ~ Bit8 Pin2
Bit15 ~ Bit12 Pin3
Bit19 ~ Bit16 Pin4
Bit23 ~ Bit20 Pin5
Bit27 ~ Bit24 Pin6
Bit31 ~ Bit28 Pin7

CRH 结构同理: Bit3~0→Pin8、Bit7~4→Pin9 ... Bit31~28→Pin15。

📸【截图位置 2:手册 CRL 位分配示意图】 截取数据手册里 CRL 寄存器位分段图,可以直观看到 4 位一组对应引脚。

二、4 位内部结构:CNF 1:0 + MODE 1:0

控制单个引脚的 4 位分为两段:

plaintext

复制代码
高位2位:CNF1 CNF0  → 配置类型
低位2位:MODE1 MODE0 → 模式+输出速度
整体排布:CNF1  CNF0  |  MODE1  MODE0

举例:10 00 代表 CNF=10,MODE=00。

2.1 MODE 1:0 低两位:区分输入 / 输出 + 输出速度

MODE 决定这个引脚到底是输入还是输出,如果是输出,还规定最高翻转速度。

表格

MODE1:0 工作类型 最大输出速度 使用场景
00 输入模式(上电默认) 无速度概念 按键、外部电平读取、ADC 模拟输入
01 输出模式 10 MHz 普通 LED 指示灯、低速开关输出
10 输出模式 2 MHz 长线输出、低速外设,抗干扰更强
11 输出模式 50 MHz SPI、PWM、串口 TX 高速复用引脚

一句话记忆: MODE=00 必然是输入;MODE≠00 就是输出,数值越大速度越快。

2.2 CNF 1:0 高两位:配置引脚电路结构

CNF 的含义取决于当前 MODE 是输入还是输出,两套规则分开理解,不容易混淆。

场景 1:MODE=00(输入模式)

引脚处于输入状态,CNF 用来选择内部上下拉电阻、是否开启施密特触发器。

表格

CNF1:0 输入模式类型 内部电路特点 常用场景
00 模拟输入 关闭上下拉、关闭施密特 ADC 电压采集
01 浮空输入(复位默认) 无上下拉电阻 外部自带上拉的传感器
10 上拉输入 接通内部 40K 上拉电阻 独立按键(按键另一端接地)
11 下拉输入 接通内部 40K 下拉电阻 高电平触发按键检测

通俗解释: 按键一端接 PA0、一端接地,如果配置成上拉输入,没有按下时引脚默认高电平;按键按下引脚变低电平,电平稳定不会乱飘。

场景 2:MODE≠00(输出模式)

引脚为输出,CNF 决定是普通推挽、开漏,还是交由外设复用。

表格

CNF1:0 输出模式类型 特性 适用场景
00 通用推挽输出 既能输出高电平,也能输出低电平,驱动能力强 LED、继电器、普通 IO 输出
01 通用开漏输出 只能主动输出低电平,高电平必须依靠外部上拉电阻 多设备线与通信
10 复用推挽输出 电平由串口、定时器等外设控制,CPU 写 ODR 无效 USART 发送、TIM PWM
11 复用开漏输出 外设控制开漏输出 I2C SDA/SCL 引脚

📸【截图位置 3:官方手册 GPIO 模式组合对照表】 把手册里 MODE+CNF 组合成 8 种 GPIO 模式的表格截图粘贴此处。

三、8 种完整 GPIO 模式对照表(CRL/CRH 配置真值表)

把 CNF+MODE 组合,就能得到 STM3 全部 8 种 GPIO 工作模式,也是标准库枚举的本质来源:

表格

GPIO 模式 CNF MODE 4 位组合
模拟输入 00 00 0000
浮空输入 01 00 0100
上拉输入 10 00 1000
下拉输入 11 00 1100
通用推挽输出 50M 00 11 0011
通用开漏输出 50M 01 11 0111
复用推挽输出 50M 10 11 1011
复用开漏输出 50M 11 11 1111

举例:上拉输入对应的 4 位二进制是 1000,十六进制就是 0x8

四、实操:直接操作寄存器改写 CRL(不用标准库)

需求:配置 PA0 为上拉输入,PA1 为 50MHz 推挽输出。

步骤 1:开启 GPIOA 时钟

时钟不开启,CRL 寄存器无法写入,所有配置无效。

c

运行

复制代码
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

步骤 2:配置 PA0(Pin0,占用 CRL Bit3~Bit0)

目标模式:上拉输入 = 1000(二进制)= 0x8 标准写法:先清空对应 4 位,再赋值,避免覆盖其他引脚配置

c

运行

复制代码
GPIOA->CRL &= ~(0x0F << 0);  // 把Pin0对应的4位全部清零
GPIOA->CRL |=  (0x08 << 0);  // 写入上拉配置 1000

步骤 3:配置 PA1(Pin1,占用 CRL Bit7~Bit4)

目标:推挽输出 50MHz → CNF=00 MODE=11 → 二进制 0011 = 0x03

c

运行

复制代码
GPIOA->CRL &= ~(0x0F << 4);
GPIOA->CRL |=  (0x03 << 4);

为什么一定要先 & 清零?

假设原先 PA1 是浮空输入(0100),直接|=0x03会变成 0100 | 0011 = 0111,模式错乱。 先使用掩码 0x0F 把目标 4 位清零,再赋值,是寄存器操作通用规范。

五、CRH 使用示例(配置 Pin8~Pin15)

配置 PA8 为复用推挽输出(串口 TX 引脚,50MHz) 复用推挽输出:CNF=10,MODE=11 → 4 位数值 1011 = 0xB PA8 对应 CRH 的最低 4 位(Bit3~Bit0):

c

运行

复制代码
GPIOA->CRH &= ~(0x0F << 0);
GPIOA->CRH |=  (0x0B << 0);

六、通俗区分容易混淆的模式(靠 CRL 配置分辨)

  1. 普通推挽输出 vs 复用推挽输出

    • 普通推挽:CNF=00,电平由 ODR/BSRR 控制,手动控制高低电平点灯;
    • 复用推挽:CNF=10,CPU 无法通过 ODR 控制引脚,电平交给串口、定时器等外设接管。 很多人串口发送不出波形,就是把 TX 引脚配置成普通推挽而非复用推挽。
  2. 上拉输入 vs 浮空输入

    • 浮空输入(CNF=01)没有上下拉电阻,引脚悬空时电平随机高低,按键极易抖动;
    • 上拉输入(CNF=10)内置上拉电阻,没按下按键时固定高电平,按键电平稳定。
  3. 模拟输入 CNF=00、MODE=00,关闭数字上下拉与施密特触发器,防止数字电路干扰模拟电压,专门给 ADC 采集使用。

七、CRL/CRH 开发高频错误总结

  1. 记开启 APB2 端口时钟 CRL、CRH 写入任何数值都不会生效,LED 不亮、按键无反应,排查优先查时钟寄存器。
  2. 不清位直接 |= 赋值 多个引脚配置相互干扰,引脚模式莫名其妙错乱,是新手最高发错误。
  3. 复用引脚配置成普通输出 USART、I2C、TIM 复用引脚必须配置复用模式,普通推挽输出外设无法接管引脚,外设失效。
  4. ADC 引脚配置成上拉输入 开启上拉电阻会分流模拟电压,ADC 采集数值不准,ADC 引脚必须配置模拟输入。
  5. PC13/14/15 配置高速输出 备份域引脚驱动能力极弱,即便 CRL 配置 50MHz 推挽,也无法正常驱动 LED。

八、标准库 GPIO_Init 本质就是改写 CRL/CRH

标准库封装之后隐藏了寄存器操作,拆开底层源码可以看到: GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU 等价于给 CRL 对应引脚赋值 CNF=10 MODE=00。 库只是帮我们封装了「清位 + 赋值」的过程,底层依旧操作 CRL 与 CRH 两个寄存器。

九、总结

  1. GPIOx_CRL 管控 Pin0~7,GPIOx_CRH 管控 Pin8~15,结构完全一致;
  2. 单个引脚占用寄存器 4bit:CNF[1:0] + MODE[1:0],组合出全部 8 种 GPIO 工作模式;
  3. MODE 区分输入 / 输出与速度,CNF 决定内部电路结构(上下拉、推挽、复用等);
  4. 寄存器标准配置格式:清零 4 位掩码 &= ~(0x0F<<n) → 写入配置 |= val<<n
  5. 所有 GPIO 异常问题,绝大多数根源都是 CRL/CRH 模式配置错误。

掌握 CRL、CRH 端口配置寄存器,才算真正看懂 GPIO 底层,不再只会复制粘贴库函数代码。后续可以结合 IDR、BSRR 寄存器实现完整按键点灯工程。

相关推荐
振南的单片机世界2 小时前
NVIC:Cortex-M内核的“中断CPU”
stm32·单片机·嵌入式硬件
KaifuZeng2 小时前
运算放大器学习笔记-虚短和虚断
单片机·嵌入式硬件·运算放大器
张海森-1688203 小时前
cv610的spi0上适配tmi8150b电机ic
单片机
硅农程序猿3 小时前
芯片设计中的门级仿真(GLS):从零延迟验证到 SDF 时序反标
嵌入式硬件·硬件架构·risc-v·芯片
智购科技智能售货柜4 小时前
自动售货机主控方案怎么选?——单片机、树莓派、ESP32的实战对比~YH
单片机·嵌入式硬件
米饭不加菜4 小时前
电平转换电路
经验分享·嵌入式硬件·硬件工程
老k一步步来18 小时前
STM32 HAL库CAN通信核心函数详解,参数以及作用
stm32·单片机·嵌入式硬件
gwf21618 小时前
SSD读写速度深度解析:顺序读写vs随机读写、IOPS、延迟,你的硬盘性能到底怎么看?
git·嵌入式硬件·缓存·github·智能硬件