4

代码:

static volatile unsigned char   TMR0    @ 0x01;

static volatile unsigned char   PORTA   @ 0x05;

static volatile unsigned char   PORTB   @ 0x06;

static volatile unsigned char   PORTC   @ 0x07;

此代码来自 PIC16F877A 的 HT-PICC 编译器 pic.h 库文件

我了解 static volatile 和其他关键字的含义。这里 Timer0 的寄存器地址是 0x01 但为什么要@放在前面呢?它与指针有关吗?

4

3 回答 3

7

它是许多嵌入式编译器中常见的编译器扩展,它允许您将变量放置在绝对内存地址中。

来自 HI-TECH C 编译器手册:

3.5.4 绝对变量

大多数变量可以通过在其声明之后使用构造 @address 来定位在绝对地址其中address是要定位变量的内存位置。这样的变量称为绝对变量。

3.5.4.1 数据存储器中的绝对变量

绝对变量主要用于将 C 标识符的地址与特殊功能寄存器相等,但可用于将普通变量放置在数据存储器中的绝对地址处。

在您的示例中:

static volatile unsigned char   TMR0    @ 0x01;

TMR0大概是 8 位无符号硬件寄存器,位于地址 0x01。

于 2018-10-11T06:46:11.467 回答
4

它是一个位于(@)特定内存位置的变量。所以有一个 8 位变量TMR0位于 address 0x01。在用于 PIC 的 Hi-Tech C 编译器的手册中,请参阅第 3.4.4 节指针类型以获取更多信息。

在 vanilla C 中,等价于:

static volatile unsigned char * TMR0 = (volatile unsigned char *) 0x01;

@运算符用于内存非常低的架构中,以帮助降低内存占用。

于 2018-10-11T06:46:56.743 回答
3

这是在特定地址分配变量的常见非标准表示法。在您的情况下,它用于将硬件寄存器映射到 C 变量。

具体来说,目的@是允许链接器/调试器像使用对象一样使用寄存器。这意味着您可以在调试器中对它们添加监视或 rw 断点,就像使用任何其他变量一样。

否则,如果您不需要在调试器中查看这些内容,则可以使用标准 C 等效项:

#define TMR0 (*(volatile uint8_t*)0x01u)

当然,没有必要为硬件寄存器分配空间,因为无论 C 程序做什么,它们都已经存在于硬件中。

良好的调试器带有 MCU 支持,并且可以选择在单独的窗口中查看 MCU 特定的寄存器。所以使用寄存器/寄存器映射的主要原因@是因为工具链带有一个糟糕的调试器。遗憾的是,这是我对嵌入式工具链的体验:调试器越差,编译器提供的寄存器映射就越混乱。

但该@符号也可用于在特定位置声明 RAM/ROM 变量。其他编译器的其他非标准扩展使用各种#pragma,___declspec(section...__attribute__(section.... 如果存在标准方式会很好,但遗憾的是没有。

于 2018-10-11T09:30:22.740 回答