ATmega EEPROM Schreiben

Gast #3186984
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.
(Firma: matzetronics) #3187045
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.
Gast #3187048
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.
Gast #3187116
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;
(Firma: matzetronics) #3187127
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.
Gast #3187638
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
#3187645
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.
#3187646
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.
Gast #3187837
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
Angehängte Dateien:
Gast #3187848
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.
Gast #3187856
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
Gast #3187860
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))
#3187865
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?
Gast #3188270
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.
Gast #3188635
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
(Firma: matzetronics) #3188799
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
#3189172
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren