MSP430 上寄存器的按位运算符,无需取消引用

Bitwise operator on registers on MSP430 without dereferencing

我使用的是 MSP430G2553,TI 在 headers 中定义了一些我正在使用的辅助代码 (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 的值在 link 时被添加并且定义为(在 linker 脚本中):

P1DIR              = 0x0022;

最后我们得到

extern volatile unsigned char 0x0022;

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

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

extern volatile unsigned char P1DIR

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

这个...

extern volatile unsigned char P1DIR

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

我也倾向于认为您误解了 linker 脚本。你说

The value of P1DIR is added at link time

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

P1DIR              = 0x0022;

... 那么就是定义对应于该符号的地址,而不是 C-language 意义上的值。这与存储在那里的值的类型无关。 linking 的全部意义在于将地址与符号相关联。

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