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


von Frank (Gast)


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?

1
 typedef struct 
2
{
3
  char  filename [13];  
4
  char  .....
5
  Int   ....
6
} struct_Name;
7
 
8
 struct_Name  struct_name_EE[6] EEMEM;
9
 
10
11
12
char* Index[6];
13
14
int Compare( const void* Arg1, const void* Arg2 )
15
  {
16
    char* pString1 = *(char**) Arg1;
17
    char* pString2 = *(char**) Arg2;
18
  
19
    return strcmp( pString1, pString2 );
20
  }
21
22
int i;
23
  
24
  for( i = 0; i < 6; ++i )
25
    {Index[i] = struct_name_EE[i].filename;}
26
27
 
28
29
  qsort( Index, 6, sizeof *Index, Compare );
30
31
  for( i = 0; i < 6; ++i )
32
    {uart_puts(Index[i]);}

Mfg

Frank

von Matthias (Gast)


Lesenswert?

Compiler? Controller?

von Frank (Gast)


Lesenswert?

Sorry,
Controller: ATmega128

Compiler: avr-gcc (GCC) 4.2.2

von Stefan E. (sternst)


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-Tutorial#EEPROM
http://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html

von Frank (Gast)


Lesenswert?

du meinst mit..
1
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?

von Karl H. (kbuchegg)


Lesenswert?

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

Gut.

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

Na, zb hier
1
char* Index[6];

Hier legst du dir ein Array von 6 Pointer an, die auf Texte zeigen 
können.
Und hier
1
  for( i = 0; i < 6; ++i )
2
    {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
1
int Compare( const void* Arg1, const void* Arg2 )
2
  {
3
    char* pString1 = *(char**) Arg1;
4
    char* pString2 = *(char**) Arg2;
5
  
6
    return strcmp( pString1, pString2 );
7
  }

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
1
  for( i = 0; i < 6; ++i )
2
    {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)
1
void uart_puts( const char* text )
2
{
3
  char c;
4
5
  c = *text;             // Zeichen holen
6
  while( c != '\0' ) {   // war das schon das letzte Zeichen des Strings?
7
    uart_putc( c );      // Nein:  Zeichen über uart_putc ausgeben
8
    text++;              //        Adresse zumnächsten Zeichen erhöhen
9
    c = *text;           //        und das Zeichen von dort holen
10
  }
11
}

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
1
void uart_puts_eeprom( const char* text )
2
{
3
  char c;
4
5
  c = eeprom_read_byte( text );   // Zeichen holen
6
  while( c != '\0' ) {            // war das schon das letzte Zeichen des Strings?
7
    uart_putc( c );               // Nein:  Zeichen über uart_putc ausgeben
8
    text++;                       //        Adresse zumnächsten Zeichen erhöhen
9
    c = eeprom_read_byte( text ); // Zeichen holen
10
  }
11
}

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
1
  for( i = 0; i < 6; ++i )
2
    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.

von Frank (Gast)


Lesenswert?

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

von Frank (Gast)


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?

1
char buffer[20];
2
3
for( i = 0; i < 6; ++i )
4
   {   eeprom_read_block(&buffer,&Index[i],sizeof(Index[i]));
5
  uart_puts( buffer );
6
   }

von Stefan E. (sternst)


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.

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
Noch kein Account? Hier anmelden.