2016-06-13 1 views
0

Je veux lire une chaîne à partir d'une struct stockée dans Arduino PROGMEM:Lecture chaîne de struct 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"}, 
}; 

Ce code imprime la chaîne très bien:

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); 
    } 

} 

Ce bombes code et redémarre le programme:

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; 
} 

Quel est le code pour renvoyer un pointeur vers cmd.name?

Répondre

0

Comme la structure contient uniquement un pointeur, pas les données de chaîne, les chaînes sont toujours stockées dans la RAM.

De même que vous ne lisez pas depuis PROGMEM lorsque vous accédez aux données, le fait qu'il fonctionne dans certaines situations n'est que de la chance, mais toujours incorrect.

Pour placer toutes les données dans PROGMEM, vous devez allouer de l'espace dans la structure pour cela. Comme la plus grande chaîne est de 11 caractères + null vous pouvez faire la longueur 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"} 
} 

Comme les entrailles de chaque struct sont en PROGMEM vous devez les lire à l'aide des fonctions spéciales. Vous ne pouvez pas les lire directement.

Cela signifie également que vous ne pouvez pas copier un élément comme vous l'avez fait:
CommandCodes::commandCode cmd = commands[i];

Mais vous pouvez utiliser une référence. Cependant, comme je l'ai mentionné ci-dessus, les éléments de la structure référencée doivent toujours être accédés correctement.

Pour un nombre entier, vous devez utiliser pgm_read_word. Pour les chaînes, vous pouvez tromper la classe Serial en l'imprimant pour vous car elle gère les chaînes flash (comme lorsque vous utilisez la macro F()). Cela peut être fait en passant le pointeur sur un const __FlashStringHelper*.

Voici un croquis de travail montrant comment accéder correctement à chaque pièce. Donnez-lui un test et essayez de comprendre ce que j'ai fait. Je suis sûr que vous aurez des questions, alors ajoutez-les aux commentaires de cette réponse et je mettrai à jour ma réponse pour vous.

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() {}