Hallo! Ich habe da ein dickes Problem im GCC AVR gefunden. Ich will einen String nach einer Reihe von Schlüsselwörtern durchsuchen. Wenn die Schlüsselwörtern im Ram stehen und unter verwendung von strcasecmp geht das auch wunderbar. Kommen die Schlüsselwörter aus dem Flash mit strcasecmp_P geht das nur wenn der index in Strings[] eine konstante ist. Kennt da jemand einen workaround? #include <avr/pgmspace.h> #include <stdio.h> #include <avr/iom128.h> #include <avr/interrupt.h> #include <string.h> #include <stdlib.h> #include <ctype.h> int16_t indx; char cliline_ram[] = "WRITE"; const char PROGMEM Str1[] = "HELP"; const char PROGMEM Str2[] = "INFO"; const char PROGMEM Str3[] = "WRITE"; const char PROGMEM Str4[] = "READ"; const char PROGMEM Str5[] = "POLL"; const char PROGMEM Str6[] = "DEFINE"; const char PROGMEM Str7[] = "SCAN"; const char PROGMEM Str8[] = "IPADDR"; const char PROGMEM Str9[] = "IPMASK"; const char PROGMEM Str10[] = "GATEWAY"; const char PROGMEM Str11[] = "PORT"; const char* PROGMEM Strings[] = { Str1, Str2,Str3 ,Str4 ,Str5 ,Str6 ,Str7 ,Str8,Str9,Str10,Str11 }; int16_t gr; uint8_t i; int16_t main(void) { indx =strcasecmp_P((const char*)&cliline_ram,Strings[0]); //nicht gefunden indx =strcasecmp_P((const char*)&cliline_ram,Strings[1]); //nicht gefunden indx =strcasecmp_P((const char*)&cliline_ram,Strings[2]); //gefunden ok i=2; indx =strcasecmp_P((const char*)&cliline_ram,Strings[i]); //geht nicht gr = sizeof(Strings) / 2; for (i=0;i<gr; i++) { indx =strcasecmp_P((const char*)&cliline_ram,Strings[i]); //geht nicht indx =strcasecmp_P((const char*)&cliline_ram,Strings[2]); //geht } return 0; }
hbloed schrieb: > indx =strcasecmp_P((const char*)&cliline_ram,Strings[0]); //nicht > gefunden Hier liegt der Fehler. Du kannst nicht einfach Strings[0] benutzen. Denn Strings liegt je seinerseits selbst wieder im Flash. Zugriffe darauf müssen daher über die pgm_read.... Funktionen geführt werden. Ist der Index eine Konstante, dann rettet dich der Optimizer, der den ZUgriff auf Strings[0] durch den Inhalt, nämlich der Adresse von Str1, ersetzt, die er kennt. Bei Strings[i] geht das dann klarerweise nicht mehr. > Ich habe da ein dickes Problem im GCC AVR gefunden. Wider nix. War doch nur ein Programmierfehler. (Das Umcasten von cliline_ram auf const char* kannst du dir sparen. Das const ist an dieser Stelle die Zusicherung der Funktion, dass sie den String nicht verändern wird. Wenn eine Funktion diese Zusicherung macht, kann man daher der Funktion sowohl konstante Texte als auch nicht konstante Texte übergeben. Das weiß auch der Compiler)
So einfach ist es nicht, nicht gefunden ist in dem Fall i.o. weil der String ja nicht übereinstimmt. die Zeilen wo ght nicht steht sind das Problem: indx =strcasecmp_P((const char*)&cliline_ram,Strings[i]); //geht nicht indx =strcasecmp_P((const char*)&cliline_ram,Strings[2]); //geht Wenn ich über i zugreife geht es nicht, bei zugriff über [2] ist es ok. Das mit dem pgm_read bring nix, hab ich auch schon probiert.
hbloed schrieb: > Das mit dem pgm_read bring nix, hab ich auch schon probiert. Dann probier's beim nächsten Mal richtig, dann geht's. Ob es allerdings wirklich lohnt, die paar Byte an Zeigern für den Stress mit dem notwendigen pgm_read_word() tatsächlich noch in den Flash zu verlagern, musst du selbst wissen. Wenn du dein PROGMEM in der Deklaration von Strings[] einfach streichst, funktioniert der ganze Krempel auf Anhieb.
hbloed schrieb: > So einfach ist es nicht, Doch. Ist es. > Wenn ich über i zugreife geht es nicht, bei zugriff über [2] ist es ok. Und ich hab (zumindest versucht) dir erklärt, warum das so ist: Das Verhalten ist deswegen so, weil dir der Optimizer einen eigentlich falschen Code durch die Optimierung ungewollt so zurechtbiegt, dass er wieder funktioniert. > Das mit dem pgm_read bring nix, hab ich auch schon probiert. Dann hast du das falsch eingebaut. Da liegt beim Code im Eröffnungsposting der Knackpunkt. Machs richtig und es wird in allen Fällen funktionieren. Wenn du mittels PROGMEM etwas ins Flash verlagerst, dann geht der Zugriff auf den Inhalt immer über eine der pgm_read Funktionen, der man die Adresse im Flash übergibt, an der die gewünschten Daten liegen. int PROGMEM i = 5; i liegt im Flash, also führt der Zugriff zum Auslesen von i über die pgm_read Funktionen const char* Strings[] PROGMEM = { .... Strings liegt im Flash, also führt der Zugriff zum Auslesen des Inhalts eines Array Elements über die pgm_read Funktionen. Du willst hier den Inhalt des i-ten Array elements von Strings benutzen strcasecmp_P((const char*)&cliline_ram,Strings[i]); also musst du pgm_read benutzen und dieser Funktion die Adresse des i-ten Arrayelements in Strings übergeben.
1 | strcasecmp_P( cliline_ram, (const char*)pgm_read_word( &Strings[i] ) ); |
So einfach ist das.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.