关于STM32的寄存器位操作《^=异或篇》(按键检测 LED反转 宏定义下的Toggle 结构体指针 偏移地址)

在这里有段宏定义如下:

#define LED_GPIO_PORT        GPIOB
#define LED_GPIO_CLK        RCC_APB2Periph_GPIOB
#define LED_GPIO_PIN        GPIO_Pin_5

#define Toggle(p,i) {p->ODR ^=i;}
#define LED_TOGGLE    Toggle(LED_GPIO_PORT,LED_GPIO_PIN)

现在我们来讲解上述代码段中的:#define Toggle(p,i)  {p->ODR ^=i;}

这里运用到了结构体指针与位运算的知识,在这里我默认读者已经掌握相关知识。

stm32f10x.h文件中我们可以找到如下代码段:

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

由此可见GPIOB是一个结构体,其中包含成员32位的输出寄存器ODR

同时我们还可以在stm32f10x_gpio.h文件中找到有关管脚偏移地址的介绍:

注:这里的偏移地址不是C语言中所谓的地址,而是16bit数。

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

stm32参考手册中我们找到有关GPIO_ODR寄存器的说明:30a9b1551c004b4d9d38b8073cf495a9.png

由上图可知,各编号ODR的位数与GPIO_PIN的偏移地址是相等的

例如:GPIO_PIN_5定义为0x0020即二进制的0000 0000 0010 0000。其中的第六位是1,而其他位均为0,恰好是与ODR5是ODR寄存器中的第六位相对应。

所以 GPIOB->ODR ^=GPIO_PIN_5 就是GPIOB的ODR中的低十六位与GPIO_PIN_5(16bit偏移地址)相异或,即实现ODR5即GPIO_PIN5输出电平的反转,而其他位保持不变

例如GPIOB_ODR=0001 001 0010 0001

 GPIOB->ODR ^=GPIO_PIN_5即GPIOB_ODR = GPIOB_ODR^GPIO_PIN_5

GPIOB_ODR = (0001 0010 0010 0001)^(0000 0000 0010 0000)

GPIOB_ODR = 0001 0010 0000 0001         (与1异或取反,与0异或保持不变)

注意:我看到有文章将 #define Toggle(p,i)  {p->ODR ^=i;} 中的i表述为管脚i的输出电平,这是错误的,i是所代表管脚的偏移地址。

 

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值