Forum: Compiler & IDEs EEPROM schreiben, lesen


von Dennis (Gast)


Lesenswert?

Hallo alle zusammen,

bräuchte kurz mal Hilfe.

Und zwar möchte ich einige Daten in den EEPROM Speicher schreiben, damit 
die nach dem Neustart noch ausgelesen werden könnten. Nur habe ich 
Schwierigkeiten mit der Schreib-Leseprozedur.

Code sieht etwa folgendermaßen aus:

#define EEMEM  _attribute_ ((section (".eeprom")))
.
.
.

unsigned char threshold_1 EEMEM;

//threshold_1 bekommt einen Wert über die eingabe zugewiesen, dieser 
soll //gespeichert werden

eeprom_write_byte(&threshold_1, threshold_1);

//beim Neustart möchte ich diesen auslesen

void load_data(void)
{
threshold_1 = eeprom_read_byte(&threshold_1);
}


//später, ausgeben
uart_putc(threshold_1);


das ist grob der Aufbau. Habe mich an das Tutorial gehalten, nur 
irgendwie klappt es net so richtig.

: Verschoben durch User
von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Hallo alle zusammen,
>
> bräuchte kurz mal Hilfe.

möglich.
Aber nicht in der Codesammlung

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

> Code sieht etwa folgendermaßen aus:
>
> #define EEMEM  _attribute_ ((section (".eeprom")))

Warum definierst du das selber?


> unsigned char threshold_1 EEMEM;
>
> //threshold_1 bekommt einen Wert über die eingabe zugewiesen,

ganz sicher nicht.
treshold_1 ist keine Variable im eigentlichen Sinne, sondern ein 
Platzhalter für eine Position im EEPROM.

Den Rest deines Postings berücksichtigend, kann daher treshold_1 gar 
keinen Wert über die Eingabe zugewiesen bekommen haben.


> void load_data(void)
> {
> threshold_1 = eeprom_read_byte(&threshold_1);
> }

Du brauchst 2 Dinge

* Eine Variable, die tatsächlich im SRAM residiert. Das ist eine ganz 
normale Variable, so wie jede andere auch

* Eine EEMEM vereinbarte 'Variable', mit der du im Prinzip nur Platz im 
EEPROM reservierst.


Mit den read und write Funktionen wird dann von dem einen zum anderen 
umkopiert.

> Habe mich an das Tutorial gehalten, nur
> irgendwie klappt es net so richtig.

Dann sieh dir nochmal das Tutorial an. Dort wirst du genau diese 
Struktur immer wieder wiederfinden: SRAM Variable + Platzhalter im 
EEPROM

von Dennis (Gast)


Lesenswert?

danke schonmal, werde es noch mal probieren

von Dennis (Gast)


Lesenswert?

Hallo, habe immer noch schwierigkeiten mit der Sache.

So wie ich es verstanden habe, soll es folgendermaßen ausschaun,

uint8_t threshold_1_eeprom EEMEM;       //platzreservierung für eeprom
uint8_t environment_1_eeprom EEMEM;     //platzreservierung für eeprom


threshold_1=3;       //Beispielwerte, werden ubers Interface angegeben
environment_1=3;

eeprom_write_byte(&threshold_1_eeprom, threshold_1); // schreiben
eeprom_write_byte(&environment_1_eeprom, environment_1); // schreiben

threshold_1 = eeprom_read_byte(&threshold_1_eeprom); // lesen
environment_1 = eeprom_read_byte(&environment_1_eeprom); // lesen

nachdem ich den Reset Knopf an meinem Board betätige, werden die Werte 
leider nicht wieder angezeigt, d.h. müssen neu eingegeben werden. Wenn 
ich aber z.B. nur einen Wert speichere "threshold_1", dann kann bekomme 
ich den Wert nach dem Reset wieder ausgegeben.

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

> nachdem ich den Reset Knopf an meinem Board betätige, werden die Werte
> leider nicht wieder angezeigt, d.h. müssen neu eingegeben werden.

Dann zeig mal etwas mehr Code.

Dein Verständnis davon, wie die read bzw. write Funktion zu benutzen 
ist, scheint jetzt richtig zu sein. Also wirst du wohl in der Verwendung 
irgendwo einen Fehler machen.

> Wenn
> ich aber z.B. nur einen Wert speichere "threshold_1", dann kann bekomme
> ich den Wert nach dem Reset wieder ausgegeben.

?

von Dennis (Gast)


Lesenswert?

Code sieht folgendermaßen aus,

  unsigned long uart_baud, rf_baud;
  unsigned char channel;
  uint8_t bandwidth_1;
  uint8_t environment_1;
  uint8_t threshold_1;
  uint8_t threshold_1_eeprom EEMEM;
  uint8_t environment_1_eeprom EEMEM;
  uint8_t bandwidth_1_eeprom EEMEM;


//******************************configurationsmodus

void configmode(void)
{  unsigned char c;
  uart_init(UART_BAUD_SELECT(CONFIG_BAUD, F_CPU));


  for(;;)
  {
    //threshold_1=THRESHOLD;
    uart_puts_P("\r\n\r\n");
    uart_puts_P("RFM12 RS232 bridge v1.2\r\n");
    uart_puts_P("(c) by Benedikt\r\n");
    uart_puts_P("Config Menue\r\n\r\n");
    uart_puts_P("Current Settings:\r\n");
    uart_puts_P("\r\nRS232 baudrate: ");
    show_number(uart_baud);
    uart_puts_P("\r\nRFM12 baudrate: ");
    show_number(rf_baud);
    uart_puts_P("\r\nchannel:        ");
    show_number(channel);
    uart_puts_P("\r\nDRSSI threshold: ");
    uart_putc(threshold_1);
    uart_puts_P("\r\nEnvironment: ");
    uart_putc(environment_1);
    uart_puts_P("\r\nBandwidth: ");
    uart_putc(bandwidth_1);
    uart_puts_P("\r\n\r\n");
    uart_puts_P("(1) set RS232 baudrate\r\n");
    uart_puts_P("(2) set RFM12 baudrate\r\n");
    uart_puts_P("(3) set RFM12 channel\r\n");
    uart_puts_P("(4) set DRSSI threshold\r\n");
    uart_puts_P("(5) set Environment\r\n");
    uart_puts_P("(6) set Bandwidth\r\n");
    uart_puts_P("\r\n");
    uart_puts_P("(0) exit menu without saving\r\n");
    uart_puts_P("(s) exit menu and save settings\r\n");
    uart_puts_P("\r\n");
    //threshold_1=THRESHOLD;
    for(;;)
    {  c=uart_getchar();
      if (c=='0')
        return;
      else if (c=='s')
      {  uart_puts_P("saved !\r\nLeaving config mode...\r\n");
        save_settings();
        _delay_ms(10);
        return;
      }
      else if (c=='1')
      {  uart_puts_P("Enter RS232 baudrate (300-150000)\r\n");
        uart_baud=read_number(300,150000);
        break;
      }
      else if (c=='2')
      {  uart_puts_P("Enter RFM12 baudrate (700-65000)\r\n");
        rf_baud=read_number(700,65000);
        break;
      }
      else if (c=='3')
      {  uart_puts_P("Enter RFM12 channel (0-3)\r\n");
        channel=read_number(0,3);
        break;
      }
      else if (c=='4')
      {  uart_puts_P("Enter threshold (6-1) where (6 low sensitivity & 1 
high sensitivity)\r\n");

        threshold_1=uart_getchar();
        uart_putc(threshold_1);
        break;
      }
      else if (c=='5')
      {  uart_puts_P("Enter environment (1-3) where (1 quite environment 
& 3 noisy environment)\r\n");

        environment_1=uart_getchar();
        uart_putc(environment_1);
        break;
      }
      else if (c=='6')
      {  uart_puts_P("Enter Bandwidth (1-6) where (1=400kHz, 2=340kHz, 
3=270kHz, 4=200kHz, 5=134kHz, 6=67kHz) \r\n");

        bandwidth_1=uart_getchar();
        uart_putc(bandwidth_1);
        break;
      }
      else
        break;
    }
  }
}




//***************************das sind die Schreib bzw. Leseroutinen

void load_settings(void)
{


  if (eeprom_read_byte((void *)1)!=0xAA)
  {

    rf_baud=RF_BAUDRATE;
    uart_baud=UART_BAUDRATE;
    channel=CHANNEL;
    threshold_1=THRESHOLD;
    environment_1=QUIET;
    bandwidth_1=_BANDWIDTH_;
    save_settings();
  }


  channel=eeprom_read_byte((void *)2);
  eeprom_read_block(&rf_baud,(void *)3,4);
  eeprom_read_block(&uart_baud,(void *)7,4);
  threshold_1 = eeprom_read_byte(&threshold_1_eeprom); // lesen
  environment_1 = eeprom_read_byte(&environment_1_eeprom); // lesen

}

void save_settings(void)
{

  eeprom_write_byte((void *)1,0xAA);
  eeprom_write_byte((void *)2,channel);
  eeprom_write_block(&rf_baud,(void *)3,4);
  eeprom_write_block(&uart_baud,(void *)7,4);
  eeprom_write_byte(&threshold_1_eeprom, threshold_1); // schreiben
  eeprom_write_byte(&environment_1_eeprom, environment_1);//schreiben

}

von Karl H. (kbuchegg)


Lesenswert?

(Auf die SChnelle beim Drüberscrollen gesehen)

Autsch
1
  eeprom_write_byte((void *)1,0xAA);
2
  eeprom_write_byte((void *)2,channel);

Entweder du überlässt dem Compiler die Entscheidung, wo er welche 
"Variable" im EEPROM hinlegt, oder du machst das selber.

Wenn Compiler: dann musst du ihm das für alle "Variablen" überlassen!
Wenn selber: dann musst du das für alle "Variablen" selber machen!

Aber mischen ist immer schlecht!
Dein Compiler kann nicht Gedanken lesen welche EEPROM Zellen du für 
andere Zwecke benutzt und mit direkter Adresse ansprichst.

von Peter D. (peda)


Lesenswert?

Schau Dir das mal an:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=91306

Klein und einfach.


Peter

von Dennis (Gast)


Lesenswert?

@ Karl

könntest du mir eventuell mal nen Link geben, wo die automatische 
Speicherzuweisung beschrieben ist, das ganze verwirrt mich immer noch 
ein bisschen, und da ich mehrere Parameter abspeichern möchte, wäre das 
ja optimal,

eeprom_write_byte((void *)1,0xAA);
eeprom_write_byte((void *)2,channel);

@ peter

danke für den Link, nur ist es für mich ein bisschen schwierig den Code 
nachzuvollziehen, hab den eingebunden, bekomme aber Fehler beim 
Compilieren.

Gruß

Dennis

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> @ Karl
>
> könntest du mir eventuell mal nen Link geben, wo die automatische
> Speicherzuweisung beschrieben ist

Was brauchst du da beschrieben?

Wenn du schreibst
1
  uint8_t threshold_1_eeprom EEMEM;
2
  uint8_t environment_1_eeprom EEMEM;
3
  uint8_t bandwidth_1_eeprom EEMEM;

dann verwaltet der Compiler/Linker das EEPROM und verteilt die 
"Variablen" da drinn. Wo genau ist Sache des Compilers/Linkers. Geht 
dich nichts an wo genau, willst du auch gar nicht wissen.

Fertig. Mehr gibt es dazu nicht zu sagen

> das ganze verwirrt mich immer noch
> ein bisschen, und da ich mehrere Parameter abspeichern möchte, wäre das
> ja optimal,
>
> eeprom_write_byte((void *)1,0xAA);
> eeprom_write_byte((void *)2,channel);

Nein, das wäre nicht optimal.
Denn mit dem (void*)1 sagt du explizit aus: Ich will an die EEPROM 
Adresse 1 den Wert 0xAA gespeichert haben.

Du weißt aber nicht, ob nicht der Compiler an dieser Stelle im EEPROM zb 
die Variable
1
  uint8_t threshold_1_eeprom EEMEM;
angesiedelt hat. Der Compiler weiß ja nicht, dass du mit der 
Speicherzelle 1 im EEPROM irgendwas spezielles vor hast. Also wird er, 
pragmatisch wie er ist, die von dir angeforderten EEMEM 'Variablen' auch 
einfach beginnend von vorne im EEPROM ansiedeln.
Und schon machts klatsch: Der Compiler hat entschieden zb die 'Variable' 
threshold_1_eeprom an die Speicherstelle 1 im EEPROM zu legen und du 
schreibst dann da einfach 0xAA drauf. Das das ein Durcheinander gibt, 
braucht man nicht extra betonen.

Mach dir doch einfach noch eine Variable ins EEPROM
1
  uint8_t magicWord_eeprom EEMEM;
2
3
  uint8_t threshold_1_eeprom EEMEM;
4
  uint8_t environment_1_eeprom EEMEM;
5
  uint8_t bandwidth_1_eeprom EEMEM;

und überlass es dem Compiler die irgendwo im EEPROM anzulegen.

Du greifst zu mittels
1
   eeprom_write_byte( &magicWord_eeprom, 0xAA );
(bzw. umgekehrt natürlich beim read genauso)

und schon kommst du mit deinen speziellen Bytes dem Compiler nicht mehr 
in die Quere.

Wenn der Compiler die Kontrolle über das EEPROM haben soll, dann musst 
du sie ihm auch vollständig geben und nicht nur halb! Das heißt: Der 
Compiler/Linker legt für ALLES fest, wo es im EEPROM angesiedelt ist und 
du hältst dich als Programmierer da raus und verwendest keine absoluten 
Adressen im EEPROM!

(Für deine restlichen Dinge im EEPROM, die du mit absoluten Adressen 
ansprichst gilt genau das gleiche in Grün)

Oder aber umgekehrt: Du kümmerst dich selbst komplett darum, die 
einzelnen 'Variablen' im EEPROM zu verteilen, d.h. du legst selber fest 
an welcher Adresse im EEPROM welche Variable angesiedelt ist. Aber dann 
musst du das für alle machen und du bist dafür verantwortlich, dass es 
zu keinen Überschneidungen kommt.

Aber nicht mischen!
Wenn du selber einen Teil des EEPROMS verwaltest und einn Teil macht der 
Compiler und beide wissen nichts voneinander, dann gibts Chaos.

von Dennis (Gast)


Lesenswert?

Hab jetzt folgendes geändert,

#define CHANNEL    2
#define RF_BAUDRATE  20000
#define UART_BAUDRATE  19200
#define THRESHOLD  1
#define BANDWIDTH     4

{
//  unsigned long uart_baud, rf_baud;
//  unsigned char channel;

        uint16_t uart_baud, rf_baud; //da vorher unsigned long, jetzt 
als
                                     //uint16_t
  uint8_t channel;
  uint8_t bandwidth_1;
  uint8_t environment_1;
  uint8_t threshold_1;
  //uint8_t data_in_eeprom;

  uint8_t data_in_eeprom EEMEM;
  uint8_t threshold_1_eeprom EEMEM;
  uint8_t environment_1_eeprom EEMEM;
  uint8_t bandwidth_1_eeprom EEMEM;
  uint16_t uart_baud_eeprom EEMEM;
  uint16_t rf_baud_eeprom EEMEM;
  uint8_t channel_eeprom EEMEM;

}

void load_settings(void)
{

  if (eeprom_read_byte(&data_in_eeprom)!=0xAA)
  {

    rf_baud=RF_BAUDRATE;
    uart_baud=UART_BAUDRATE;
    channel=CHANNEL;
    threshold_1=THRESHOLD;
    environment_1=QUIET;
    bandwidth_1=_BANDWIDTH_;
    save_settings();
  }

  channel=eeprom_read_byte(&channel_eeprom);
  rf_baud=eeprom_read_word(&rf_baud_eeprom);
  uart_baud=eeprom_read_word(&uart_baud_eeprom);

  threshold_1 = eeprom_read_byte(&threshold_1_eeprom); // lesen
  environment_1 = eeprom_read_byte(&environment_1_eeprom); // lesen

}

void save_settings(void)
{
  eeprom_write_byte(&data_in_eeprom,0xAA);
  eeprom_write_byte(&channel_eeprom,channel);
  eeprom_write_word(&rf_baud_eeprom,rf_baud);
  eeprom_write_word(&uart_baud_eeprom,uart_baud);
  eeprom_write_byte(&threshold_1_eeprom, threshold_1); // schreiben
  eeprom_write_byte(&environment_1_eeprom, environment_1);// schreiben

}

stimmt es soweit? habe den "block" Teil als "word" definiert.
das config menue habe ich soweit gleich gelassen. Komischer weise komme 
ich nicht mehr ins ConfigMenue :?


Gruß

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

> stimmt es soweit?

sieht gut aus

> das config menue habe ich soweit gleich gelassen. Komischer weise komme
> ich nicht mehr ins ConfigMenue :?

Das hängt jetzt aber nicht mit diesen EEPROM-Routinen an sich zusammen

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dennis schrieb:
>   if (eeprom_read_byte(&data_in_eeprom)!=0xAA)
>   {
>
>     rf_baud=RF_BAUDRATE;
>     uart_baud=UART_BAUDRATE;
>     channel=CHANNEL;
>     threshold_1=THRESHOLD;
>     environment_1=QUIET;
>     bandwidth_1=_BANDWIDTH_;
>     save_settings();
>   }
>
>   channel=eeprom_read_byte(&channel_eeprom);
>   rf_baud=eeprom_read_word(&rf_baud_eeprom);
>   uart_baud=eeprom_read_word(&uart_baud_eeprom);
>   threshold_1 = eeprom_read_byte(&threshold_1_eeprom); // lesen
>   environment_1 = eeprom_read_byte(&environment_1_eeprom); // lesen

Fehlt da kein else nach dem if-Block? Du überknallst Dir unten wieder 
alle Variablen.

Gruß,

Frank

von Dennis (Gast)


Lesenswert?

Eigentlich nachdem die if-Anweisung an "save_settings()" angekommen ist, 
werden ja alle Daten gespeichert, d.h. die nachfolgenden Zuweisungen von 
"channel"-"environment" enthalten schon die richtigen Werte.

Sollte eigentlich alles stimmen. Das einzige Problem is jetzt nur der 
Zugriff auf das ConfiMenue.

Gruß

Dennis

von Dennis (Gast)


Lesenswert?

Habs jetzt, ch weiss nicht genau warum, aber nachdem ich den Config 
Aufrug mit einem Ausrufezeichen negiert habe, bekamm ich plötzlich mein 
ConfigMenue angezeigt. Is zwar n bissi merkwürdig, aber solange es 
funzt.

Danke für die Hilfe & Gruß

Dennis

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Habs jetzt, ch weiss nicht genau warum, aber nachdem ich den Config
> Aufrug mit einem Ausrufezeichen negiert habe, bekamm ich plötzlich mein
> ConfigMenue angezeigt.

Dem solltest du aber nachgehen. Solange bis du es weißt.

> Is zwar n bissi merkwürdig, aber solange es
> funzt.

Schlechte Idee.
'solange es funzt' ist eine schlechte Begründung, für eine Änderung die 
man nicht versteht bzw. die vollkommen unlogisch erscheint. Da kann sich 
auch ein Bug dahinter verstecken, der sich momentan eben so sichtbar 
macht. Bei der nächsten Programmänderung springt der Bug woanders hin 
und schon gehen die Ratespielchen wieder von vorne los.

von Dennis (Gast)


Lesenswert?

Also das ConfigMenue is bei mir folgens defieniert

#define CONFIG    PINB_1  // Pin fuer Config Jumper (DDR beachten)

if (!CONFIG)               //vorher war es nicht negiert
  configmode();      //ConfigMenue Aufruf

also PB1 ist bei mir mit dem Taster_1 verbunden, teoretisch, sollte ich 
den Taster betätigen dann muesste mein Menue erscheinen. Leider 
erscheint das Menue nur wenn ich den Reset Knopf drücke und auch nur 
dann, wenn der Aufruf negiert ist.

Bin momentan überfragt :?

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Also das ConfigMenue is bei mir folgens defieniert
>
> #define CONFIG    PINB_1  // Pin fuer Config Jumper (DDR beachten)
>

Wie ist PINB_1 definiert?

von Peter D. (peda)


Lesenswert?

Dennis schrieb:
> bekomme aber Fehler beim
> Compilieren.

Und was nun?

Rück mal ein Stück zur Seite, damit mein Astralkörper die Fehlermeldung 
auf Deinem Bildschirm auch sehen kann.


Peter

von Dennis (Gast)


Lesenswert?

@ Karl


struct bits {
  char b0:1;
  char b1:1;
  char b2:1;
  char b3:1;
  char b4:1;
  char b5:1;
  char b6:1;
  char b7:1;
} __attribute__((_packed_));
.
.
.

#define PINB_1 ((*(volatile struct bits*)&PINB).b1)
.
.
.
mehr habe ich zum PINB_1 net stehn.


@ Peter
.
.
.
          EECR |= 1<<EEMPE;
          EECR |= 1<<EEPE;
.
.
. Fehler: EEMPE, EEPE-undeclared (first use in this function)

ka. was der von mir moechte?

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> @ Karl
>
>
> struct bits {
>   char b0:1;
>   char b1:1;
>   char b2:1;
>   char b3:1;
>   char b4:1;
>   char b5:1;
>   char b6:1;
>   char b7:1;
> } __attribute__((_packed_));
> .
> .
> .
>
> #define PINB_1 ((*(volatile struct bits*)&PINB).b1)

ok.
Also direkte Port Pin Abfrage.

* Wie sind deine Taster angeschlossen
* ist ein Pullup an den Tastern notwendig/vorhanden/eingeschaltet
* wie sieht der Rest des Programms aus?

Bitte akzeptiere, dass es in einem Programm immer viele Möglichkeiten 
gibt, wie ein Effekt entstehen kann. Letztendliche Klarheit kann man 
daher in manchen Fällen nur dann erhalten, wenn man alle Fakten 
vollständig kennt.

Oftmals ist es so, dass man mit einem kleinen Programmausschnitt die 
eigentlich Ursache erraten kann. Oftmals ist es aber auch so, dass eben 
genau das nicht geht.

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

> .
>           EECR |= 1<<EEMPE;
>           EECR |= 1<<EEPE;
> .
> .
> . Fehler: EEMPE, EEPE-undeclared (first use in this function)
>
> ka. was der von mir moechte?

Das Bit wird auf deinem µC ein klein wenig anders heißen.
Ins Datenblatt schauen, die Beschreibung vom EECR Register raussuchen. 
Nachsehen ob es in dem ein Bit gibt, welches fast so heißt wie EEMPE.
Zur Sicherheit auch noch die anderen EEPROM Register kontrollieren, ob 
nicht das EEMPE Bit bei deinem µC in einem anderen Register angesiedelt 
wurde.

Oftmals, aber nicht immer, kann man Code unbeschadet von einem Prozessor 
zu einem anderen transportieren ohne etwas ändern zu müssen. Aber in 
manchen Fällen hat Atmel dem einen Riegel vorgeschoben, in dem die Dinge 
bei unterschiedlichen Porzessoren ein klein wenig anders heißen.

von Peter D. (peda)


Lesenswert?

Welchen AVR-Typ benutzt Du denn?

Bei den neueren AVRs heißen die Bits:

Bit 2 – EEMPE: EEPROM Master Program Enable
Bit 1 – EEPE: EEPROM Program Enable


Peter

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.