【问题标题】:Bitwise operator on registers on MSP430 without dereferencingMSP430 上寄存器的按位运算符,无需取消引用
【发布时间】:2023-03-14 01:15:01
【问题描述】:

我使用的是 MSP430G2553,TI 在我使用的标头 (msp430g2553.h) 中定义了一些帮助代码。因此,例如,如果我想设置端口 1 的 GPIO 引脚 0 的方向,我可以写

P1DIR |= BIT0;

出于好奇,我查看了 P1DIR 是如何定义的。我发现了

SFR_8BIT(P1DIR);

其中 SFR_8BIT 定义为

#define SFR_8BIT(address)   extern volatile unsigned char address

所以我们得到

extern volatile unsigned char P1DIR

P1DIR 的值是在链接时添加的,它被定义为(在链接描述文件中):

P1DIR              = 0x0022;

所以我们终于得到了

extern volatile unsigned char 0x0022;

所以在我看来 P1DIR 是一个指针,这意味着我们应该 取消引用它。但在所有文档中,我认为他们直接在 P1DIR 代替 *P1DIR。这怎么可能?

【问题讨论】:

  • P1DIR 至少根据上面的声明不是指针类型,如果它被定义为extern volatile unsigned char *P1DIR,它将是指针。
  • @kiranBiradar 是的,你是对的。但在我看来,P1DIR 的值是一个地址,就像指针的值是一个地址一样。那么,如果我们首先将指针转换为 int/char,我们能否在不取消引用指针的情况下对指针值进行按位操作?也许我错过了链接阶段发生的其他事情。
  • 在这种情况下,我想我需要将 P1DIR 转换为指针,然后对其进行按位运算,例如 *((char *) (P1DIR)) |= BIT0; .好吧,也许这毕竟是有道理的,将其转换为指针然后解除引用会相互消除。
  • casting it to a pointer and then dereferencing eliminates each other 不,这是不正确的。这样做实际上取消了0x0022 位置。

标签: c pointers cpu-registers msp430


【解决方案1】:

编译器将 P1DIR 视为一个变量,正如您正确跟踪的那样,它看到 P1DIR 是这样的:

extern volatile unsigned char P1DIR

这是一个变量,它的地址在别处定义。在这种情况下,可能会在链接步骤中使用的标准库中。
在链接步骤中,变量的地址被解析,并且 P1DIR 取自它被定义为 0x22 的位置。
这种变量需要在特定的地址上,因为它需要在该端口的定义地址上。 您可以在 MSP430 文档中查看每个端口的地址(其中声明 P1DIR 位于 0x22)

【讨论】:

    【解决方案2】:

    这...

    extern volatile unsigned char P1DIR
    

    ... 将P1DIR 声明为volatile unsigned char,而不是指向一个的指针。对这样的对象进行按位运算是没有问题的。

    我也倾向于认为您误解了链接描述文件。你说

    P1DIR 的值是在链接时添加的

    ,但是虽然我不知道所讨论的特定链接器脚本语言,但它是一种 link 语言。当然,如果脚本包含 ...

    P1DIR              = 0x0022;
    

    ... 那就是定义与该符号对应的地址,而不是它在 C 语言意义上的值。这与存储在那里的值的类型无关。将地址与符号相关联就是链接的全部内容。

    那么,0x0022 大概是一个 I/O 端口的地址。当程序读取P1DIR 的值时,它正在从该地址读取一个值,因此从端口读取一个值,这可能会暴露状态寄存器或类似寄存器的值。它不是在读取地址本身。

    【讨论】:

    • 很好的答案,谢谢我现在明白了。我误解了链接器阶段。链接器不设置 P1DIR 的值,它设置位置。事后看来,extern volatile unsigned char 0x0022;甚至没有意义,我的意思是变量名去了哪里...... :)