簡體   English   中英

初始化變量並同時指定存儲地址:是否可能?

[英]Initializing a variable and specifying the storage address the same time: is it possible?

例如,在Atmel處理器的codevision編譯器中,可以指定全局變量的存儲地址

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

當然,根據標准C,變量可以在聲明時初始化

int a=42;

但是,我沒有發現任何可能同時做到這兩點。 int a @0x100 = 42int a = 42 @0x100; 不起作用,它們會導致編譯器錯誤。

你可能會問為什么這么做很重要,因為人們可以這樣做

int a @0x100;

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

但是,如果我在EEPROM中有變量,我需要初始化它們,因為這是自動生成帶有值的eeprom文件的唯一方法。 我以后不能分配這些值,因為在這種情況下,它實際上會在程序的每個開始時將值寫入eeprom。

雖然我知道無法直接將EEPROM變量分配給特定地址並對其進行初始化,但我發現此鏈接非常有用: 固定地址的EEPROM數據

我使用的解決方案是在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變量,只要將它們添加到結構的末尾即可,以免干擾已建立的變量的地址。

我知道你在說什么,我自己也有同樣的問題。 問題是使用帶有變量本身內聯地址的@符號是大多數工具鏈的附加功能。 雖然它支持許多嵌入式工具鏈,因此您可以明確地調出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工具鏈的屬性)將其附加到代碼中的變量。 規范應該可以通過命令行參數和/或使用命令行選項修改標准linkerscript來指定非默認的linkerscript。 我知道第二種方法是在IAR提供的工具鏈上進行標准和唯一的方法。

只需看看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; 

您可以使用指向絕對地址的指針:

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

然后你可以使用解除引用運算符*來訪問該地址的值,如下所示:

int value = *pa;

要么

*pa = 0x10;

編輯:無法聲明變量指向特定區域,同時為該區域指定值。 除非編譯器具有允許它的擴展名。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM