相关文章推荐
刚失恋的黄瓜  ·  为什么C数组下标从0开始,而不是从1开始_c ...·  2 月前    · 
胡子拉碴的感冒药  ·  如何通過text渲染指定樣式的文本 - ...·  5 月前    · 
眼睛小的柚子  ·  关于加强养老服务人才队伍建设的意见·  6 月前    · 
逆袭的领结  ·  2024年中国碳酸锂行业市场需求现状及发展前 ...·  1 年前    · 
伤情的香菜  ·  Python将string转换成对象 ...·  2 年前    · 
微笑的冰淇淋  ·  404 Not Found·  2 年前    · 
Code  ›  【C语言笔记】操作位的技巧开发者社区
c语言
https://cloud.tencent.com/developer/article/1453795
谦和的风衣
2 年前
作者头像
正念君
0 篇文章

【C语言笔记】操作位的技巧

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 嵌入式大杂烩 > 【C语言笔记】操作位的技巧

【C语言笔记】操作位的技巧

作者头像
正念君
发布 于 2019-07-01 17:25:18
1.4K 0
发布 于 2019-07-01 17:25:18
举报

一、操作位的方法

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

VH0Pit.md.png

二、不改变其他位的值的状况下,对某几个位进行设值。

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

VH0QJ0.md.png

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

TEST = 0x01;

但是,这样设置是不够准确的,因为这时候已经同时操作到了高7位: bit1~bit7 ,如果这高7位没有用到的话,这么设置没有什么影响;但是,如果这7位正在被使用,结果就不是我们想要的了。

在这种情况下,我们就可以借用 & 和 | 进行配置。

对于二进制位操作来说,不管该位原来的值是0还是1,它跟0进行&运算,得到的结果都是0,而跟1进行&运算,将保持原来的值不变;不管该位原来的值是0还是1,它跟1进行|运算,得到的结果都是1,而跟0进行|运算,将保持原来的值不变。

所以,此时可以设置为:

TEST = TEST | 0x01;

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

TEST |= 0x01;

这种写法可以一定程度上简化代码,是 C 语言常用的一种编程风格。

同样的,要给 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)
 
推荐文章
刚失恋的黄瓜  ·  为什么C数组下标从0开始,而不是从1开始_c语言数组从0开始还是从1开始
2 月前
胡子拉碴的感冒药  ·  如何通過text渲染指定樣式的文本 - Mobile Platform as a Service - 阿里雲
5 月前
眼睛小的柚子  ·  关于加强养老服务人才队伍建设的意见
6 月前
逆袭的领结  ·  2024年中国碳酸锂行业市场需求现状及发展前景分析 预计2029年碳酸锂消费量将达200万吨_电池_产品产量_增速
1 年前
伤情的香菜  ·  Python将string转换成对象 python如何将string转为int_mob6454cc6ccc8a的技术博客_51CTO博客
2 年前
微笑的冰淇淋  ·  404 Not Found
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号