完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
刚开始学习STM8单片机时,看别人的代码,在设置寄存器的时候经常使用,位或、位与、左移、右移等运算,就很不理解,为什么不直接给寄存器赋值,非要搞的这么复杂。直到后来程序写的多了,才明白这样写的好处。比如我们现在要设置PB5口为输出口。首先我们需要设置PB口的方向寄存器PB_DDR。
我们要设置PB5口为输出,那么就要把DDR5位设置为1。那么要设置的寄存器PB_DDR寄存器二进制数据为 0010 0000,转换为16进制为 0x20。设置寄存器的语句为 PB_DDR = 0x20; 这样操作寄存器看起来没什么问题,也挺方便。唯一的问题就是每次要先将设置的二进制数确定好,然后再转换为16进制数,再赋值给寄存器。代码少的时候没什么感觉,但是一旦代码量比较大,要设置的寄存器比较多时,再这样操作就比较麻烦,特别是设置的寄存器值要进行改变时再去计算二进制数,在转换成16进制数,就非常麻烦。而且还要不停的查阅参考手册,来确认寄存器的每一位值。一不小心很容易设置错,排除原因的时候又很难发现。 为了方便程序的编写和维护,这时候就需要用到移位运算。还是上面的例子,要设置PB5口为输出,需要将PB_DDR寄存器的第5位设置为1,其他位不变。那么将1左移5位,第五位不就刚好是1了吗。我们来看看移位操作,首先1的二进制数为 0000 0001 将这个数左移五位,最高位移出去,最低位补0,那么,向左移动5位后,变为 0010 0000 转换为16进制数为 0x20。于是对PB_DDR寄存器的设置语句可以改为: PB_DDR = 1<<5; 将1左移5位,然后赋值给PB_DDR寄存器。这样从代码上一眼就能看出来这是设置PB_DDR寄存器的DDR5为1。比上面的那种操作方式看起来简洁明了。 如果要继续设置PB4为输出的时候,寄存器的设置就可以写为: PB_DDR = 1<<4; 这样就将PB4口设置为了输出口。这时我们发现了一个问题,当将PB4设置为输出口时寄存器的值变为 0001 0000,DDR4为0,但是又将上一步设置的DDR5的值由1 变为0了,将PB4设置为输出后,又将PB5设置为了输入,改变了设计初衷。 那么如何解决这种问题呢,就需要用到位运算。先看看位或运算和位与运算的区别: 位或运算 |: 位之间进行或运算,如果有一个位为1,结果就为1。 位与运算&:位之间进行与运算,如果有一个位为0,结果就为0。 在设置PB4的时候不希望影响到PB5位,那么就可以用位或运算,给第4位或1,不管第4位以前的值是1还是0,与1进行或运算后,第4位的值就会变成1。那么在给PB_DDR赋值时,先进行或运算. PB_DDR = PB_DDR | 0x10; 同样为了方便程序书写和阅读,将16进制数改为位移运算。 PB_DDR = PB_DDR | (1<<4); 为了书写简便,可以将上面的语句简写为: PB_DDR |= 1<<4; 这样在操作寄存器其中一位的时候,不会影响到其他位。这时如果设置PB4、PB5为输出,可以这样写: PB_DDR |= 1<<4; PB_DDR |= 1<<5; 这样通过位移运算和位或运算的组合,可以很方便的设置寄存器值。 从语句上就能很清楚的看到是设置 PB_DDR寄存器的第4位和第5位为1。 如果这时候又需要将PB4口设置为输入模式,那么就需要将DDR4位由1变为0。位或运算只能将0变为1,不能将1变为0。而位与运算可以将1变为0,那么可以用位与运算实现。给PB_DDR寄存器的第4位位与0,就能将DDR4位由1变为0。 第4位为0,其他位为1二进制数为 1110 1111 转换为16进制数为0xEF。 PB_DDR = PB_DDR & 0xEF; 这样在不影响其他位的情况下,将第4位变为了0。但是这样换算16进制也很麻烦,能不能同样用位移运算实现。但是位移运算是高位溢出后,低位自动补0。我们需要的是自动补1,那么有没有其他办法实现。我们观察设置第4位为0和第4位为1时的二进制数据 0001 0000 1110 1111 这两组数据刚好互补,那么将第4位为1其他位为0的数进行取反操作,那么得到的数刚好就是我们位与运算需要的数。 那么上面的设置语句可以改为 PB_DDR = PB_DDR &( ~(1<<4)); 将1左移4位后,先取反,让第4位变为0,其他位变为1,在和寄存器原先的值进行位与运算,那么就可以在不影响其他位的情况下,将第4位由1变为0。 上面的设置语句可以简写为: PB_DDR &= ~(1<<4); 通过增加一个取反运算,就可以实现用位移运算对寄存器某一位清0。 通过上面的分析可以得出一个结论 位或 | 运算可以实现将寄存器的某一位置1,而 位与& 运算可以实现将寄存器的某一位清0。通过这几种运算符的组合,设置寄存器时就会很方便快捷。 如要将PB4设置为输出,PB5设置为输入,那么运用上面的方法,可以很轻松的写出 PB_DDR |= 1<<4; PB_DDR &= ~(1<<5); 这时候在看用以前对寄存器的操作方法,先设置对应的二进制数为 DDR4 为1 DDR5为0 0001 0000 转换为16进制数位 0x10 设置语句为 PB_DDR = 0x10; 明显可以发现直接设置寄存器操作起来麻烦,程序可读性很差。要修改寄存器的值时很费劲。 所以在以后代码编写中,推荐大家多用位或、位与、左移、右移、取反这些运算的组合方式进行寄存器设置。 |
|
|
|
只有小组成员才能发言,加入小组>>
3311 浏览 9 评论
2994 浏览 16 评论
3493 浏览 1 评论
9058 浏览 16 评论
4087 浏览 18 评论
1178浏览 3评论
605浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
599浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 23:44 , Processed in 1.231146 second(s), Total 79, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号