2016-02-04 79 views
0

documentation on PROGMEM的底部,這說明什麼看起來像一個非常簡單的方式編譯字符串到程序的.text段:爲什麼F()宏(將字符串存儲在.text中)編譯?

的F()宏

當像一個指令:

Serial.print("Write something"); 

時,要被打印的字符串通常被保存在RAM中。如果您的素描在串行監視器上打印了大量內容,則可以輕鬆填充RAM。如果您有免費的Flash內存空間​​,你可以很容易地表明,該字符串必須使用語法被保存在FLASH:

Serial.print(F("Write something that is stored in FLASH")); 

不過,我只有壞運氣得到這個編譯。

#include <avr/pgmspace.h> 
static const struct {short cmd; const char *txt;} cmds[] = { 
    {2, F("Hi")}, 
}; 

它抱怨與

t.c:3: error: initializer element is not constant 
{2, F("hi")}, 
^ 
t.c:3: error: (near initialization for 'cmds[0].txt') 
exit status 1 
initializer element is not constant 

沒有F宏,它編譯就好了。

{2, "Hi"}, 

有沒有人有經驗得到這個工作?我喜歡10K的字符串,我想進入程序空間。

回答

1

F宏只能用於代碼的可執行部分,而不能用於變量定義。由於結構成員不能具有PROGMEM屬性,因此必須分兩步完成:在PROGMEM中聲明每個文本字符串,然後在結構中使用PROGMEM地址。

結構數組也可以在PROGMEM中。

static const char cmd_0_txt[] PROGMEM = "Hello"; 
static const char cmd_1_txt[] PROGMEM = "World"; 

struct cmd_t {short cmd; const char *txt; }; // the struct type 

// An array of structs in PROGMEM 
static const cmd_t cmds[] PROGMEM = { 
    {2, cmd_0_txt}, 
    {2, cmd_1_txt}, 
}; 

void setup() 
{ 
    Serial.begin(9600); 
    Serial.println(F("Test")); 

    for (uint8_t i=0; i < sizeof(cmds)/sizeof(cmds[0]); i++) { 

    // First, read the PROGMEM txt member (a pointer to the text) 
    const char *ptr = (const char *) pgm_read_word(&cmds[i].txt); // cast required 

    // Next, read each text character from that PROGMEM location 
    for (;;) { 
     char c = pgm_read_byte(ptr++); 
     if (!c) 
     break; 
     Serial.print(c); 
    } 
    Serial.println(); 
    } 
} 

void loop() 
{} 
+0

我想我對宏觀的預期太多了。這是將字符串放在程序存儲器中,並將指針指向數據。考慮到命令表的大小,我想我可能不得不做一些狡猾的「包含兩次」不同的宏定義,以達到預期的結果。謝謝你的一個方向。 – wallyk

+0

但是你不在變量定義區使用它嗎?你有什麼和我有什麼關鍵的區別? – wallyk

+1

這不是一個變量定義:'Serial.println(F(「Test」));'這是我的例子中唯一使用F宏的地方。 PROGMEM屬性可以在幾個地方使用,但F宏被限制爲可執行的代碼行。 –

相關問題