【问题标题】:Reading string from struct in Arduino PROGMEM从 Arduino PROGMEM 中的结构读取字符串
【发布时间】:2016-06-13 05:05:51
【问题描述】:

我想从存储在 Arduino PROGMEM 中的结构中读取字符串:

struct commandCode {
   int code;
   const char *name;
};

const PROGMEM commandCode commands[LAST_COMMAND] =  {
   { CMD_DEMO, "DEMO" } ,
   { CMD_STOP, "STOP"} ,
   { CMD_FORWARD, "FORWARD"},
   { CMD_BACKWARD, "BACKWARD"},
   { CMD_TURN_LEFT, "TURN LEFT"},
   { CMD_TURN_RIGHT, "TURN RIGHT"},
   { CMD_WAIT, "WAIT"},
   { CMD_WAIT_DONE, "WAIT DONE"},
};

这段代码可以很好地打印字符串:

void CommandCodes::show() {
    Serial.print(LAST_COMMAND);
    Serial.println(" Comands Defined:");
    for (int i = FIRST_COMMAND; i < LAST_COMMAND; i++) {
        CommandCodes::commandCode cmd = commands[i];
        showCommand(cmd);
    }
}

void CommandCodes::showCommand(commandCode cmd) {
    if (cmd.code > FIRST_COMMAND) {
        Serial.print(F("["));
        Serial.print(cmd.code);
        Serial.print(F("] "));
        Serial.println(cmd.name);
    }

}

这段代码会炸弹并重新启动程序:

const char* CommandCodes::name(int code) {
    for (int i = FIRST_COMMAND; i < LAST_COMMAND; i++) {
        CommandCodes::commandCode cmd = commands[i];
        if (cmd.code == code) {
            return cmd.name;
        }
    }
    return NULL;
}

返回指向cmd.name的指针的代码是什么?

【问题讨论】:

    标签: arduino progmem


    【解决方案1】:

    由于结构只包含一个指针,不包含字符串数据,所以字符串仍然存储在 RAM 中。

    此外,当您访问数据时,您没有从 PROGMEM 读取数据,它在某些情况下工作的事实只是运气,但它仍然不正确。

    要将所有数据放在 PROGMEM 中,您需要在结构内为其分配空间。由于最大的字符串是 11 chars + null 你可以使长度为 12。

    struct commandCode {
      int code;
      const char name[12];
    };
    
    const commandCode commands[] PROGMEM = {
      { CMD_DEMO, "DEMO" } ,
      { CMD_STOP, "STOP"} ,
      { CMD_FORWARD, "FORWARD"},
      { CMD_BACKWARD, "BACKWARD"},
      { CMD_TURN_LEFT, "TURN LEFT"},
      { CMD_TURN_RIGHT, "TURN RIGHT"},
      { CMD_WAIT, "WAIT"},
      { CMD_WAIT_DONE, "WAIT DONE"}
    }
    

    由于每个结构的内部都在 PROGMEM 中,您需要使用特殊函数来读取它们。你不能直接阅读它们。

    这也意味着您不能像以前那样复制项目: CommandCodes::commandCode cmd = commands[i];

    但是您可以使用参考。 const commandCode &amp;cmd = commands[i];

    但是,就像我上面提到的,引用结构的元素仍然需要正确访问。

    对于整数,您需要使用pgm_read_word。对于字符串,您可以欺骗 Serial 类在它处理 Flash 字符串时为您打印它(就像您使用 F() 宏的地方一样)。这可以通过将指针转换为 const __FlashStringHelper* 来完成。

    这是一个工作草图,展示了如何正确访问每个部分。给它一个测试,试着弄清楚我做了什么。我相信你会有一些问题,所以只需将它们添加到这个答案的 cmets 中,我会为你更新我的答案。

    struct commandCode {
      int code;
      const char name[12];
    };
    
    enum COMMANDS{
      CMD_DEMO,
      CMD_STOP,
      CMD_FORWARD,
      CMD_BACKWARD,
      CMD_TURN_LEFT,
      CMD_TURN_RIGHT,
      CMD_WAIT,
      CMD_WAIT_DONE,
    };
    
    const commandCode commands[] PROGMEM = {
      { CMD_DEMO, "DEMO" } ,
      { CMD_STOP, "STOP"} ,
      { CMD_FORWARD, "FORWARD"},
      { CMD_BACKWARD, "BACKWARD"},
      { CMD_TURN_LEFT, "TURN LEFT"},
      { CMD_TURN_RIGHT, "TURN RIGHT"},
      { CMD_WAIT, "WAIT"},
      { CMD_WAIT_DONE, "WAIT DONE"}
    };
    
    #define FIRST_COMMAND 0
    #define LAST_COMMAND sizeof(commands) / sizeof(*commands)
    #define FSH (const __FlashStringHelper*)  //A helper to allow printing the PROGMEM strings.
    
    void show() {
        for (int i = FIRST_COMMAND; i < LAST_COMMAND; i++) {
            const commandCode &cmd = commands[i];
            showCommand(cmd);
        }
    }
    
    void showCommand(const commandCode &cmd) {
        if ( pgm_read_word( &cmd.code ) > FIRST_COMMAND) {
            Serial.print(F("["));
            Serial.print( pgm_read_word( &cmd.code ) );
            Serial.print(F("] "));
            Serial.println( FSH( cmd.name ) );
        }
    }
    
    const char* name(int code) {
        for (int i = FIRST_COMMAND; i < LAST_COMMAND; i++) {
            const commandCode &cmd = commands[i];
            if (pgm_read_word(&cmd.code) == code) {
                return cmd.name; //As cmd.name resolves to a pointer it can be passed back as is.
                //However to use the 'pointed to data' it will have to be accessed properly.
            }
        }
        return NULL;
    }
    
    void setup() {
      Serial.begin(9600);
    
      Serial.println("Show test");
      show();
    
      Serial.println("Name test");
      for (int i = FIRST_COMMAND; i < LAST_COMMAND; i++) {
        Serial.println( FSH( name(i) ) );
      }
      Serial.println("Done");
    }
    
    void loop() {}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多