6

Atmel处理器的codevision编译器中,可以指定全局变量的存储地址,例如

int a @0x100; // will place the variable at the address 0x100 in RAM

当然,按照标准 C,变量可以在声明时初始化

int a=42;

但是,我没有发现任何可能同时做这两个。int a @0x100 = 42或者int a = 42 @0x100;不工作,它们会导致编译器错误。

你可能会问为什么这样做如此重要,因为一个人可以简单地拥有

int a @0x100;

int main()
{
    a = 42;
    //...
}

但是,如果我在EEPROM中有变量,我需要初始化它们,因为这是自动生成包含其中值的 eeprom 文件的唯一方法。我以后不能分配这些值,因为在这种情况下,它实际上会在程序的每次启动时将值写入 eeprom。

4

4 回答 4

2

虽然我不知道如何直接将 EEPROM 变量分配给特定地址并对其进行初始化,但我发现此链接非常有用:EEPROM data at fixed address

我使用的解决方案是在 EEPROM 中声明一个结构,并使程序中的所有 EEPROM 变量成为该结构的成员。您定义结构成员的顺序将是链接器将它们放置在 EEPROM 地址空间中的顺序。由于该结构将是唯一的全局 EEPROM 声明,因此可以肯定地说它将被寻址到地址 0x0000。因此,您将知道每个 EEPROM 变量的地址。

例子:

 typedef eeprom struct EEvars
{
    eeprom char    foo1;   // will be located at EEPROM address 0x0000
    eeprom char    foo2;   // will be located at EEPROM address 0x0001
    eeprom short   foo3;   // will be located at EEPROM address 0x0002
    eeprom long    foo4;   // will be located at EEPROM address 0x0004
    eeprom char[3] fooArr; // fooArr[0] @ 0x0008; fooArr[1] @ 0x0009; 
                           // fooArr[2] @ 0x000A 
} EEVARS;

然后,您可以在结构的声明中初始化变量。编译时,这将创建 .eep 文件,其中包含已知 EEPROM 地址处的初始化值。

eeprom EEVARS eepromInit = {0xAA, 0xBB, 0xCCDD, 0xEEEEFFFF, {0xF0, 0xF1, 0xF2}};

这在 AVR 的引导加载程序部分用于升级 FLASH 并且新程序需要访问存储的 EEPROM 变量的情况下尤其有效。它甚至允许您跨软件更新添加 EEPROM 变量,只要您将它们添加到结构的末尾,以免干扰已经建立的这些变量的地址。

于 2013-06-26T13:23:43.113 回答
2

我知道你在说什么,我自己也遇到过同样的问题。问题在于,使用带有与变量本身内联的地址的 @ 符号是大多数工具链的附加功能。虽然许多嵌入式工具链都支持它,因此您可以显式调用 SFR 或其他寄存器的位置,但这不是标准 C 的正常行为。

虽然我不熟悉您正在使用的特定编译器,但我知道大多数编译器提供了一种更复杂的方式来指定内存映射。例如,来自 Atmel 的 ATmega 系列提供了在项目设置中指定自定义内存部分的功能。例如,在 GNU 工具链上,这些部分用作变量声明的一部分,方法是使用带有变量的 section 属性:

 __attribute__((__section__("<section_name>")))

对于 ATmega 系列,您可以在 EEPROM 中定位任何内存,方法是在变量声明的同一行(之前或之后,只要它位于赋值中的“=”之前)包含以下文本:

__attribute__((__section__(".eeprom")))

如果您想保证 EEPROM 中的特定内存地址设置为二进制映像的一部分,因此它只在第一次写入映像时被编程一次,您可以在项目设置中声明一个自定义内存部分(如果您在 Atmel Studio 中开发,它位于“工具链”设置的“内存设置”下)。

例如,我通过在内存设置的 EEPROM 部分中声明“.tune_data”部分(遵循提供的地址偏移等文档)然后声明如下变量,完全按照您对数据块的描述:

const __attribute__((__section__(".tune_data))) Tune_Data_s as_tune_data = { <all_my_data> };

显然它会略有不同,因为您没有使用 GNU 编译器,也可能没有使用 Atmel Studio。但是,如果您仔细研究一下,几乎每个嵌入式编程工具链都提供了一些方法来声明自定义内存部分,然后可以通过编译指示(或 GNU 工具链的属性)将其附加到代码中的变量。规范应该可以通过命令行参数和/或使用命令行选项修改标准链接描述文件来指定非默认链接描述文件。我知道第二种方法是在 IAR 提供的工具链上执行此操作的标准方法,也是唯一方法。

于 2013-11-22T16:26:30.503 回答
2

只看CodeVisionAVR帮助,

@ operator“如果在声明期间必须初始化全局变量(使用 放置在特定地址),则必须使用以下过程:

/* the variable will be stored in EEPROM at address 0x10 */

eeprom int abc @0x10;

/* and it will be initialized with the value 123 */ 

eeprom int abc=123; 
于 2017-01-04T06:05:30.790 回答
0

您可以使用指向绝对地址的指针:

volatile int *pa = (int *) 0x100;

然后您可以使用解引用运算符*访问该地址的值,如下所示:

int value = *pa;

或者

*pa = 0x10;

编辑:没有办法声明一个变量指向一个特定的区域,同时为该区域分配一个值。除非编译器有允许它的扩展。

于 2012-08-02T05:34:19.000 回答