Forum: Mikrocontroller und Digitale Elektronik Wie einer static-Variablen einen Eeprom-Startwert zuweisen?


von Gerhard (Gast)


Lesenswert?

Steh gerade ein wenig auf dem Schlauch...

Eine Funktion, die jede Sekunde aufgerufen wird, soll mit einem 
Eeprom-Wert beginnen.

void test ()
{static unsigned int Time=1000;
Time--;
bla
bla
bla
if (!Time)
    Time=TimeReload_ee;
}

Eine Möglichkeit wäre natürlich, Time von 0 bis TimeReload_ee laufen zu 
lassen. Ich hätte es aber gern als Abwärtszähler.

static unsigned int Time=TimeRelaod_ee;
führt zu einem (nicht unerwarteten) Fehler: must be constant expression

von Arduinoquäler (Gast)


Lesenswert?

Gerhard schrieb:
> static unsigned int Time=TimeRelaod_ee;

Wenn du einen Wert aus dem EEPRPOM haben willst musst
du ihn auch aus dem EEPROM lesen, nicht (so wie du es
jetzt machen willst) aus dem RAM.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

1
void test()
2
{
3
  static unsigned int Time = 0;
4
5
  if (!Time) 
6
    Time = TimeReload_ee;
7
8
  Time--;
9
10
  bla bla
11
  bla
12
}

von Gerhard (Gast)


Lesenswert?

Es geht nur um den allerersten Aufruf.
Ist Time abgelaufen, wird es ja aus dem Eeprom nachgeladen.

Ursprünglich war der Startwert fest, nachträglich soll das jetzt ein 
einstellbarer Parameter sein.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Gerhard schrieb:
> Es geht nur um den allerersten Aufruf.

Hat Rufus doch gelöst! Beim ersten Aufruf von test() wird Time mit dem 
EEPROM-Wert initialisiert, nämlich hier:
1
  if (!Time) 
2
    Time = TimeReload_ee;

Rufus nutzt hier aus, dass der Time-Wert aus dem EEPROM niemals 0 sein 
kann. Daher initialisiert er Time = 0 (was übrigens bei statics Default 
ist). Und damit wird auch beim ersten Aufruf der EEPROM-Wert geladen.

Allgemein macht man eine Laufzeitinitialisierung von Statics zum 
Beispiel so:
1
test ()
2
{
3
    static unsigned char already_called = 0;
4
    static int mystatic;
5
6
    if (! already_called)
7
    {
8
        mystatic = mein_initialwert_aus_eeprom_oder_sonstwoher;
9
        already_called = 1;
10
    }
11
12
   ...
13
}

Ist hier bei diesem trivialen Problem aber nicht notwendig.

von Einer K. (Gast)


Lesenswert?

Wenn die Variable beim Start, aus einem EEPROM, vorbesetzt werden soll, 
dann ist eine lokale statische vermutlich das falsche Mittel!
Zumindest arg unelegant.


Wäre es nicht schöner diese Variable global anzulegen und vor dem 
Main-Loop zu initialisieren...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

U. F. schrieb:
> Wäre es nicht schöner diese Variable global anzulegen und vor dem
> Main-Loop zu initialisieren...

Es reicht, wenn der Start- bzw. Wiederholungswert global ist, also 
TimeReload_ee. Genau das ist der Fall.

Nach der Zählvariablen Time fragt keine Sau^H^H^Handere Funktion, 
deshalb ist eine lokale static-Variable auch hier die korrekte Lösung.

von Stefan F. (Gast)


Lesenswert?

Ich finde das nicht unelegant.

Immerhin ist die Variable dort hingeschrieben worden, wo sie verwendet 
wird und sie ist auch nur innerhalb dieser einen Funktion sichtbar.

Klar macht es umgekehrt auch einen gewissen Sinn, alle EEprom variablen 
woanders zsuammen zu fassen. Ist halt Geschmacks-Sache.

von A. H. (ah8)


Lesenswert?

Wäre C++ für Dich eine Option? In C++ sind im Initializer einer 
statischen lokalen Variable auch Funktionen zulässig:

1
int init() { return 13; }
2
3
int foo()
4
{
5
        static int i = init();
6
        return i;
7
}

init wird genau einmal aufgerufen und zwar bevor das Ausführen des 
Funktionsblockes von foo zum ersten Mal beginnt. (Es sei denn, init 
wirft eine Exception. In dem Fall gilt i als nicht initialisiert und 
die Funktion wird beim nächste Eintritt in foo erneut aufgerufen.)

Möglicherweise kann ein neuerer C-Standard das ja auch? Ob und ggfs. 
Welche Einschränkungen es bei Mikrocontrollern gibt, kann ich allerdings 
nicht sagen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

A. H. schrieb:
> Wäre C++ für Dich eine Option? In C++ sind im Initializer einer
> statischen lokalen Variable auch Funktionen zulässig:

Das löst hier aber nicht die Aufgabe, die Zählvariable immer wieder neu 
zu setzen, nämlich wenn sie runter auf 0 gelaufen ist. Rufus' Lösung ist 
hier schon die richtige.

von TM F. (p_richner)


Lesenswert?

Noch eine andere Anregung:
Wenn du jede Sekunde einen Wert aus dem EEPROM liest, wird es in kurzer 
Zeit nicht mehr gehen. Wenn du pro uC ca. 100'000 Zugriffe hast, hast du 
nach gut einem Tag die 100'000 verbraucht, danach ist es nicht mehr 
garantiert, dass du weiter zugreifen kannst.

(Kommt auf den uC an)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

TM F. schrieb:
> Wenn du jede Sekunde einen Wert aus dem EEPROM liest, wird es in kurzer
> Zeit nicht mehr gehen.

Häh? Seit wann nutzt das Lesen eines EEPROMs dieses ab? Du meinst eher 
wohl das Schreiben! Das ist hier aber gar nicht der Fall.

Außerdem liegt der Wert des EEPROMs bereits im RAM vor, nämlich als 
TimeReload_ee.

Unglaublich, was hier spekuliert wird...

von A. H. (ah8)


Lesenswert?

Frank M. schrieb:
> A. H. schrieb:
>> Wäre C++ für Dich eine Option? In C++ sind im Initializer einer
>> statischen lokalen Variable auch Funktionen zulässig:
>
> Das löst hier aber nicht die Aufgabe, die Zählvariable immer wieder neu
> zu setzen, nämlich wenn sie runter auf 0 gelaufen ist. Rufus' Lösung ist
> hier schon die richtige.

Es war zumindest das, was der TO vorhatte:

> static unsigned int Time=TimeRelaod_ee;
> führt zu einem (nicht unerwarteten) Fehler: must be constant expression

Mit C bekomme ich den gleichen Fehler, mit C++ funktioniert 's 
problemlos. Wobei es genaugenommen natürlich

1
  static unsigned int Time=TimeReload_ee();

heißen muss. Wobei gegen Rufus' Lösung natürlich auch nichts einzuwenden 
ist.

von Gerhard (Gast)


Lesenswert?

Frank M. schrieb:
> Hat Rufus doch gelöst! Beim ersten Aufruf von test() wird Time mit dem
> EEPROM-Wert initialisiert, nämlich hier:

Das war die Antwort an den Arduinoquäler, Rufus' Antwort hatte ich noch 
gar nicht gesehen.

Gut, hätte ich noch dazu schreiben können, Time interessiert schon. Wird 
zurückgegeben an die aufrufende Funktion und wird auch weiterverwendet. 
Deshalb wollte ich auch nicht einfach die Zählrichtung ändern.

Und, nein, als globale Variable will ich den Zähler nicht haben. 
TimeReload_ee ist eine globale Variable, und die liegt im Eeprom.

Rufus Lösung ist (fast) genau das, was ich suchte. Bis auf den 
Rückgabewert, der nicht 0 sein darf. Aber das bekomme ich jetzt schon 
hin :-)

C++, hm. Noch nie damit beschäftigt, also eher nein.

Also, vielen Dank an alle, Problemchen gelöst.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Gerhard schrieb:
> Bis auf den Rückgabewert, der nicht 0 sein darf.

Da ist kein Rückgabewert. Wo soll da einer sein?

von Gerhard (Gast)


Lesenswert?

Wie schon gesagt, in echt ist der vorhanden, tat aber zum eigentlichen 
Problem nichts zur Sache, deshalb weggelassen.
0 ist bei mir ein Fehlercode, 1 der minimale Rückgabewert.
Bei deinem Beispiel wäre 0 der kleinste Rückgabewert. Konntest du 
natürlich nicht wissen.

Alles ist gut :-)

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.