- LiTime Speicher und Akkus         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: Wie einen Datensatz in C passend ablegen?

  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    17.08.2004
    Beiträge
    1.065

    Wie einen Datensatz in C passend ablegen?

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Moin zusammen.
    Ich möchte eine Datenstruktur in einem Atmega168 verwenden, es geht dabei um Sternenkarten, die ich nach der Form "1. Byte Index, 2.-21. Byte Name, 22.-38. Byte Daten" aufgebaut sind, es gibt ingesamt 22 Einträge, die ich am liebsten mit einer Variable zugreifen will. Zuerst hab ich an ein Array einer Struktur gedacht sozusagen:
    typdef struct Karten{...};
    Karten Sternbilder[22];
    Dabei machte mir der GCC aber irgendwelche Striche durch die Rechnung. Dann wollte ich es als Array mit 22x37 Zeichen speichern, sodass ich die Karte mit der X-Koordinate auswähle, das Objekt dann mit der Y-Koordinate.
    Das ganze sind Konstanten, ich benötige noch 2 dieser Strukturen als Variablen (ein Abbild der angezeigten Karte, ein Buffer).
    Die Variablen lege ich natürlich im RAM ab, aber was mache ich am besten mit den Konstanten? Das EEPROM ist für den kompletten Datensatz zu klein, würde ich alles in den RAM legen und initialisieren lassen, wäre der schon damit zu 76% belegt.
    Wie kann ich sowas schön im Flash ablegen und zugreifen?
    Per Assembler wäre das kein Problem, damit weiß ich, was ich machen muss. Aber in C fehlt mir der beste Ansatz.
    MfG
    Björn

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Was in der Richtung?
    Code:
    #include <avr/pgmspace.h>
    
    typedef struct
    {
       foo1_t foo1;
       foo2_t foo2;
       ...
    } karte_t;
    
    
    const karte_t karten[] PROGMEM =
    {
       { .foo1 = ..., .foo2 = ...},
       { .foo1 = ...},
       ...
    }
    
    karte_t k_buf;
    
    void foo (void)
    {
       uint8_t i;
       for (i=0; i < sizeof (karten) / sizeof (karte_t); i++)
       {
           memcpy_P (& k_buf, & karten[i], sizeof (karte_t));
       }
    }
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    17.08.2004
    Beiträge
    1.065
    Ah, ich glaub schon. Eine bessere Lösung gibts wohl nicht? Das einzige, was mich stört, ist, dass man ne spezielle Funktion braucht um die Werte abzuholen, aber das ist ja kein Problem. Ich hab parallel das Tutorial bei Mikrocontroller.net gefunden, in dem die es auch so machen. kannst du das Initialisieren der const struct karten[] nochmal genauer erläutern? das macht dann der Compiler vor dem brennen, nicht das Programm richtig? Ich hatte mit der Initialisierung des Structs Probleme.

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    17.08.2004
    Beiträge
    1.065
    Ok, das hab ich soweit hinbekommen, noch eine Frage:

    Code:
    typedef struct
    {
    unsigned char Name[Name_Length];
    unsigned char Bitfield[Daten_Length];
    } Daten;
    
    Daten Buffer,Image;
    Wie weise ich einem Element vom typ struct an der stelle Name einen String zu, bzw eine Reihe von Chars. Bei der Initialisierung hab ich das geschaft, aber nun möchte ich
    Destination.Name[]="Zuweisungstext";
    machen. Er sagt mir ../Sternenhimmel.c:92: error: incompatible types in assignment
    als Fehler.
    Wie bekomme ich sonst so eine Zuweisung? ich möchte ungern 20 Zuweisungen hintereinander schreiben, nur wenn nicht anders geht.


    Ich habe mir nun nach etwas Probieren eine weitere const char[] deklariert, die im Flash liegt und nun einfach per for-Schleife zugewiesen wird.

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Der Initializer enthält für jede Komponente einen Wert, wobei Unterkomonenten in {} gefasst werden. Zusätzlich kann man mit .name=...explizit eine Komponente nennen, ist aber "nur" GNU-C und kein ANSI-C. Ansonsten müssen die Initializer in der richtigen Reihenfolge stehen. Inits in einem Array kann man auch angeben mit zB [0]=...

    Strings zu initialisieren ist etwas lästig wenn sie im Flash liegen sollen, weil das Makro PSTR eine lokale Variable braucht.

    Beispiele sind etwa in https://www.roboternetz.de/wissen/in...#Sprungtabelle

    Die Daten, die im Flash bleiben, erhalten das Attribut progmem und landen in der speziellen Section .progmem, die vom Startup-Code der vor main() läuft ins RAM kopiert werden.

    https://www.roboternetz.de/wissen/in...terna#Sections
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    17.08.2004
    Beiträge
    1.065
    Moment, würde das nicht bedeuten, dass diese Geschichte doch wieder den SRAM zumüllt? Der Compiler zeigt aber keinen gestiegenen Bedarf an.
    Das Verhalten hab ich gesehen, wenn ich eine normale Variable initialisiert habe, also das erscheinen im SRAM, mit der PROGMEM-Attribut passiert das nichtmehr.

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    ah sorry, fehler meinerseits. Das so besprochene initialisieren .pgmspace -> .data betrifft natürlich nur normale variablen.
    Disclaimer: none. Sue me.

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    17.08.2004
    Beiträge
    1.065
    Moin, hier nochmal ein Nachsatz:
    Ich habe nun einen Quellcode geschrieben und in mein Hauptprogramm eingebunden, in der Header-Datei steht
    Code:
    #define Name_Length		20	//Länge des Namen der Sternbildstruktur
    #define Daten_Length	16	//Länge der Bitfield-Variablen der Sternbildstruktur
    
    //Struktur der Sternenbilder
    typedef struct
    {
    unsigned char Name[Name_Length];
    unsigned char Bitfield[Daten_Length];
    } Daten;
    
    //Hilfsvariablen, Buffer zum Arbeiten, Image als Kopie des Hardwarezustands
    Daten Buffer;
    Daten Image;
    Ich habe nun eine Funktion geschrieben, die aus einer anderen Struktur im Flash die Daten in eine Variable vom Typ Daten schreiben soll:
    Code:
    //Fügt die Konstanten für das Sternbild an stelle Source_Address in die Variable Destination ein
    void Set_Image (volatile Daten Destination, unsigned char Source_Address)
    {
    	unsigned char i=0;
    	
    	for (i=0;i<Name_Length;i++)
    	{
    		Destination.Name[i] = pgm_read_byte(&Sternbilder[Source_Address].Name[i]);
    	}
    	for (i=0;i<Daten_Length;i++)
    	{
    		Destination.Bitfield[i] = pgm_read_byte(&Sternbilder[Source_Address].Bitfield[i]);
    	}
    }
    Wenn ich das nun im Hauptprogramm so aufrufe:
    Set_Image(Image,0);
    Set_Image(Buffer,3);
    Dann läuft das erste schon richtig ab, aber er schreibt an der zweiten Stelle in den gleichen Speicherbereich, als ob Image und Buffer identisch wären!

    Woran könnte das liegen bzw wie bekomm ichs weg?

    Mir fiel noch auf: Halte ich den Cursor über dem Funktionsnamen, so blendet AVRStudio ein, dass Image die SRAM -Adresse 0x101 besitzt, Buffer 0x125. Die Daten werden jedoch im SRAM ab der Stelle 0x4DA abgelegt, und dort auch überschrieben. Der Inhalt der SRAM -Variablen 0x101-0x125 ist und bleibt 0

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Destination wird per Wert übergeben, du schreibst nur in eine lokale Kopie.

    Code:
    void Set_Image (volatile Daten * dest, unsigned char Source_Address)
    {
       unsigned char i=0;
       
       for (i=0;i<Name_Length;i++)
       {
          dest->Name[i] = pgm_read_byte(&Sternbilder[Source_Address].Name[i]);
       }
       for (i=0;i<Daten_Length;i++)
       {
          dest->Bitfield[i] = pgm_read_byte(&Sternbilder[Source_Address].Bitfield[i]);
       } 
    }
    Disclaimer: none. Sue me.

  10. #10
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    17.08.2004
    Beiträge
    1.065
    Ah, sowas hab ich mir schon gedacht, hab auch einiges probiert um das zu lösen. Übergabe von &Image und dann auch * im Prototyp, allerdings kannte ich den -> operator nicht, was ist der unterschied zu dem und meine *dest.Name[i]??
    Kannst du mir das erläutern?
    Schonmal besten Dank, klappt jetzt endlich

    Wenn ichs richtig verstehe, dann kann ich pointer auf variablen zeigen lassen,
    z.b. eine Variable vom Typ int oder Typ struct Daten.
    Während ich bei nem Pointer auf ne einfache Variable direkt auf den Wert zugreifen kann, muss ich das element bei einer komplexeren Variable, meiner Struct, erst noch mit dem Pfeil eindeutig identifizieren.. dh ich benutze * um mein Array aus Structs nach einer bestimmten zu durchsuchen und dann -> um das Element der per Pointer ausgewählten Struct zu nutzen. richtig?

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test