Variable wo deklarieren?

Hallo,

bei meinen Sketchen mache ich es meistens so, dass sich globale Variablen, void setup und void loop auf der ersten "Seite" befinden.

Sämtliche anderen Funktionen verteile ich normalereweise auf Tabs. Mittlerweile arbeite ich viel mit verschachtelten Funktionen und frage mich, wo ich deren Variablen deklarieren soll.

Ein Beispiel:

void setup()
{
}

void loop()
{
  funktion_01();
}

// TAB

void funktion_01()
{
  variable_42 = 2;
  funktion_02();
}

void funktion_02()
{
  variable_42 = 3;
}

Mit der Variablen variable_42 "arbeiten" lediglich die Funktionen funktion_01 und funktion_02, so dass ich ungern eine globale Variable auf der ersten Seite erstellen möchte.

Wie löst man sowas am elegantesten?

Gruß Chris

hi,

indem Du die variable_42 als parameter übergibst.

gruß stefan

Schau dir mal Referenzparameter / call by reference an

Man kann z.B. das machen:

void loop()
{
     static int var;       //oder auch nicht-static wenn der Wert nur in einer loop-Iteration gebraucht wird

     func(var);
}

void func(int& var)
{
   var = 42
}

Durch das & wird die Adresse der Variablen übergeben und nicht deren Wert (call by value). Dadurch kann man die Variable in der Funktion ändern und die Änderung ist außerhalb sichtbar

Ich danke Euch Beiden,

leider kann ich Eure Vorschläge nicht in meinem aktuellen Projekt umsetzen. Vielleicht denke ich auch nur zu kompliziert.

Hier mal der komplette Code inkl. einer kleinen Erklärung was da passieren soll:

Dass noch ganz grundsätzliche Dinge wie Serial.begin() fehlen und sich bestimmt noch der eine oder andere Denkfehler im Code tummelt , sei mal dahingestellt. Es geht mir primär um das weiter unten, nach dem Code geschilderte Problem.

char serial_buffer[11];     // Buffer
char c;                     // Eingehendes Zeichen
int i = 0;                  // Indexnummer
unsigned long serial_time;  // Eingangszeitpunkt des ersten Zeichens
boolean serial_fall = 0;    // Schrittnummer
byte serial_dur = 50;       // Maximale Gesamtdauer eines Auslesevorgangs

void setup()
{}

void loop()
{
  serial_available();
}

// TAB

void serial_available()
{
  if(Serial.available())  // Lesevorgang einleiten
  {
    switch (serial_fall)
    {
    case 0:
      {
        serial_time = millis();                    // Eingangszeit des ersten Zeichens festhalten
        serial_fall++;
      }
    case 1:
      {
        c = Serial.read();                         // Zeichen auslesen
        serial_buffer[i] = c;                      // Buffer beschreiben
        i++;                                       // Index erhöhen (Achtung- es darf nicht über die Arraygrenze hinaus geschrieben werden!)

        if(c == '\r') serial_check();              // Falls das "Abschlusszeichen" (hier ein "enter") reinkam..
      }
    }
  }
  
  if(millis() >= serial_time + serial_dur & serial_fall)  // Wenn eine bestimmte Zeit ohne Eingang des "Abschlusszeichens" vergangen ist..
  {                                                       // Es liegt dann sozusagen ein "Timeout" vor.
    serial_reset();
  }
}

void serial_check()
{
  if(strcmp(serial_buffer,"Befehl_ohne_enter_am_Ende") == 0)
  {
    // Coole Dinge machen..
    serial_reset();
  }
}


void serial_reset()
{
  memset(serial_buffer,0,sizeof(serial_buffer));  // Puffer mit Nullbytes fuellen und dadurch loeschen
  i = 0;                                          // Indexnummer zurücksetzen
  serial_fall = 0;                                // Schrittnummer zurücksetzen
}

Der Code soll einen seriellen Eingang prüfen und mein Problem ist nun, dass ich die Variablen serial_buffer, c, i, serial_time, serial_fall und serial_dur gerne von meiner ersten Seite weghätte, ich jedoch nicht weiss wie ich es lösen könnte.

Gruß Chris

Au backe. Lohnt es ich nachher überhaupt, das so aufzubauen :roll_eyes:

void serial_available(void){static int i; char c = 0; static char serial_buffer[11]; static unsigned long serial_time; static int serial_fall, static int serial_dur;}

Schau dir generell mal Funktions-Parameter an (und verstehe den Unterschied zwischen call-by-value und call-by-reference). Und schaue dir auch Rückgabe-Werte an.

Dann schau dir an was static macht!!

Den Puffer z.B. kannst du static in serial_available() deklarieren und dann das machen:

void serial_check(char* buffer)

Dann rufst du das so auf:

serial_check(serial_buffer);

Für char c reicht doch eine normale lokale Variable! Die wird nirgends sonst gebraucht.

index i ebenfalls static in serial_available().

Ähnlich kannst du es mit den anderen Variablen machen. Was sich nicht verändert wird const deklariert. Und was man im nächsten Funktions-Aufruf noch braucht wird static deklariert. Merke: static Variablen behalten ihren Wert von Aufruf zu Aufruf, aber sie haben lokalen Scope!

Wenn man etwas in einer anderen Funktion braucht übergibt man es als Parameter. Wenn man den Wert in der Funktion ändern will übergibt man eine Referenz oder einen Zeiger. Und Funktionen können natürlich auch einen Wert zurückgeben.

Werd mich reinarbeiten- danke soweit!

Gruß Chris

@ sschultewolter: Es geht hier nicht darum, ob und was sich hier lohnt, sondern es geht ganz konkret um meine Frage.

Noch ein Tip:

if(strcmp(serial_buffer,"Befehl_ohne_enter_am_Ende") == 0)

Du hast gerade 26 Byte RAM verschwendet wenn ich das richtig zähle

Besser:

if(strcmp_P(serial_buffer, PSTR("Befehl_ohne_enter_am_Ende")) == 0)

Damit bleibt der String im Flash.

Vielleicht bin ich inzwischen auch zu aggressiv mit dem pro-aktiven RAM optimieren (noch bevor man überhaupt Probleme bekommt), aber es schadet auch nichts wenn man sich sowas gleich angewöhnt :slight_smile:

Es gibt von allen String Funktionen die einen solchen festen String als Parameter haben _P Versionen wie man mit PSTR() ein Literal im Flash lassen kann

Ich finds super, dass Du mich darauf hingewiesen hast. :wink:

Gruß Chris

Chris72622:
Werd mich reinarbeiten- danke soweit!

Gruß Chris

@ sschultewolter: Es geht hier nicht darum, ob und was sich hier lohnt, sondern es geht ganz konkret um meine Frage.

Frage wurde doch beantwortet. Ich hab nur darauf hingewiesen, dass die Funktionen jetzt irgendwie etwas unnötig sind. Wenn man sich mit sowas vertraut machen möchte (Übergabe von Parametern), dann nimmt man sich da ein anderes Beispiel.

seriel_check() ist schon ok und die Übergabe lässt sich einfach realisieren. Außerdem ist es generell sinnvoll Eingabe von Verarbeitung zu trennen.
serial_reset() machst das ganze dagegen eher unübersichtlicher und unnötig kompliziert. Das gehört in die normale Funktion.