Forum: Mikrocontroller und Digitale Elektronik ATmega EEPROM Schreiben


von arser (Gast)


Lesenswert?

Hallo,

wie kann ich einen Wert im EEPROM beim allerersten Programmlauf ablegen?
Also vorbelegen quasi und beim nächsten Programmlauf wird die 
Speicherzelle mit dem zur Laufzeit entstandenem Wert überschrieben?

Kann ich das auch im AVR Studio machen?

Gruß Artur

PS. die Befehle zu Schreiben/Lesen des EEPROMs sind mir bekannt, mir 
geht es nur um den Trick.

von Eumel (Gast)


Lesenswert?

Du kannst das EEPROM direkt aus dem Programmierdialog des AVR Studio 
heraus beschreiben. Mit einer von dir ausgewählten Datei. Ebenso kannst 
du es auch auslesen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

So etwas hier erzeugt zum Beispiel eine *.eep Datei mit vorbesetzten 
Werten im Sourcecode:
1
// EEPROM values
2
uint16_t ee_address1 __attribute__((section(".eeprom"))) = TimeStamp; 
3
uint8_t ee_address2  __attribute__((section(".eeprom")))= MYCONSTANT;
4
uint8_t ee_address3  __attribute__((section(".eeprom"))) = 0b10001000;
5
uint8_t ee_address4 __attribute__((section(".eeprom"))) = 0xAA;
Ansprechen kannst du sie dann mit ihren ee_xxxxx Adressen.

von DIL EMMA (Gast)


Lesenswert?

Jungfräuliche AVRs haben im EEPROM FF an allen Stellen. Beim allerersten 
Programmstart kannst du ein zusätzliches Byte != FF setzen. Beim 
nächsten Programmstart testest du dieses zusätzliche Byte und weißt 
dann, das es bereits einen Programmstart gegeben hat. Von der Benutzung 
der Speicherstelle bei 0x00 ist aus anderen Gründen abzuraten.

von arser (Gast)


Lesenswert?

Hallo,
Danke Euch. Ich werde es mal probieren.
@DIL EMMA:
An sowas dachte ich, aber ich habe keine Vorstellung mit welcher 
Sicherheit die Zellen den beschriebenen Zustand haben.

Es hat sich nun folgendes, neues Problem ergeben:
1
void main()
2
{
3
...
4
  Kardan_Faktor = eeprom_read_float(&KF);
5
  Umfang_Faktor = eeprom_read_float(&UF);
6
7
  sei();                          //Interrupts an
8
9
  //Hauptschleife
10
  while(1) 
11
  {
12
    
13
  switch(main_state)
14
  {
15
    case state_Tacho:
16
17
      zahl = f_Welle * Kardan_Faktor*Umfang_Faktor * 3.6;;
18
      Zahlenart = GANZ;
19
20
      if( get_key_short( 1<<KEY1 ))
21
        main_state = state_OelTemp;
22
      if( get_key_short( 1<<KEY2 ))
23
        main_state = state_U_Bat;
24
    break;
25
26
    case state_U_Bat:
27
28
      zahl = delta_V*MESSFAKTOR*ADC_result;
29
      Zahlenart = DEZIMAL1;
30
31
      if( get_key_short( 1<<KEY1 ))
32
        main_state = state_Tacho;
33
34
      if( get_key_short( 1<<KEY2 ))
35
        main_state = state_Tages_km;
36
    break;
37
38
    case state_Tages_km:
39
40
      zahl = 222;
41
      Zahlenart = GANZ;
42
43
      if( get_key_short( 1<<KEY1 ))
44
        main_state = state_U_Bat;
45
46
      if( get_key_short( 1<<KEY2 ))
47
        main_state = state_Gesamt_km1;
48
    break;
49
50
    case state_Gesamt_km1:
51
52
      zahl = km_Stand/1000;
53
      Zahlenart = GANZ;
54
55
      if( get_key_short( 1<<KEY1 ))
56
        main_state = state_Tages_km;
57
58
      if( get_key_short( 1<<KEY2 ))
59
        main_state = state_Gesamt_km2;
60
    break;
61
62
    case state_Gesamt_km2:
63
64
      km_int = km_Stand/1000;
65
      zahl = (uint16_t)km_Stand - km_int*1000;
66
      Zahlenart = GANZ;
67
68
      if( get_key_short( 1<<KEY1 ))
69
        main_state = state_Gesamt_km1;
70
71
      if( get_key_short( 1<<KEY2 ))
72
        main_state = state_Kardan;
73
    break;
74
75
    case state_Kardan:
76
      
77
      zahl = Kardan_Faktor;
78
      Zahlenart = DEZIMAL2;
79
80
      if( get_key_short( 1<<KEY1 ))
81
        main_state = state_Gesamt_km2;
82
83
      if( get_key_short( 1<<KEY2 ))
84
        main_state = state_Umfang;
85
86
      if( get_key_long( 1<<KEY1 ))
87
        Kardan_Faktor -= 0.01;
88
89
      if( get_key_long( 1<<KEY2 ))
90
        Kardan_Faktor += 0.01;
91
    break;
92
93
    case state_Umfang:
94
      
95
      zahl = Umfang_Faktor;
96
      Zahlenart = DEZIMAL2;
97
98
      if( get_key_short( 1<<KEY1 ))
99
        main_state = state_Kardan;
100
101
      if( get_key_short( 1<<KEY2 ))
102
        main_state = state_OelTemp;
103
104
      if( get_key_long( 1<<KEY1 ))
105
        Umfang_Faktor -= 0.01;
106
107
      if( get_key_long( 1<<KEY2 ))
108
      {
109
        PORTC ^= (1<<PC1);    //LED toggle
110
        Umfang_Faktor += 0.01;
111
      }
112
    break;
113
114
    case state_OelTemp:
115
116
      zahl = 777;
117
      Zahlenart = GANZ;
118
119
      if( get_key_short( 1<<KEY1 ))
120
        main_state = state_Umfang;
121
122
      if( get_key_short( 1<<KEY2 ))
123
        main_state = state_Tacho;
124
125
      if( get_key_long( 1<<KEY2 ))
126
      {
127
        cli();                          //Interrupts aus
128
        eeprom_write_float(&KF, Kardan_Faktor);
129
        eeprom_write_float(&UF, Umfang_Faktor);
130
        sei();                          //Interrupts an
131
      }
132
    break;
133
134
    default:
135
136
      zahl = 999;
137
      Zahlenart = GANZ;
138
139
    break;
140
  }
141
...

Wenn ich die Zeilen
  Kardan_Faktor = eeprom_read_float(&KF);
  Umfang_Faktor = eeprom_read_float(&UF);
einfüge lassen sich die Variablen Kardan_Faktor und Umfang_Faktor im 
state_Kardan und state_Umfang nicht per Tastendruck verändern.
So habe ich es deklariert (Ausserhalb von main()):

float Kardan_Faktor = 0;
float KF EEMEM;

float Umfang_Faktor = 0;
float UF EEMEM;

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

arser schrieb:
> state_Umfang nicht per Tastendruck verändern

Sind das denn richtig deklarierte Variablen? Die globale Deklaration 
hast du ja nicht mitgepostet. Die 2te Frage ist, ob deine 'get_key_long' 
Routine über jeden Verdacht erhaben ist. Toggelt denn die Test LED?

arser schrieb:
> cli();                          //Interrupts aus
>         eeprom_write_float(&KF, Kardan_Faktor);
>         eeprom_write_float(&UF, Umfang_Faktor);
>         sei();                          //Interrupts an

Und du solltest da unbedingt noch
1
eeprom_busy_wait();
dazwischen machen. Beim Lesen braucht mans nicht, beim Schreiben aber 
schon.

von Arser (Gast)


Lesenswert?

Hallo Mathias,

die Deklaration ist global, vor main().
Die Test LED toggelt.

Ich habe es auch versucht, dass ich die Variablen in andere zwei 
kopiere, wahrscheinlich unsinnig, aber es hat nicht funktioniert.

Gruß Artur

von Karl H. (kbuchegg)


Lesenswert?

arser schrieb:
> Hallo,
> Danke Euch. Ich werde es mal probieren.
> @DIL EMMA:
> An sowas dachte ich, aber ich habe keine Vorstellung mit welcher
> Sicherheit die Zellen den beschriebenen Zustand haben.

Den haben sie, keine Sorge.

So ähnlich mach ichs auch, allerdings einfacher.
1
....
2
3
int main()
4
{
5
  eeprom_write_float(&KF, 0.5);
6
  eeprom_write_float(&UF, 0.5);
7
8
9
  .... dein restlicher Code

und hab dann die Werte im EEPROM, ehe das eigentliche Programm loslegt. 
:-)
Wenn dann der Rest funktioniert, kommentiere ich einfach die beiden 
Zeilen aus und fertig.

von Karl H. (kbuchegg)


Lesenswert?

Arser schrieb:
> Hallo Mathias,
>
> die Deklaration ist global, vor main().

Arser.
Bitte mach ed dir zur Regel, deinen Code einfach in Form eines C-Files 
an das Psoting anzuhängen.
Beschreib nicht deinen Code, zeig ihn nicht in Auszügen, sondern häng 
einfach den Code direkt an. Das ist für dich einfacher, das ist für uns 
einfacher, viele Nachfragen nach Details entfallen und nicht zu letzt 
zeigt sich immer wieder, dass das eigentliche Problem gar nicht in dem 
Codestück sitzt, welches du in Ausschnitten gezeigt hast.

von arser (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Karl Heinz,

hast recht, hätte ich gleich machen sollen. Wollte Euch einfach nicht 
mit zuviel Code belasten.

Die entsprechende Stelle liegt auf Zeile 164/165 und ist kommentiert.
Wie gesagt, wenn ich die zwei Zeilen weglasse kann ich die Variablen 
Kardan_Faktor und Umfang_Faktor zur Laufzeit per Tastendruck ändern, 
sonst nicht.

Gruß Artur

von arser (Gast)


Lesenswert?

...ach ja, falls es sonst etwas am Code, genauer am Stil zu bemängeln 
gibt, ist mein Ohr offen.

Gruß Artur

von Viktor N. (Gast)


Lesenswert?

Uiiiiiii, Tasten & Interrupts .... keine Spur von Entprellen.

Regel 1 mit Tasten :
Keine Interrupts. Es kommt ganz sicher nicht auf die Mikrosekunde an.

Regel 2 mit Tasten :
Ueber einen Timer-Tick, aber im Main, Entprellen.

von Viktor N. (Gast)


Lesenswert?

Float ... sollte man vermeiden. Die bringen in 99% aller Faelle nichts.
Delays sollte man vermeiden, die machen das Programm schwer zu debuggen, 
denn man weiss nicht genau wo es steht. Und kann es auch nicht 
herausfinden

von Karl H. (kbuchegg)


Lesenswert?

Viktor N. schrieb:
> Uiiiiiii, Tasten & Interrupts .... keine Spur von Entprellen.

Red keinen Quatsch. Er benutzt die PeDa Entprellung. Das Beste was man 
benutzen kann.

von arser (Gast)


Lesenswert?

Den INT1_vect löst ein Hall-Sensor aus. Durch die Beschaltung ist 
mehrmaliges Auslösen eigentlich nicht möglich. Ist auch getestet worden.

Die Entprellung der zwei Taster ist wie hier beschrieben realisiert:
http://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29

Die Qualität meines Guzzi-Tachos wäre um einiges schlechter ohne diese 
Enprell-Lösung))

von Karl H. (kbuchegg)


Lesenswert?

arser schrieb:

> Die Entprellung der zwei Taster ist wie hier beschrieben realisiert:
> 
http://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29



Dein Entprellen ist schon ok.
Allerdings hab ich mit den short bzw. long Funktionen auch keine 
Erfahrung. Hab ich noch nie benutzt.

Ich seh allerdings auch keinen Zusammenhang, wie das jetzt mit den 
EEPROM Funktionen zusammen hängen könnte.

OK, dass deine Multiplex-Anzeige verbesserungswürdig ist, darüber kann 
man reden. Allerdings ist das jetzt erst mal nicht das Problem.



Den einzigen Zusammenhang den ich vielleicht herstellen könnte ist, dass 
es einen Reset gibt und daher immer wieder derselbe Wert aus dem EEPROM 
geholt wird. Aber ansonsten seh ich da nicht wirklich, wie das zusammen 
hängen könnte.

Im übrigen würde ich den Wert sofort nach der Manipulation im EEPROM 
ablegen und nicht erst auf einen Tastendruck vom Benutzer warten um das 
Speichern anzustossen. Du kannst eine EEPROM Zelle mindestens 10000 mal 
beschreiben, ehe sie kaputt geht. So oft stellst du diese Faktoren nicht 
um! Oder fummelst du im Minutentakt, 24 Stunden am Tag, 2 Monate lang an 
dieser Einstellung rum?

von arser (Gast)


Lesenswert?

Natürlich nicht. Die Speicherung würde in den gleichen State verlegt 
werden. Es würde dann abgespeichert werden wenn man zum 
naächsten/vorherigen State umschaltet.
Zur Problemlösung wurde das Speichern "ausgelagert".

Ei Reset ist auszuschliesen, denn das Programm beginnt beim State Tach. 
Oder ich habe Deine Vermutung falsch verstanden.

Was Multiplexen angeht bin ich natürlich auch gelehrig, funzt auch nicht 
optimal. Die Anzeigen haben unterschiedliche Leuchtkraft, die dritte ist 
die hellste, denn die ist am längsten an, da nach ih vermutlich mehr 
Code abgearbeitet wird.

von arser (Gast)


Lesenswert?

Das Problem ist scheinbar unabhängig davon, ob ich die Entprellfunktion 
benutze.
Auch bei einfachster Pinabfrage lässt sich die Variable nicht verändern.

von arser (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> arser schrieb:
>> Hallo,
>> Danke Euch. Ich werde es mal probieren.
>> @DIL EMMA:
>> An sowas dachte ich, aber ich habe keine Vorstellung mit welcher
>> Sicherheit die Zellen den beschriebenen Zustand haben.
>
> Den haben sie, keine Sorge.
>
> So ähnlich mach ichs auch, allerdings einfacher.
> ....
>
> int main()
> {
>   eeprom_write_float(&KF, 0.5);
>   eeprom_write_float(&UF, 0.5);
>
>
>   .... dein restlicher Code
>
> und hab dann die Werte im EEPROM, ehe das eigentliche Programm loslegt.
> :-)
> Wenn dann der Rest funktioniert, kommentiere ich einfach die beiden
> Zeilen aus und fertig.

Man könnte ja den Speicher vorher auslesen und dann wie Du einen 
konstanten Wert schreiben, aber vorher abfragen ob der ausgelesene Wert 
EXAKT dem entspricht was reingeschrieben wurde. Wurde der Inhalt der 
EEPROM-Zelle zur Laufzeit bereits verändert, findet beim nächsten Mal 
das Beschreiben nicht mehr statt. Und sollte der Wert EXAKT dem 
entsprechen womit initialisiert wurde ist ja nicht schlimm.

Ich habe die EEPROM-Funktionen ausgetauscht: float gegen word. mit der 
byte Lese-/Schreibfunktion funktioniert es auch.

Leider bleibt das Problem für mich ungeloöst, mit einem Workaround durch 
Umrechnung verkraftbar))

Vielen Dank an alle!

Gruß Artur

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

arser schrieb:
> Leider bleibt das Problem für mich ungeloöst, mit einem Workaround durch
> Umrechnung verkraftbar))

Es ist sicher sinnvoll, die Software generell auf Integermathmatik 
umzubauen und lediglich für die Anzeige dann Dezimalzahlen zu verwenden. 
Du wirst dich wundern, wieviel Platz plötzlich im Flash verfügbar ist 
und kannst dann noch andere spassige Sachen mit einbauen.
http://www.mikrocontroller.net/articles/Festkommaarithmetik

von a. l. (artur78)


Lesenswert?

Interssanter Link. Man lernt nie aus.
Danke!

von Peter D. (peda)


Lesenswert?

Matthias Sch. schrieb:
> Du wirst dich wundern, wieviel Platz plötzlich im Flash verfügbar ist

Die float Grundrechenarten belegen einmalig 1kB Flash (AVR-GCC).
Könnte beim ATtiny2313 ne Rolle spielen.
Ab ATmega168 würde ich mir aber keinen Kopp darum machen.


Den EEPROM benutze ich nie direkt, sondern ne Struct im SRAM.
Beim Reset wird im EEPROM ne CRC geprüft und bei Erfolg die Struct 
geladen.
Bei falscher CRC bleibt die Vorbelegung der Struct gültig.

Erfolgt eine Bedienung, wird nur die Struct geändert. Nach Abschluß 
erfolgt dann das Berechnen der CRC und Update des EEPROM.
Update schreibt nur geänderte Bytes, man macht es daher immer über die 
gesamte Struct.

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.