C语言 | 位操做的一些技巧

1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。关注微信公众号【嵌入式大杂烩】,回复1024,便可免费获取!git

操做位有两种方法,一种是位字段,另外一种是使用按位运算符。位字段的方法可查看往期笔记:【C语言笔记】位域。本文介绍使用按位运算符操做位的方法。下表为几种位操做符及其含义:github

位操做符

不改变其余位的值的情况下,对某几个位进行设值

嵌入式编程中,经常须要对一些寄存器进行配置,有的状况下须要改变一个字节中的某一位或者几位,可是又不想改变其它位原有的值,这时就可使用按位运算符进行操做。下面进行举例说明,假若有一个8位的TEST寄存器:
TEST寄存器编程

当咱们要设置第0位bit0的值为1时,可能会这样进行设置:微信

TEST = 0x01;

可是,这样设置是不够准确的,由于这时候已经同时操做到了高7位:bit1~bit7,若是这高7位没有用到的话,这么设置没有什么影响;可是,若是这7位正在被使用,结果就不是咱们想要的了。markdown

在这种状况下,咱们就能够借用“&”和“|”进行配置。ide

对于二进制位操做来讲,无论该位原来的值是0仍是1,它跟0进行&运算,获得的结果都是0,而跟1进行&运算,将保持原来的值不变;无论该位原来的值是0仍是1,它跟1进行|运算,获得的结果都是1,而跟0进行|运算,将保持原来的值不变。函数

因此,此时能够设置为:ui

TEST = TEST | 0x01;

其意义为:TEST寄存器的高7位均不变,最低位变成1了。在实际编程中,常改写为:.net

TEST |= 0x01;

这种写法能够必定程度上简化代码,是 C 语言经常使用的一种编程风格。code

一样的,要给TEST的低4位清0,高4位保持不变,能够进行以下配置:

TEST &= 0xF0;

这个场景单片机开发中常用,方法就是先对须要设置的位用&操做符进行清零操做,而后用|操做符设值。好比我要改变GPIOA的状态,能够先对寄存器的值进行&清零操做:

GPIOA->CRL &= 0XFFFFFF0F; //将第4-7位清0

而后再与须要设置的值进行|或运算:

GPIOA->CRL |= 0X00000040; //设置相应位的值,不改变其余位的值
移位操做提升代码的可读性。

移位操做在单片机开发中也很是重要,下面让咱们看看固件库的GPIO初始化的函数里面的一行代码:

GPIOx->BSRR = (((uint32_t)0x01) << pinpos);

这个操做就是将BSRR寄存器的第pinpos位设置为1,为何要经过左移而不是直接设置一个固定的值呢?其实,这是为了提升代码的可读性以及可重用性。这行代码能够很直观明了的知道,是将第pinpos位设置为1。若是你写成:

GPIOx->BSRR = 0x0030;

这样的代码就很差看也很差重用了。
相似这样的代码不少:

GPIOA->ODR |= 1 << 5; //PA.5输出高,不改变其余位

这样咱们一目了然,5告诉咱们是第5位也就是第6个端口,1告诉咱们是设置为1了。

~取反操做使用技巧

SR寄存器的每一位都表明一个状态,某个时刻咱们但愿去设置某一位的值为0,同时其余位都保留为1,简单的做法是直接给寄存器设置一个值:

TIMx->SR = 0xFFF7;

这样的做法设置第3位为0,可是这样的做法一样很差看,而且可读性不好。看看库函数代码中怎样使用的:

TIMx->SR = (uint16_t)~TIM_FLAG;

而TIM_FLAG 是经过宏定义定义的值:

#define TIM_FLAG_Update  ((uint16_t)0x0001)
#define TIM_FLAG_CC1     ((uint16_t)0x0002)
#define TIM_FLAG_CC2     ((uint16_t)0x0004)
#define TIM_FLAG_CC3     ((uint16_t)0x0008)
#define TIM_FLAG_CC4     ((int16_t)0x0010)
#define TIM_FLAG_COM     ((uint16_t)0x0020)
#define TIM_FLAG_Trigger ((uint16_t)0x0040)
#define TIM_FLAG_Break   ((uint16_t)0x0080)
#define TIM_FLAG_CC1OF   ((uint16_t)0x0200)
#define TIM_FLAG_CC2OF   ((uint16_t)0x0400)
#define TIM_FLAG_CC3OF   ((uint16_t)0x0800)
#define TIM_FLAG_CC4OF   ((uint16_t)0x1000)

即设置SR第3位为0时可设置为:

TIMx->SR = (uint16_t)~TIM_FLAG_CC3;

以上就是关于位操做在嵌入式编程中的一些技巧,若有错误,欢迎指出!

参考资料:

《STM32F1开发指南-库函数版本_V3.1 》

《手把手教你学51单片机》

相关文章
相关标签/搜索