AVR:如果声明

时间:2013-07-07 14:12:00

标签: c avr

我是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)

4 个答案:

答案 0 :(得分:6)

如果您想知道变量是否等于0xff,只需测试相等性:

if (received_message == 0xff)

答案 1 :(得分:2)

你的问题与AVR关系不大,但有些关于编译器和微控制器如何工作的错误想法。这不是一个抱怨,这是一个糟糕的问题 - 任何有助于你学习的问题都是好的!

(TLDR:“使用按位运算符”仅与AVR特定的东西形成对比,您可以完全自由地使用所有正常操作。)

首先,你用英语表达了你想要做的事情 - 一个平等测试。像C这样的编程语言的全部意义在于允许您以一种相当可读的方式表达计算操作,因此使用received_msg == 0xFF最明显(也就是说清晰)的转换 - 编译器的工作就是将其转换为特定计算机(AVR)的代码,即使它做得很糟糕,它也会浪费不到几微秒。 (事实并非如此,但是如果你使代码变得足够复杂,它就无法做得很好。)

其次,你试图表达相同的操作 - 将每一位与设定值进行比较,并以另外两种方式收集结果以查看它们是否全部相等。读取和写入都很棘手,如第二版中的错误所示,但更重要的是,第二个版本显示了对C的按位运算符的误解。这里的按位意味着值的每个位都独立于其他位进行处理;他们仍然处理完毕。因此,不需要将其拆分为循环,只会使程序员和编译器的工作更加困难。用于使按位运算符仅影响单个位的技术,不与其操作混淆,被称为屏蔽;它依赖于“0或n = n”,“1和n = n”以及“0 x或n = n”等属性。

我也得到的印象是,这是基于像AVR这样的微控制器一直在处理各个位的想法。这种情况极为罕见,但经常被PLC模拟。我们所拥有的是使单位工作的成本低于通用CPU的成本。例如,考虑“PORTB | = 1 <&lt; 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操作组合,例如shift和or。如果您要求它不进行优化,您甚至可能会从编译器中获取此类代码。但由于它是微控制器的常见操作,因此AVR只需一条指令即可完成此操作而无需在保持v0-v4时使用寄存器:

SBI PORTB, 3     // (set bit in I/O register)

这使我们不需要两个寄存器(从重用不再需要的vN)和六个指令到零寄存器和一个指令。进一步的增益是可能的,因为一旦它是单个指令,就可以使用跳过而不是分支。但它依赖于一些已知的事情,例如1 <&lt;&lt; 3&lt; 3仅设置单个固定位,PORTB是最低32个I / O寄存器之一。如果编译器不知道这些东西,它就永远不会使用SBI指令,并且有这样的时间。这就是我们建议“使用按位运算符”的原因 - 您不再需要编写sbi(PORTB,PB3);,这对于不了解AVR指令集的人来说是显而易见的,但现在可以编写PORTB |= 1<<3;这是标准的C,因此更加清晰,同时同样有效。可以说更好的宏命名也可能使代码更具可读性,但许多宏都是在输入短语时出现的 - 例如_BV(x)等于1<<x

可悲的是,一些标准的C公式变得相当棘手,比如清除位N:port &= ~(1<<N);这对于像“Arduino的digitalWrite”这样的“clear_bit(端口,位)”宏来说是个很好的例子。一些微控制器(如8051)为单比特工作提供特定地址,一些编译器提供语法扩展,如port.3。我有时想知道为什么AVR Libc没有声明bitfields for bit manipulation。请原谅。还有一些编译器不知道的优化,例如将PORTB ^= x;转换为PINB = x;(这看起来很奇怪 - PIN寄存器不可写,所以他们将该操作用于另一个函数)。

另请参阅AVR Libc manual section on bit manipulation,特别是“移植使用已弃用的sbi / cbi宏的程序”。

答案 2 :(得分:0)

您还可以尝试使用有用的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 之后放置常量值,并注意 break 当从 {} 块跳出时告诉它的声明。

答案 3 :(得分:0)

我不确定received_msg将代表什么。如果是数值,则一定要使用开关盒,if-else或其他比较结构;不需要位掩码。

但是,如果received_msg包含二进制数据,并且您只想查看某些元素并排除其他元素,则位掩码将是合适的方法。