www.mikrocontroller.net

Forum: Compiler & IDEs Struct-Array im EEprom sortiert ausgeben


Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich habe folgendes Problem:
Ich möchte ein struct Array ,welches im EEprom liegt, sortiert ausgeben.
Die Sortierung soll anhand des "filenames" erfolgen.
Mit Daten die nicht im EEprom liegen funktioniert es, so leider nicht.

Die Ausgabe liefert mir nur Müll.
Kann mir jemand einen Rat geben wo der Fehler liegt?

 typedef struct 
{
  char  filename [13];  
  char  .....
  Int   ....
} struct_Name;
 
 struct_Name  struct_name_EE[6] EEMEM;
 


char* Index[6];

int Compare( const void* Arg1, const void* Arg2 )
  {
    char* pString1 = *(char**) Arg1;
    char* pString2 = *(char**) Arg2;
  
    return strcmp( pString1, pString2 );
  }

int i;
  
  for( i = 0; i < 6; ++i )
    {Index[i] = struct_name_EE[i].filename;}

 

  qsort( Index, 6, sizeof *Index, Compare );

  for( i = 0; i < 6; ++i )
    {uart_puts(Index[i]);}

Mfg

Frank

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Compiler? Controller?

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry,
Controller: ATmega128

Compiler: avr-gcc (GCC) 4.2.2

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>     {Index[i] = struct_name_EE[i].filename;}
> ...
>   qsort( Index, 6, sizeof *Index, Compare );

Du kannst nicht direkt auf Daten im EEPROM zugreifen, du musst sie mit 
den entsprechenden Funktionen dort auslesen.

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...
http://www.nongnu.org/avr-libc/user-manual/group__...

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du meinst mit..
eeprom_read_block(&mybuffer,&struct_name_EE[i],sizeof(struct_Name));
das "normale" EEprom beschreiben und lesen klappt. Ich check einfach 
nicht wie ich die Funktionen einbinden muss. Muss ich den Umweg über 
einen Buffer gehen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank wrote:
> du meinst mit..
>
> eeprom_read_block(&mybuffer,&struct_name_EE[i],sizeof(struct_Name));
> 
> das "normale" EEprom beschreiben und lesen klappt.

Gut.

> Ich check einfach
> nicht wie ich die Funktionen einbinden muss.

Na, zb hier
char* Index[6];

Hier legst du dir ein Array von 6 Pointer an, die auf Texte zeigen 
können.
Und hier
  for( i = 0; i < 6; ++i )
    {Index[i] = struct_name_EE[i].filename;}

befüllst du dieses Array. Jeder einzelne der Index-Pointer zeigt auf 
einen Text. Aber wo sind denn diese Texte? Die liegen doch nach wie vor 
im EEPROM rum. Alles was du dir bisher gemacht hast, sind Verweise, 
wobei jeder Verweis ins EEPROM zeigt.

 Bis hierher ist alles gut

Jetzt kommt die Sortierung.
Du willst deine Verweise so umsortieren, dass man sortiert an die Texte 
rankommt, wenn man nur die Verweise in der richtigen Reihenfolge 
abarbeitet. Dazu genügt es, die Verweise umzuschaufeln. Auch diese Idee 
ist ja an sich nicht schlecht.

Aus

  Index
  +--------------+                  +---------------+
  |    o--------------------------->| "ABCD"        |
  +--------------+                  +---------------+
  |    o--------------------------->| "XYZ"         |
  +--------------+                  +---------------+
  |    o--------------------------->| "IJKL"        |
  +--------------+                  +---------------+
  |    o--------------------------->| "EFGH"        |
  +--------------+                  +---------------+

wird so

  Index
  +--------------+                  +---------------+
  |    o--------------------------->| "ABCD"        |
  +--------------+                  +---------------+
  |    o------------------+    +--->| "XYZ"         |
  +--------------+    +---|----+    +---------------+
  |    o--------------|---|-------->| "IJKL"        |
  +--------------+    |   |         +---------------+
  |    o--------------+   +-------->| "EFGH"        |
  +--------------+                  +---------------+

Sucht man die Texte in der Reihenfolge auf, die über das Index Array 
vorgegeben wird, so sind diese sortiert, ohne dass man die Texte 
umsortieren musste.

Aber: Die Texte liegen nachwievor im EEPROM!

Wenn man an die eigentlichen Texte rann will, muss man die EEPROM 
Funktionen benutzen um sie auszulesen. Die Sortierung von Index (welches 
im SRAM) liegt, hat daran ja nichts geändert.

Daher kann hier
int Compare( const void* Arg1, const void* Arg2 )
  {
    char* pString1 = *(char**) Arg1;
    char* pString2 = *(char**) Arg2;
  
    return strcmp( pString1, pString2 );
  }

der strcmp nicht funktionieren.
Sowohl pString1 als auch pString2 enthalten ja Adressen, die ins EEPROM 
zeigen. Und damit kann strcmp nun mal nichts anfangen! Entweder du 
schreibst dir selbst eine Vergleichsfunktion, die auf Einzelbyte Ebene, 
analog zu strcmp, den Vergleich durchführt, oder du lädst dir zuerst die 
Texte vom EEPROM in temporäre Variablen, die im SRAM liegen (also stink 
normale char-Arrays) und lässt dann strcmp darauf los.

Selbiges hier
  for( i = 0; i < 6; ++i )
    {uart_puts(Index[i]);}

uart_puts erwartet die Texte, die es ausgeben soll im SRAM und nicht im 
EEPROM.


> Muss ich den Umweg über einen Buffer gehen?
Das ist eine Möglichkeit. Aber letztendlich arbeiten alle 
String-Funktionen irgendwann auf Einzelzeichen. uart_puts wird einen 
String ausgeben, indem es jedes einzelne Zeichen über uart_putc ausgibt. 
Zb so
(Ich schreibs jetzt absichtlich in langer Form)
void uart_puts( const char* text )
{
  char c;

  c = *text;             // Zeichen holen
  while( c != '\0' ) {   // war das schon das letzte Zeichen des Strings?
    uart_putc( c );      // Nein:  Zeichen über uart_putc ausgeben
    text++;              //        Adresse zumnächsten Zeichen erhöhen
    c = *text;           //        und das Zeichen von dort holen
  }
}

an 2 Stellen kommt
   c = *text;
vor. Hier wird ein einzelner Character von einer Speicherstelle geholt. 
Die Adresse von der gelesen werden soll, steht in text. Durch die Art 
des Zugriffs (Dereferenzierung mit *) ist klar, dass die Adresse als 
Adresse ins SRAM aufzufassen ist und daher wird auch aus dem SRAM 
gelesen.
Aber: Deine Adresse ist keine SRAM Adresse! Deine Adresse ist eine 
Adresse ins EEPROM. Daher musst du das Zeichen anders besorgen: mittels 
der eeprom_read_byte Funktion.

Der Rest der Ausgabelogik bleibt gleich, lediglich die Art und Weise, 
wie das auszugebende Zeichen besorgt wird ändert sich
void uart_puts_eeprom( const char* text )
{
  char c;

  c = eeprom_read_byte( text );   // Zeichen holen
  while( c != '\0' ) {            // war das schon das letzte Zeichen des Strings?
    uart_putc( c );               // Nein:  Zeichen über uart_putc ausgeben
    text++;                       //        Adresse zumnächsten Zeichen erhöhen
    c = eeprom_read_byte( text ); // Zeichen holen
  }
}

und schon hast du eine Funktion, die wie uart_puts funktioniert, nur 
dass die übergebene Adresse nicht die Adresse eines Strings im SRAM, 
sondern die Adresse eines Strings im EEPROM ist. Perfekt geeignet, um 
hier
  for( i = 0; i < 6; ++i )
    uart_puts_eeprom( Index[i] );

eingesetzt zu werden, denn in Index stehen ja lauter Adressen von Texten 
im EEPROM.

So jetzt bist du drann, dir einen Ersatz für die strcmp Funktion zu 
schreiben, die als Argumente Adressen von Texten im EEPROM erhält.
Überleg dir einfach mal, wie wohl strcmp arbeiten wird. Das formulierst 
du dann in C (und testest es!) und ersetzt danach alle Speicherzugriffe, 
bei denen ein einzelnes Zeichen aus dem Speicher geholt werden muss 
durch die entsprechenden Funktionsaufrufe, die das Zeichen aus dem 
EEPROM anstatt aus dem SRAM holen.

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow! Danke für deine sehr anschauliche und vorallem  sehr ausführliche 
Erklärung! Das muss ich erstmal verdauen.
Gruß Frank

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal ein kleine Frage zum Verständniss..
Wenn ich den Umweg über einen Buffer machen möchte...
Warum liefert mir nachfolgender Code nicht der gewünschten EEprom 
Inhalt?


char buffer[20];

for( i = 0; i < 6; ++i )
   {   eeprom_read_block(&buffer,&Index[i],sizeof(Index[i]));
  uart_puts( buffer );
   }

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1)
"&Index[i]" ist nicht die Adresse, von der aus dem EEPROM gelesen werden 
muss, sondern "Index[i]".

2)
"sizeof(Index[i])" ist 2.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.