GPIO之IDR、ODR及BSRR寄存器详解
IDR (Input Data Register, 输入数据寄存器)
每个GPIO端口对应一个IDR寄存器(如GPIOA一个IDR寄存器,GPIOB又一个寄存器),而每一个GPIO引脚(如GPIO_PIN_0)对应IDR寄存器的一位,IDR寄存器的位值对应该引脚的电平【0-0(逻辑低),1-1(逻辑高)】
例如STM32为32位的处理器,其数据总线宽度、寄存器宽度和指令集都是32位的,故其IDR寄存器也是32位的。如果 GPIO 端口支持 16 个引脚(例如 GPIOA),IDR 的低 16 位(位 0 ~ 15)对应 GPIOA 的引脚 0 到引脚 15。剩余的高 16 位(位 16 ~ 31)是未使用的,在这种情况下,这些位通常是固定的 0。如下图所示则表示GPIO_PIN_15和GPIO_PIN_9为高电平,其余为低电平.
位数 | 31 | 30 | … | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
位值 | 0 | 0 | … | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
实际应用示例:
补充:GPIO_PIN_13是位掩码,对应0x2000
= 0010 0000 0000 0000
#define DATA_READ_GPIO GPIOD
#define DATA_READ_PIN GPIO_PIN_13
uint8_t Data=0;
//高位先行
for(int i=7;i--;i>=0)
{
if(DATA_READ_GPIO->IDR&GPIO_PIN_13==1)Data|=1<<i;
else Data|=0<<i;
}
ODR 寄存器(Output Data Register,输出数据寄存器)
同IDR寄存器,每一个GPIO引脚(如GPIO_PIN_0)对应IDR寄存器的一位,IDR寄存器的位值对应该引脚的电平【0-0(逻辑低),1-1(逻辑高)】,也是32位。高16位为0,低16位一一对应,只不过ODR是输出,IDR是输入。
实际应用示例:
//精准控制
GPIOA->ODR|=GPIO_PIN_13; //GPIOA的第13号引脚输出高电平
GPIOA->ODR|=~GPIO_PIN_13; //GPIOA的第14号引脚输出低电平
//LED闪烁
GPIOA->ODR ^= GPIO_PIN_13; // 翻转 LED 状态
BSRR 寄存器(Bit Set/Reset Register,位设置/复位寄存器)
位数 | 功能 | 描述 |
0-15 | Set位 | 写入 1 设置对应引脚为高电平(0-15号引脚) |
16-31 | Reset位 | 写入 1 设置对应引脚为低电平(0-15号引脚) |
相对ODR寄存器的优点是:
通过一次写入寄存器的方式,可以同时设置多个引脚为高电平或低电平,避免因中断或任务切换导致的不一致问题。例如:可以同时设置 GPIO 引脚 13 为高电平,同时将 GPIO 引脚 14 拉低。
实际应用示例:
GPIOC->BSRR = GPIO_PIN_13; // 写入 BSRR 的第 13 位(0~15),引脚 13 被置位
GPIOC->BSRR = GPIO_PIN_13 << 16; // 写入 BSRR 的第 29 位(16~31),引脚 13 被复位
GPIOC->BSRR = GPIO_PIN_13 | (GPIO_PIN_14 << 16); //将引脚13拉高,同时将引脚14拉低
如果BSRR 第0位和第16位同时置1。最终,GPIO_PIN_0设置复位操作会覆盖置位操作,GPIO_PIN_0 引脚的状态为 低电平.
【使用BSRR相对ODR的优点是能够避免竞态问题】
作者:大只L