再学GPIO(二)

GPIO寄存器

       每个GPI/O端口有两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。

GPIOx_CRL,GPIOx_CRH

寄存器作用

   GPIOx_CRL(Port Configuration Register Low)用于配置 GPIO 端口低位引脚(Pin 0 ~ Pin 7) 的工作模式与输出特性,GPIOx_CRH(Port Configuration Register High)用于配置 GPIO 端口高位引脚(Pin 8 ~ Pin 15) 的工作模式与输出特性,每个引脚占用 4 个二进制位(共 32 位,控制 8 个引脚)。高位引脚(Pin 8 ~ Pin 15)的配置由 GPIOx_CRH 寄存器完成。

偏移地址:0x04 复位值:0x4444 4444

寄存器结构

       每个引脚由 CNFy[1:0]和 MODEy[1:0]字段控制,其中 y 表示引脚号(0~7)。
例如,Pin 0 对应 CNF0[1:0] 和 MODE0[1:0],Pin 1 对应 CNF1[1:0] 和 MODE1[1:0],依此类推。

配置模式详解

例1

浮空输入(Floating Input)设置PA0为浮空输入,寄存器操作如下

// 配置 PA0 为浮空输入(模式:输入,配置:浮空)
GPIOA->CRL &= ~(0x0F << 0*4);  // 清除PA0原有配置
GPIOA->CRL |=  (0x04 << 0*4);  // CNF[1:0]=01(浮空输入), MODE[1:0]=00(输入模式)
  • CNF[1:0] = 01(浮空输入)
  • MODE[1:0] = 00(输入模式)

例2

 上拉输入(Pull-Up Input)设置PA1为上拉输入,寄存器操作如下

// 配置 PA1 为上拉输入
GPIOA->CRL &= ~(0x0F << 1*4);  // 清除PA1原有配置
GPIOA->CRL |=  (0x08 << 1*4);  // CNF[1:0]=10(上拉/下拉输入), MODE=00
GPIOA->ODR |= (1 << 1);        // 使能上拉(ODR对应位写1)
  • CNF[1:0] = 10(上拉/下拉输入)

  • MODE[1:0] = 00(输入模式)

  • 注意:需通过ODR寄存器设置上拉(1)或下拉(0)。

例3

推挽输出(Push-Pull Output)设置PA2为推挽输出,最大速度10MHz

// 配置 PA2 为推挽输出,最大速度10MHz
GPIOA->CRL &= ~(0x0F << 2*4);  // 清除PA2原有配置
GPIOA->CRL |=  (0x01 << 2*4);  // CNF[1:0]=00(推挽输出), MODE=01(10MHz)
  • CNF[1:0] = 00(推挽输出)

  • MODE[1:0] = 01(最大速度10MHz,可选10(2MHz)、11(50MHz))

例4

开漏输出(Open-Drain Output)设置PA3为开漏输出,最大速度50MHz

// 配置 PA3 为开漏输出,最大速度50MHz
GPIOA->CRL &= ~(0x0F << 3*4);  // 清除PA3原有配置
GPIOA->CRL |=  (0x0C << 3*4);  // CNF[1:0]=01(开漏输出), MODE=11(50MHz)
  • CNF[1:0] = 01(开漏输出)

  • MODE[1:0] = 11(50MHz)

GPIOx_IDR

寄存器作用

GPIOx_IDR(Input Data Register)用于读取 GPIO 端口引脚的电平状态(高电平 1 或低电平 0)。每个引脚对应寄存器中的一个二进制位,共 16 位(对应 Pin 0 ~ Pin 15),但实际有效位数取决于具体型号的 GPIO 端口引脚数量。

  • 只读寄存器:无法通过写入修改其值,仅反映引脚的实时电平。

  • 电平有效性

输入模式下(如浮空、上拉/下拉、模拟输入),值由外部电路或内部上/下拉电阻决定。

输出模式下,值反映当前输出寄存器的状态(ODR 的值),而非外部实际电平。

  • 原子操作:直接读取整个寄存器(GPIOx->IDR)可一次性获取所有引脚的电平状态。

寄存器结构

  • 位域IDRy(Input Data for Pin y),y 表示引脚号(0~15)。

位值为 0:引脚当前电平为低(GND)。

位值为 1:引脚当前电平为高(VDD)。

配置模式详解

读取 PA3 引脚的电平状态。PA3 必须配置为 输入模式

// 读取 PA3 的电平(假设已配置为输入模式)
uint8_t pinState = (GPIOA->IDR & GPIO_IDR_ID3) >> 3;  // 提取 PA3 的值

// 或直接判断特定位
if (GPIOA->IDR & GPIO_IDR_ID3) {
    // PA3 为高电平
} else {
    // PA3 为低电平
}

// 读取整个端口的电平状态(16位)
uint16_t portState = GPIOA->IDR;

GPIOx_ODR

寄存器作用

GPIOx_ODR(Output Data Register)用于 控制 GPIO 端口引脚的输出电平状态(高电平 1 或低电平 0)。每个引脚对应寄存器中的一个二进制位(共 16 位,控制 Pin 0 ~ Pin 15),直接控制引脚的输出电平,适用于 推挽输出 或 开漏输出模式。

  • 读写寄存器:可写入值控制输出电平,也可读取当前设置的电平状态。

  • 输出模式依赖

仅在 输出模式(通用或复用)下有效,输入模式下写入无意义。

在输入模式下读取 ODR 返回的是最后一次写入的值,而非实际引脚电平。

  • 原子操作

直接写入整个寄存器(GPIOx->ODR = value)可一次性设置多个引脚电平。

通过位操作(置位/清零)可单独控制某个引脚。

寄存器结构

  • 位域ODRy(Output Data for Pin y),y 表示引脚号(0~15)。

位值为 0:引脚输出低电平(GND)。

位值为 1

        推挽模式:输出高电平(VDD)。

        开漏模式:引脚进入高阻态(需外接上拉电阻才能输出高电平)。

配置模式详解

控制PB5引脚输出高电平,并保持PB7引脚为低电平,PB5 和 PB7 必须配置为 输出模式

// 方法1:直接操作寄存器(不影响其他位)
GPIOB->ODR |= (1 << 5);      // PB5 置高
GPIOB->ODR &= ~(1 << 7);     // PB7 置低

// 方法2:使用库函数(如 HAL 库)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);    // PB5 高电平
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);  // PB7 低电平

// 方法3:批量设置多个引脚电平
GPIOB->ODR = (GPIOB->ODR & 0xFF5F) | (1 << 5);  // 仅修改 PB5 和 PB7
  • 输出模式配置

必须通过 GPIOx_CRL 或 GPIOx_CRH 将引脚设置为 输出模式(通用或复用),否则 ODR 写入无效。

复用功能模式(如 SPI、I2C)下,ODR 通常由外设自动控制,手动写入可能冲突。

  • 开漏模式限制

若配置为 开漏输出,需外接上拉电阻才能输出高电平;否则引脚仅能拉低或保持高阻态。

GPIOx_BSRR

寄存器作用

GPIOx_BSRR(Bit Set/Reset Register)是 STM32 中用于 原子操作 GPIO 输出电平的核心寄存器,可直接设置或清除引脚的输出状态,无需读-改-写操作,避免多线程或中断环境下的数据竞争问题

  • 高 16 位(BRy):用于清除引脚电平(置低)。

  • 低 16 位(BSy):用于设置引脚电平(置高)。

  • 单次写入:可同时设置多个引脚的置高/置低操作。

寄存器结构

  • 位域

    • BSy(Bit Set for Pin y,低 16 位):

      • 写入 1:对应引脚输出高电平(ODRy = 1)。

      • 写入 0:无影响。

    • BRy(Bit Reset for Pin y,高 16 位):

      • 写入 1:对应引脚输出低电平(ODRy = 0)。

      • 写入 0:无影响。

配置模式详解

例1

将 PA5 置高,PA3 置低

/ 方法:直接操作 BSRR 寄存器
GPIOA->BSRR = (1 << 5) | (1 << (16 + 3));  
// 解释:
// - (1 << 5)        → 设置 PA5 为高(BS5 = 1)
// - (1 << (16 + 3)) → 清除 PA3 为低(BR3 = 1)

例2

快速翻转 PB0 电平(高 → 低 → 高交替)

/ 方法:交替设置 BSRR 的 BR0 和 BS0
GPIOB->BSRR = (1 << 0);          // PB0 置高
delay_ms(100);
GPIOB->BSRR = (1 << (16 + 0));   // PB0 置低
delay_ms(100);

下一篇继续讲解GPIO寄存器

### STM32 GPIO 习教程 #### 一、GPIO基本概念 STM32中的GPIO(通用输入输出端口)是用于与外部世界交互的重要接口。通过配置不同的模式和属性,可以实现对外部设备的控制或读取其状态[^4]。 #### GPIO引脚配置选项 对于每一个GPIO引脚来说,在实际应用中可以通过设置相应的寄存器来改变它的功能特性。具体而言: - **模式(Mode)**:决定该引脚作为输入还是输出;还可以进一步细分为模拟输入、推挽输出等多种工作方式。 - **速度(Speed)**:当设定为输出时有效,用来指定信号切换的最大频率范围。 - **上下拉电阻**:可以选择是否启用内部上拉/下拉电阻以稳定未驱动状态下电平[^1]。 #### 三、实例分析——光敏传感器初始化函数解析 考虑一段针对特定应用场景下的代码片段,即如何利用上述知识点完成对连接于PB13上的光敏元件进行初始化操作: ```c void LightSensor_Init(void) { /* 开启时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* 配置GPIO结构体并调用库函数执行初始化 */ GPIO_InitTypeDef GPIO_InitStructure; // 设置成上拉输入模式 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO📐⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗⚗📐 def(); } ``` 此部分展示了怎样基于之前提到的原则去构建具体的程序逻辑,特别是关于`GPIO_Mode_IPU`的选择以及为何要特别处理PB13这个特殊位置的信息[^2]。 #### 四、常见错误及其解决方案 在编写涉及浮点运算单元(FPU)相关汇编指令的过程中可能会遇到类似于“unknown register name 'vfpcc' in asm”的报错提示。这类问题往往是因为编译工具链版本不匹配或是项目工程配置不当所引起的。建议检查当前使用的IDE版本和支持文档,确保所有组件都处于最新且兼容的状态[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值