呵呵,和大家分享几个我用了很久的宏,
菜鸟表示刚刚才用STM32点了个灯,看着例程代码还是有点辛苦,主要是我比较笨吧,什么位与又什么位或的,
还好在学习51的时候写了一些宏,改了一下,代码读起来才感觉舒服一些,心情也好了一点
心情好的时候我就分享~
第一个:
#define BIT(x) (0x01L<<(x))
这个宏是后面使用的基础,很好理解,其实这个宏是抄的,我一开始的定义是
#define BIT0 0x01L
#define BIT1 0X02l
...
第二个:
#define BitFromTo(h, l) ((h > l)? ((BIT(h) - BIT(l) + BIT(h))): (BIT(l) - BIT(h) + BIT(l)) )
打个比方,BitFromTo(3, 0) 的结果就是 0x0f
BitFromTo(7, 4)的结果是0xf0
第三个:
#define AssignBit(type ,flag , which_bit, val) ((((type)which_bit)&((type)val)) | ((flag)&(~((type)which_bit))))
一开始写这个宏的时候是没有type这个参数的,type是从通用性和安全上考虑的,不过又要多打几个字,不爽,如果C/C++能够支持typeof操作符就好了(自己分析,这里不详细写,在帖子的最后我会提供我代码里的全部注释)
比如说我要把变量u8 a 的 6号位到4号位的值设置为 101,我就可以
a = AssignBit(u8, a, BitFromTo(6, 4), BIT(6) | BIT(4));
这样多直观呀,
本来是要这样写的,不仅不好懂,还容易出错
a &= 0x8f;
a |= 0x50;
第四个
#define SetBit(type, flag, which_bit) ((flag) | ((type)which_bit))
这个好理解,如果要把变量a的1号位转置1的话就
a = SetBit(u8, a, BIT(1));
第五个
#define ClearBit(type, flag, which_bit) ((flag) & (~((type)which_bit)))
呵呵,这个是用来把一个变量的某些位清零的
比如把变量u8 a = 0xf4;的2号位清零
a = ClearBit(u8, a, BIT(2));
现在 a == 0xf0 了
最后说一下优缺点,
最大的优点就是可读性好,
最大的缺点就是打的字会比较多,每次要加个类型作为参数,不过在我的眼里,可读性更重要
有网友可能会提到效率问题,
这几个宏没有效率问题!如果参数which_bit和val 是常数表达式(我用到的大部分场合都是这样的),编译器是会自动优化的,不信你可以反汇编看看。如果都是变量,编译器不能优化,但是就算是手动写代码效率也是一样的。
最后附上全部代码以及说明:
/*********************************************************************************
* AssignBit / AssignFlag
*说明:
* 这个宏用来得到一个变量的某个或某几个位被赋值后的值
*参数:
* type 参数flag的类型
* flag 要赋值的变量
* which_bit
* 标明flag的哪几个位要被赋值
* val 表示要赋给flag的那几个位的值
*注意:
* 1. 对于宏,其参数不要用++i;之类的表达式!也不要直接使用调用函数得到的返回值!
* 2. 如果type是寄存器,那么它必须是可读的
*示例:
* u8 a = 0xf0;
* AssignBit(u8, a, BIT4 | BIT0, BIT0);
* 执行完后,a == 0xe1;
*备注:
* 1. 效率上, 如果参数(除flag外)都是常量, 编译器会自动优化, 如果参数是变量, 就算手动写代码也是这个样子的
* 2. (which_bit) 括号是为了保证 AssignBit(flag, BIT0 | BIT1, 0)之类的用法不会出错
*********************************************************************************/
#define AssignBit(type ,flag , which_bit, val)
((((type)which_bit)&((type)val)) | ((flag)&(~((type)which_bit))))
#define AssignFlag AssignBit
#define AssignB AssignBit
/*********************************************************************************
//说明:
// 得到一个变量某几位位被置位后的值
//注意:
// 1. 如果flag是寄存器,必须是可读的
*********************************************************************************/
#define SetBit(type, flag, which_bit) ((flag) | ((type)which_bit))
#define SetB SetBit
//说明:
// 清零位,flag变量中which_bit标明的位被清0
//注意:
// 1. flag必须是可以正常读写的
#define ClearBit(type, flag, which_bit) ((flag) & (~((type)which_bit)))
#define ClearB ClearBit
//说明:
// 检查flag中的某一位是否被置位, 如果被置位, 则宏的值为非0(不一定是1), 如果没有被置位, 则宏的值为0
//注意:
// 1. flag必须是可以读的
#define CheckBit(type, flag, which_bit) ( (flag) & ((type)which_bit) )
#define BIT(x) (0x01L<<(x))
//说明:
// 得到一个指定范围的BIT被置位的值
// BitFromTo(3, 0) 会得到 0x0f
//备注:
// 1. 这个宏是为提高可读性才写的,对于常数参数是表达式的,编译器会自动优化。
#define BitFromTo(h, l) ((h > l)? ((BIT(h) - BIT(l) + BIT(h))): (BIT(l) - BIT(h) + BIT(l)) )
#define BitF2 BitFromTo
#define BitFT BitFromTo
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
呵呵,这两个片子我都没玩过,AVR在我们这只有部分师兄在玩,跟我同年级的好像都没有使用过,
现在在玩STM32
因为现在还没有C++版的固件库,所以我一直都在边学习边积累自己的固件库,
有这些东西确实非常方便,以前问题要考虑移位啊,与啊或啊的。
现在用写好的内联函数+宏+几个模板,基本上就一劳永逸了
封装STM32的寄存器都比较舒服,直接照着参考手册定义寄存器的位,后面的操作都很方便,代码维护起来也比较舒服
其实这些宏STM32官方的库的头文件里面也有相似的,
都是用来方便寄存器操作的,因为参数固定是32位的,所以就不需要type这个参数了。
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
人家的库发布的时候我51都不怎么会...如有雷同,,,还得算是我抄他们的。。。
我以前的宏的实现差不多是那样的,后来把赋值的动作分离出来,通用性会强一点。
再后来到了STM32把一部分宏都改成内联函数去实现了,因为宏使用不当容易出问题
呵呵~~我玩过一点~~
一周热门 更多>