Hallo zusammen, ich versuche gerade, diverse char Arrays mit verschiedener Länge vom Flash ins EEprom zu verlagern um Flash Speicher zu sparen ( Atmega48 ). Die char Arrays werden im Programm nur gelesen. Die char Arrays gebe ich dann auf die UART Schnittstelle aus. Bei der Ausgabe muss ich allerdings wissen, wie lang die einzelnen Arrays sind. Leider funktioniert sizeof() nicht, das gibt immer 2 als Rückgabewert für die im EEprom gespeicherten Arrays aus. Kann ich die Länge der Arrays irgendwie per Software feststellen ? Gruß, dasrotemopped
sizeof funktioniert korrekt; Du übergibst einen Pointer, und sizeof gibt Dir dessen Größe zurück. Und die ist auf einem AVR nunmal 2. Um die Größe eines Arrays zu bestimmen, sind andere Mechanismen anzuwenden, und das ist unabhängig davon, ob die Arrays nun im EEPROM oder im RAM stehen. Es ist anzunehmen, daß Deine "char Arrays" Strings sind - die übliche Funktion zur Stringlängenbestimmung ist strlen, wobei Du aufgrund der vergurkten Architektur des AVR wohl auf strlen_P zurückgreifen musst.
Rufus Τ. Firefly schrieb: > Es ist anzunehmen, daß Deine "char Arrays" Strings sind - die übliche > Funktion zur Stringlängenbestimmung ist strlen, wobei Du aufgrund der > vergurkten Architektur des AVR wohl auf strlen_P zurückgreifen musst. Ich geh auch mal davon aus, dass wir hier in Wirklichkeit über Strings reden. > Die char Arrays gebe ich dann auf die UART Schnittstelle aus. > Bei der Ausgabe muss ich allerdings wissen, wie lang die einzelnen > Arrays sind. Nö, muss man ncht. Die Länge von Strings ergibt sich automatisch durch das abschliessende '\0' Zeichen. Bei der Behandlung von Strings, insbesonderer bei der Ausgabe muss man ganz selten die Größe vorab wissen. Im Regelfall gibt man einfach aus, bis man auf das \0 Zeichen stößt und das wars. Kein Mensch muss vorher wissen wie lang der String dabei ist.
Rufus Τ. Firefly schrieb: > Es ist anzunehmen, daß Deine "char Arrays" Strings sind - die übliche > Funktion zur Stringlängenbestimmung ist strlen, wobei Du aufgrund der > vergurkten Architektur des AVR wohl auf strlen_P zurückgreifen musst. Das wird bei einem String im EEPROM aber auch nicht funktionieren. Das EEPROM liegt ja nochmal in einem anderen "Adressbereich". Ich sehe auch keinen Grund warum sizeof() nicht funktionieren sollte. Wahrscheinlich wird der Operator eben, wie schon vermutet, auf die falsche Variable angewendet nämlich auf einen Pointer und nicht auf das Array selbst. Matthias
dasrotemopped schrieb: > Die char Arrays gebe ich > dann auf die UART Schnittstelle aus. Bei der Ausgabe muss ich allerdings > wissen, wie lang die einzelnen Arrays sind. Ausgabe bis Zeichen gleich '\0' NUL-Byte ist, dann stop. Spart ne Menge Probleme. :-)
Floh schrieb: > dasrotemopped schrieb: >> Die char Arrays gebe ich >> dann auf die UART Schnittstelle aus. Bei der Ausgabe muss ich allerdings >> wissen, wie lang die einzelnen Arrays sind. > > Ausgabe bis Zeichen gleich '\0' NUL-Byte ist, dann stop. > Spart ne Menge Probleme. :-) Geht aber schon bei rechtsbündiger Ausgabe nicht mehr so einfach. Matthias
Hier habe ich mal den C-Code zur Ansicht : char r_on[] ="ON"; char r_off[] ="OFF"; char relais[] ="Relais already "; char def[] ="no op"; char help_0[] EEMEM ="0 - Relais ausschalten"; char help_1[] EEMEM ="1 - Relais einschalten"; char help_2[] EEMEM ="l - Loop starten"; char help_3[] EEMEM ="s - shot (nur mit 230V)"; char help_4[] EEMEM ="b - break (nur mit 230V & Relais ein)"; char help_5[] EEMEM ="x - break (nur mit 230V & Relais ein) after 2 sec off"; char help_6[] EEMEM ="h - Hilfe"; void send_eemem_string(char a[]) { uint8_t cnt=0; /* while(a[cnt]!=(char)0){ uart_send_byte(eeprom_read_byte(&a[cnt])); cnt++; } */ for(uint8_t x=0;x<22;x++) { uart_send_byte(eeprom_read_byte(&a[x])); } } void relais_on() { if((PORTC &~ 0b00010000 )){ PORTC = 0b00010000; } else{ send_eemem_string(help_1); uart_send_lf(); uart_send_string(relais); } uart_send_string(r_on); uart_send_lf(); } Probleme macht halt die send_eemem_string() Routine, die uart_send_string() Routine ist nur eine mehrfach aufgerufene uart_send_byte() Routine. Auf das NUL Byte prüfen hat schon mal nicht funktioniert, mit strlen und strlen_P auch nicht. Vielleicht mache ich mir ein Hilfsarray mit den Stringlängen, das sollte bei statischen Strings noch praktikabel sein. Oder hat noch jemand eine Idee ? Gruß, dasrotemopped
Wieso holst Du dir das EEPROM-Array nicht als Block wie im AVR-GCC Tutorial beschrieben ?
1 | eeprom_read_block(myByteBuffer,eeFooByteArray1,sizeof(myByteBuffer)); |
dasrotemopped schrieb: > Auf das NUL Byte prüfen hat schon mal nicht funktioniert, > mit strlen und strlen_P auch nicht. deutet darauf hin dass kein Nul-Byte hinterlegt wird. Beende deine Texte mal mit \0, also z.b. dasrotemopped schrieb: > char help_0[] EEMEM ="0 - Relais ausschalten\0"; und tests nochmal aus. :-)
1 | size_t strlen_E(EEMEM char * a) __attribute__((__pure__)); |
2 | size_t strlen_E(EEMEM char * a) { |
3 | size_t l=0; |
4 | while (eeprom_read_byte(a++)) ++l; |
5 | return l; |
6 | }
|
oder so...
dasrotemopped schrieb: > Probleme macht halt die send_eemem_string() Routine, die > uart_send_string() Routine ist nur eine mehrfach aufgerufene > uart_send_byte() Routine. > Auf das NUL Byte prüfen hat schon mal nicht funktioniert, > mit strlen und strlen_P auch nicht. Dann hast du irgendwo einen Fehler gemacht. Es gibt keinen Grund, warum
1 | void send_eemem_string( const char* eString ) |
2 | {
|
3 | char c = eeprom_read_byte( eString++ ); |
4 | |
5 | while( c ) { |
6 | uart_send_byte( c ); |
7 | c = eeprom_read_byte( eString++ ); |
8 | }
|
9 | }
|
nicht funktionieren sollte. Edit: Da haben wirs schon while(a[cnt]!=(char)0){ Du kannst hier natürlich nicht über a[cnt] auf den Character zugreifen. Die Daten liegen im EEPROM! Um an den Character zu kommen, musst du ihn auch mit der Lesefunktion von dort lesen ehe du ihn testen kannst. Genau so, wie du es bei uart_send_byte(eeprom_read_byte(&a[cnt])); richtigerweise getan hast.
Sven schrieb: > Wieso holst Du dir das EEPROM-Array nicht als Block wie im AVR-GCC > Tutorial beschrieben ? > >
1 | eeprom_read_block(myByteBuffer,eeFooByteArray1,sizeof(myByteBuffer)); |
Schlechte Idee. Dazu muss er erst recht wieder die Stringlänge kennen, die er nur erhält indem er den String zuerst einzelzeichenweise durchgeht. Ausserdem braucht man dann einen entsprechend großes Array, in dem der Block zwischengespeichert werden kann.
Floh schrieb: > dasrotemopped schrieb: >> Auf das NUL Byte prüfen hat schon mal nicht funktioniert, >> mit strlen und strlen_P auch nicht. > > deutet darauf hin dass kein Nul-Byte hinterlegt wird. Dann wäre sein Compiler schadhaft.
habe mal die Vorschläge durchprobiert : uint8_t help_L[] EEMEM ={22,22,16,23,37,53,9}; char help_0[] EEMEM ="0 - Relais ausschalten\0"; usw... char help_6[] EEMEM ="h - Hilfe\0"; void send_eemem_string(char a[], uint8_t l) { // funktioniert ! /* char c = eeprom_read_byte( a++ ); while( c ) { uart_send_byte( c ); c = eeprom_read_byte( a++ ); } */ // mit \0 funktioniert die Ausgabe nicht, es fehlen Buchstaben in der Ausgabe uint8_t cnt=0; while( !(strcmp(eeprom_read_byte(&a[cnt]),'\0')) ){ uart_send_byte(eeprom_read_byte(&a[cnt])); cnt++; } // funktioniert ! mit Hilfsarray help_L /* for(uint8_t x=0;x<l;x++) { uart_send_byte(eeprom_read_byte(&a[x])); } */ } Da ich aber jetzt 2 funktionierende Lösung habe würde ich sagen "Mission accomplished !" Danke an alle, dasrotemopped.
dasrotemopped schrieb: > while( !(strcmp(eeprom_read_byte(&a[cnt]),'\0')) ){ Oh Mann. Du kannst doch nicht ein 2 Zeichen mit strcmp vergleichen! strcmp vergleicht Strings und keine Einzelzeichen. Was ist falsch an while( eeprom_read_byte(&a[cnt]) != '\0' ) Zu einfach? Zu banal? Zu simpel? (Jetzt mal von der Tatsache abgesehen, dass es sinnlos ist, zweimal aufwändig dasselbe Zeichen mittels eeprom_read_byte aus dem Eeprom zu lesen) > Da ich aber jetzt 2 funktionierende Lösung habe würde ich sagen "Mission > accomplished !" Nun ja. Deine fehlgeschlagenen Versuche zeigen eigentlich, dass du mit Stringverarbeitung noch sehr weit auf Kriegsfuss stehst. Und deine '2-te funktionierende Lösung' - nope, das willst du nicht wirklich machen. Das ist ausser kompliziert und fehleranfällig nur noch kompliziert und fehleranfällig. Lerne Stringverarbeitung und fang an dich von der Sichtweise zu lösen, dass man auf die Character eines Strings per Array-Zugriff rankommt. Manchmal ist das eine gute Sichtweise, aber meistens ist die Sichtweise besser und einfacher, nach der man einen Pointer auf den Anfang eines Strings hat und mit dem Pointer durch den String durchgeht um damit Zeichen für Zeichen zu holen. while( *string ) { Zeichen = *string; mach was mit Zeichen string++; } In deinem Fall kannst du natürlich nicht die Pointer Dereferenzierung benutzen, also den *. Stattdessen wird die Zugriffsfunktion, in deinem Fall für EEPROM benutzt, die den Pointer 'dereferenziert' und das Zeichen holt.
mit > while( eeprom_read_byte(&a[cnt]) != '\0' ) funktioniert jetzt auch die 3. Lösung Wie bekomme ich jetzt noch die Compiler Warnung ../LineSyncer.c:43: warning: pointer targets in passing argument 1 of '__eerd_byte_m48' differ in signedness weg ? Diese Warnung kommt bei allen Lösungen durch "eeprom_read_byte(&a[cnt]". Gruß, dasrotemopped. @ Karl Heinz : wenn ich schon perfekt C könnte müsste ich keine Fragen stellen. Bin mit Sicherheit nur ambitionierter Anfänger mit dem AVR Studio und C auf Atmel.
dasrotemopped schrieb: > mit >> while( eeprom_read_byte(&a[cnt]) != '\0' ) > > funktioniert jetzt auch die 3. Lösung > > Wie bekomme ich jetzt noch die Compiler Warnung > > ../LineSyncer.c:43: warning: pointer targets in passing argument 1 of > '__eerd_byte_m48' differ in signedness Sieh beim Prototypen von eeprom_read_byte nach, was es erwartet: einen Pointer auf signed char oder einen Pointer auf unsigned char. An dieser Stelle wissen wir, dass es ok ist, wenn der Pointer auf das jeweils falsche zeigt. Du willst nur das Byte haben und es spielt keine Rolle, ob eeprom_read_byte den Pointer nun auf unsigned oder auf signed char haben will, weil es mit dem Byte an dieser Stelle ja sowieso nichts macht, ausser es zurückzugeben. WEnn du weist, welchen Pointer eeprom_read_byte haben will, dann castest du dir das dann einfach zurecht. > @ Karl Heinz : wenn ich schon perfekt C könnte müsste ich keine Fragen > stellen. Darum gehts nicht. Fragen ist ok. Nur einige Fehler sind so banal (wie zb nicht zwischen Einzelzeichen und Strings zu unterscheiden und str... zu verwenden, wenn es einfach nicht angebracht ist), dass sie schon weh tun. > Bin mit Sicherheit nur ambitionierter Anfänger mit dem AVR > Studio und C auf Atmel. Genau deswegen, ist ein gern gegebener und eigentlich sehr guter Rat: Mach deine ersten Schritte mit C mit einem guten Buch und auf dem PC. Arbeite das erste Drittel des Buches auf einem PC durch. Alles, bis dann im Buch File-Verarbeitung beginnt. Also insbesondere auch Stringverarbeitung und einfache Pointer-Dinge, die kommen normalerweise im ersten Drittel vor. Dann hast du ein gutes Rüstzeug um auf einen µC zu wechseln und dich dann mit den µC-spezifischen Dingen rumzuschlagen. PC deswegen, weil: * Alles so funktioniert wie es im Buch beschrieben ist. * Du eine Konsolenausgabe hast, die von Anfang an funktioniert und einem das Leben für Hilfs und Zwischenausgaben zur Fehlersuche erleichtert * Man einen richtigen Debugger zur Verfügung hat um dem Programm zuzusehen und auf die Finger zu sehen, während es läuft. Der Simulator um AVR-Studio ist zwar nicht schlecht, aber im Vergleich zu den Möglichkeiten am PC, ist er nur ein müder Abklatsch.
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.