我是AVR编程的新手。我想控制一个变量(uint8_t received_msg
),如果它等于0xFF
。这样做是否正确:
if (!(received_msg ^ 0xFF))
或者我需要一点一点地比较
uint8_t test = 0;
test = received_msg ^ 0xFF
for (i =0; i<8; i++){
test = 0 & (1<<received_msg)
}
if(test==0)
发布于 2013-07-07 22:20:05
如果你想知道一个变量是否等于0xff
,只需要测试它是否相等:
if (received_message == 0xff)
发布于 2013-08-18 17:16:51
你的问题与AVR没有多大关系,只是对编译器和微控制器的工作原理有一些误解。这并不是抱怨这是一个糟糕的问题--任何有助于你学习的问题都是好的!
(TLDR:“使用按位运算符”只是相对于AVR特定的东西,请完全自由地使用所有常规操作。)
首先,你已经用英语表达了你想做的事情--一个相等性测试。像C这样的编程语言的全部要点是允许你以一种相当可读的方式表达计算操作,所以使用received_msg == 0xFF
最明显(因此也是最清楚)的翻译-它是编译器的工作,将其转换成特定计算机(AVR)的代码,即使它做得很糟糕,它也不会浪费几微秒。(它不会,但如果您使代码足够复杂,它可能无法完成出色的工作。)
其次,您已经尝试以另外两种方式表达相同的操作-将每一位与设置值进行比较,并收集结果以查看它们是否都相等。正如第二个版本中的bug所显示的那样,这使得读取和写入都变得棘手,但更重要的是,第二个版本显示了对C的位运算符功能的误解。在这里,按位表示值的每一位都独立于其他位进行处理;它们仍然全部被处理。因此,没有必要将其拆分成循环,并且只会使程序员和编译器的工作变得更加困难。用于使按位运算符仅影响单个位的技术称为掩蔽;它依赖于"0或n= n“、"1和n= n”和"0 xor n= n“等属性。
我也得到了这样的印象,这是基于像AVR这样的微控制器将一直在单个比特上工作的想法。这是非常罕见的,但经常被PLC模仿。我们所做的是使单比特工作比通用CPU的成本更低的操作。例如,考虑"PORTB |= 1<<3“。这可以理解为几个基本的操作:
v0 := 1 // load immediate
v1 := 3
v2 := v0 shiftleft v1 // shift left
v3 := PORTB // load I/O register
v4 := v3 or v2
PORTB := v4 // store back to I/O register
这种解释将是极其精简的指令集,其中加载和存储永远不会与诸如移位和或之类的ALU操作相结合。如果你要求编译器根本不优化,你甚至可以从编译器中得到这样的代码。但由于这是微控制器的常见操作,AVR只需一条指令即可完成此操作,而无需花费寄存器来保持v0-v4:
SBI PORTB, 3 // (set bit in I/O register)
这使我们从需要两个寄存器(重用不再需要的vN )和六条指令变为零寄存器和一条指令。进一步的收益是可能的,因为一旦它是单指令,就可以使用跳过而不是分支。但它依赖于一些已知的东西,例如1<<3只设置了一个固定的位,PORTB是最低的32个I/O寄存器之一。如果编译器不知道这些事情,它就永远不能使用SBI指令,而且曾经有过这样一段时间。这就是为什么我们有“使用按位运算符”的建议--你不再需要编写sbi(PORTB,PB3);
,这对于不了解AVR指令集的人来说是不明显的,但现在可以编写标准C语言的PORTB |= 1<<3;
,因此更清晰,同时也同样有效。可以说,更好的宏命名可能也会使代码更具可读性,但这些宏中的许多都是作为输入速记而出现的-例如,等同于1<<x
的_BV(x)
。
可悲的是,一些标准的C公式变得相当棘手,比如清除位N:port &= ~(1<<N);
这对于“clear_bit(端口,位)”宏来说是一个很好的例子,比如Arduino的digitalWrite。一些微控制器(如8051)为单位工作提供特定地址,而一些编译器提供语法扩展,如端口。3.我有时想知道为什么AVR Libc不声明bitfields for bit manipulation。请原谅我的咆哮。还有一些编译器不知道的优化,例如将PORTB ^= x;
转换为PINB = x;
(这看起来很奇怪-PIN码寄存器是不可写的,所以他们将该操作用于另一个函数)。
另请参阅AVR Libc manual section on bit manipulation,特别是“移植使用已弃用的sbi/cbi宏的程序”。
发布于 2013-07-18 22:37:17
您还可以尝试有用的switch(){ case }语句,如下所示:
#define OTHER_CONST_VALUE 0x19
switch(received_msg){
case 0xff:
do_this();
break;
case 0x0f:
do_that();
break;
case OTHER_CONST_VALUE:
do_other_thing();
break;
case 1:
case 2:
received_1_or_2();
break;
default:
received_somethig_else();
break;
}
此代码将根据received_msg的值执行命令,将常量值放在case word之后是很重要的,并且要小心使用break语句,它会告诉您何时从{ }块跳出。
https://stackoverflow.com/questions/17512883
复制相似问题