【问题标题】:Bit setting logic in CC中的位设置逻辑
【发布时间】:2016-12-03 06:16:24
【问题描述】:

我很难理解在 32 位寄存器中成功设置位背后的逻辑。下面是函数的伪代码:

读取主寄存器,
如果第29位CREG_CLK_CTRL_I2C0没有设置,则设置

uint32_t creg;

//read the CREG Master register   
creg = READ_ARC_REG((volatile uint32_t)AR_IO_CREG_MST0_CTRL);

if((creg & (1 << CREG_CLK_CTRL_I2C0)) == 0){
     creg |= ( 1 << CREG_CLK_CTRL_I2C0);
     WRITE_ARC_REG(creg, (volatile uint32_t)(AR_IO_CREG_MST0_CTRL));
}

如果 CREG 主寄存器最初为空,则逻辑无法按预期工作。但是,如果我在第 31 位 (1000...0) 中用全零和 1 填充它,则逻辑确实有效。我不确定我的测试条件是不正确还是其他原因。

谁能帮忙?

【问题讨论】:

  • creg的类型是什么?
  • "如果第 29 位没有设置" - 为什么不直接设置呢。
  • 您的目标到底是什么?如果您只是想设置一点,那么我什至根本不会打扰条件,只需设置它即可。如果它已经设置好了,谁在乎呢?
  • 您编写的代码预计 CREG_CLK_CTRL_I2C0 为 29,第 29 位。您确定是这种情况,并且CREG_CLK_CTRL_I2C0 不是第 29 位的 0b00100000000000000000000000000000 吗?
  • 永远不要使用演员表,直到你能证明你必须这样做并且你理解所有的含义!您使用的宏应该已经正确定义(如果没有获得另一个工具链,那就不好了。并且要小心移位有符号整数。除非您真的知道自己在做什么并且必须这样做,否则请避免使用它们!

标签: c arduino logic bit


【解决方案1】:

就个人而言,我会使用给定的数据类型:uint32_t。无论上下文如何,这都将保证对齐。那是(为了清楚起见,假设 shift 不会产生不同的尺寸类型)

uint32_t mask = ((uint32_t)1) << CREG_CLK_CTRL_I2C0;
if((creg & mask) == 0){
     creg |= mask;
     WRITE_ARC_REG(creg, (volatile uint32_t)(AR_IO_CREG_MST0_CTRL));
}

【讨论】:

    【解决方案2】:

    以下是调试问题的一些想法:

    第 1 步:确保您真正了解该寄存器的工作原理。请记住,微控制器寄存器的行为可能与内存不同。寄存器可能会忽略您尝试将1 写入某个位,直到满足某些其他条件。如果您先将1 写入第 31 位,也许这就是它起作用的原因。位 31 有什么作用?

    第2步:我在网上翻了一下,发现定义READ_ARC_REG()WRITE_ARC_REG()的同一个标头可能还包含SET_ARC_BIT()的定义。看看你能不能找到并使用它。

    第 3 步:确保您尝试编写的内容有意义。在调试器中逐步执行该函数和/或添加某种形式的打印输出以显示您尝试写入寄存器的值。然后在这样做之后读取寄存器并重复该过程。查看您是否尝试写入正确的值,然后查看该写入是否实际完成。如果您的代码尝试将您想要的值写入寄存器,但随后的读取显示您的写入没有更改该位,则返回上面的第 1 步。

    【讨论】:

      【解决方案3】:

      只是一个猜测(我不做太多嵌入式编程),但根据 C 标准,数字文字 1 的类型为 int。在嵌入式编程中int 可以是 16 位,在这种情况下,您的左移将具有未定义的行为,因为右操作数太大。

      所以尝试使用1L 使其成为long 类型。

      此外,正如 Olaf 在 cmets 中提到的,除非您确定需要它,否则不要使用 (volatile uint32_t) 强制转换。一些谷歌搜索表明这是关于 Arduino 101,我发现 source code 确实使用了 READ_ARC_REGWRITE_ARC_REG 没有任何演员。

      creg = READ_ARC_REG(AR_IO_CREG_MST0_CTRL);
      
      if((creg & (1L << CREG_CLK_CTRL_I2C0)) == 0){
           creg |= (1L << CREG_CLK_CTRL_I2C0);
           WRITE_ARC_REG(creg, AR_IO_CREG_MST0_CTRL);
      }
      

      【讨论】:

      • 我已经删除了我的 volatile 强制转换,将我的 '1' 整数强制转换为 uint32_t 并使用了掩码,但如果寄存器最初为空,则该位仍未设置...
      • 使用 1L 的一个弱点是它是有符号的,将 1 移到符号位置是一个问题,因为 CREG_CLK_CTRL_I2C0 可能是 31。代码可以使用 1UL 来避免这种情况。
      猜你喜欢
      • 2023-04-05
      • 2012-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多