mikrocontroller.net

Forum: PC-Programmierung Frage zu static-Variable


Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen!

Eine Frage zur static-Variable: Ich habe diese deklariert, damit die 
Variable in der Funktion beim nächsten Aufruf auch wieder vorhanden ist 
und ihren Wert nicht verliert.

Wenn ich diese nun aber nicht mehr benötige, wie werde ich sie wieder 
los?

Gibt es einen Befehl, um den Speicher wieder frei zu geben?

: Verschoben durch Admin
Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ewald schrieb:

> Wenn ich diese nun aber nicht mehr benötige, wie werde ich sie
> wieder los?

Überhaupt nicht.

> Gibt es einen Befehl, um den Speicher wieder frei zu geben?

Nein.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Nein.

Wie? Einmal in die elt gesetzt...für immer am Hals? Ist ja schlimmer als 
n Kind.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nu - weshalb heisst "static" wohl so? Damit es dynamisch ist?

Beschreib lieber mal das eigentliche Problem als deinen fehlgeschlagenen 
Ansatz zur Lösung. Es gibt nämlich auch statische Zeiger auf dynamischen 
Speicher, wenn's unbedingt sein muss.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Damit es dynamisch ist?

Nee, natürlich nicht, nur kann ja sein, dass man sie explizit wieder 
killen kann, wenn man sie nicht mehr benötigt.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void current_test_out (void)
{
  static uint8_t position = 5;
  
  static int8_t  number_1 = 0;
  static int8_t  number_2 = 4;
  static int8_t  number_3 = 0;
  static int8_t  number_4 = 0;
  
  uint32_t dac_test_value = 0;

  .....

Das ganze ist in einem Menü. number_1  bis number_4 sind vier Stellen 
auf einem LCD, welche man mit +/- -Tasten einzeln erhöhen, bzw. 
verringern kann.

Da es noch andere Sachen im Programm zu tun gibt, wird das Menü zyklisch 
aufgerufen, die eigentliche Funktion also verlassen.

Wenn ich die Variablen nicht als static deklariere, sind sie natürlich 
beim nächsten Aufruf weg.

Und meine Frage wäre jetzt gewesen, dass wenn ich den Menüpunkt nicht 
mehr aufrufe, die Variable auch weg kann.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm eine globale Variable und nenn sie help. Dann kannst du mit ihr 
machen, was du willst... ;-)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du machst dir wegen der paar Bytes solche Sorgen?

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Du machst dir wegen der paar Bytes solche Sorgen?

Nein, war ja nur ne Frage, ob es geht.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ewald schrieb:

> Wenn ich die Variablen nicht als static deklariere, sind sie natürlich
> beim nächsten Aufruf weg.

Schon.
Aber warum muss sich diese Funktion die Werte merken?

Warum kann man sich die nicht ausserhalb merken?
Warum müssen das 4 int8_t sein? Warum kann das nicht ein einzelner 
int8_t sein, der von der Funktion bei Betreten (die Funktion bekommt den 
Wert mit) in die einzelnen Stellen zerlegt wird und der von der Funktion 
vor dem Verlassen wieder zu einem int8_t zusammengebaut wird? Die 
Funktion liefert dann an den Aufrufer den neuen, vom Benutzer 
veränderten Wert zurück. Die aufrufende Funktion macht dann mit dem 
Wert, was auch immer notwendig ist und die Funktion muss sich selbst 
intern nichts merken.

Neben dem geringeren Speicherplatzverbrauch gewinnst du dadurch auch 
Flexibilität, da du diese 'Einstellfunktion' dann für viele verschiedene 
Werte in deinem Programm benutzen kannst und nicht nur für einen.


Du versuchst gerade ein 'Problem' zu lösen, dass du bei einem 
vernünftigen Programmdesign gar nicht hättest.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Warum kann man sich die nicht ausserhalb merken?

Meinst du mit ner globalen Variable?

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> dass du bei einem
> vernünftigen Programmdesign gar nicht hättest

So lang bin ich eben noch nicht beim Programmieren...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ewald schrieb:
> Karl heinz Buchegger schrieb:
>> Warum kann man sich die nicht ausserhalb merken?
>
> Meinst du mit ner globalen Variable?

Kann sein.

Aber:
Warum müssen das 4 int8_t sein? Warum kann das nicht ein einzelner
int8_t sein, der von der Funktion bei Betreten (die Funktion bekommt den
Wert mit) in die einzelnen Stellen zerlegt wird und der von der Funktion
vor dem Verlassen wieder zu einem int8_t zusammengebaut wird? Die
Funktion liefert dann an den Aufrufer den neuen, vom Benutzer
veränderten Wert zurück. Die aufrufende Funktion macht dann mit dem
Wert, was auch immer notwendig ist und die Funktion muss sich selbst
intern nichts merken.

Neben dem geringeren Speicherplatzverbrauch gewinnst du dadurch auch
Flexibilität, da du diese 'Einstellfunktion' dann für viele verschiedene
Werte in deinem Programm benutzen kannst und nicht nur für einen.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist halt quasi so:
main
{
  irgendwas...
  irgendwas anderes...

  if (menue_soll_angezeigt_werden == JA)
  {
    switch (menuepunkt)
    {
      punkt1:
      {
        ...
      }
      punktX:
      {
        static uint8_t position = 5;
  
        static int8_t  number_1 = 0;
        static int8_t  number_2 = 4;
        static int8_t  number_3 = 0;
        static int8_t  number_4 = 0;
  
        uint32_t dac_test_value = 0;

        ...
      }
    }
  }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ewald schrieb:
> Es ist halt quasi so:

Nicht 'quasi'.

Jeder Fall ist immer ein wenig anders.
Wenn man konkret sagen soll, wie es besser gehen könnte, muss man auch 
den konkreten Code sehen.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, das ist das ganze dazu, ist natürlich jetzt recht lang, sind 
eigentlich nur abfragen drin um bestimmte Grenzen nicht zu 
über-/unterschreiten.

4-stellige LCD-Anzeige bei der man mit PLUS und MINUS hoch und runter 
zählen kann und mit einer dritten Taste die Stelle wechselt.

Damit stellt man einen Strom ein, der dann zu einem DAC geschickt wird, 
wenn man die dritte Taste langegedrückt hält.
main
{
  ...
  
  if ((menu_item == 0) && (get_button_long (BUTTON_3)))
  {
    menu_item = 1;
  }

  if (menu_item != 0)
  {
    current_test_out ();
  }

  ...
}



void current_test_out (void)
{
  static uint8_t position = 5;
  
  static int8_t  number_1 = 0;
  static int8_t  number_2 = 4;
  static int8_t  number_3 = 0;
  static int8_t  number_4 = 0;
  
  uint32_t dac_test_value = 0;
  
  if (ten_ms_toggle)
  {
    ten_ms_toggle = FALSE;
    
    lcd_clear_display ();
    lcd_jump_to (2,4);
    lcd_send_string ("mA");
    lcd_jump_to (1,1);
    
    switch (position)
    {
      case 1:
      {
        if (display_toggle)
        {
          lcd_send_num (number_1, FALSE);
        }
        else
        {
          lcd_send_num (' ', FALSE);
        }

        lcd_send_num (number_2, TRUE);
        lcd_send_num (number_3, FALSE);
        lcd_send_num (number_4, FALSE);

        break;
      }

      case 2:
      {
        lcd_send_num (number_1, FALSE);
          
        if (display_toggle)
        {
          lcd_send_num (number_2, TRUE);
        }
        else
        {
          lcd_send_num (' ', TRUE);
        }

        lcd_send_num (number_3, FALSE);
        lcd_send_num (number_4, FALSE);

        break;
      }

      case 3:
      {
        lcd_send_num (number_1, FALSE);
        lcd_send_num (number_2, TRUE);
          
        if (display_toggle)
        {
          lcd_send_num (number_3, FALSE);
        }
        else
        {
          lcd_send_num (' ', FALSE);
        }

        lcd_send_num (number_4, FALSE);

        break;
      }

      case 4:
      {
        lcd_send_num (number_1, FALSE);
        lcd_send_num (number_2, TRUE);
        lcd_send_num (number_3, FALSE);

        if (display_toggle)
        {
          lcd_send_num (number_4, FALSE);
        }
        else
        {
          lcd_send_num (' ', FALSE);
        }          

        break;
      }

      case 5:
      {
        lcd_send_num (number_1, FALSE);
        lcd_send_num (number_2, TRUE);
        lcd_send_num (number_3, FALSE);
        lcd_send_num (number_4, FALSE);

        break;
      }
    }

    if (BUTTON_PLUS)
    {
      switch (position)
      {
        case 1:
        {
          number_1 += 1;

          if (number_1 > 2)
          {
            number_1 = 0;
          }

          break;
        }

        case 2:
        {
          number_2 += 1;

          if (number_1 == 2)
          {
            if (number_2 > 4)
            {
              number_2 = 0;
            }
          }
          else if (number_1 == 0)
          {
            if (number_2 > 9)
            {
              number_2 = 3;
            }
          }            
          else
          {
            if (number_2 > 9)
            {
              number_2 = 0;
            }
          }

          break;
        }

        case 3:
        {
          number_3 += 1;

          if ((number_1 == 2) && (number_2 == 4))
          {
            number_3 = 0;
          }
          else if ((number_1 == 0) && (number_2 == 3))
          {
            if (number_3 > 9)
            {
              number_3 = 5;
            }
          }
          else
          {
            if (number_3 > 9)
            {
              number_3 = 0;
            }
          }

          break;
        }

        case 4:
        {
          number_4 += 1;

          if ((number_1 == 2) && (number_2 == 4))
          {
            number_4 = 0;
          }
          else
          {
            if (number_4 > 9)
            {
              number_4 = 0;
            }              
          }

          break;
        }
      }
    }

    if (BUTTON_MINUS)
    {
      switch (position)
      {
        case 1:
        {
          number_1 -= 1;
            
          if (number_1 < 0)
          {
            number_1 = 2;
          }

          break;
        }

        case 2:
        {
          number_2 -= 1;

          if (number_1 == 0)
          {
            if (number_2 < 3)
            {
              number_2 = 9;
            }
          }

          else if (number_1 == 2)
          {
            if (number_2 < 0)
            {
              number_2 = 4;
            }
          }
          else
          {
            if (number_2 < 0)
            {
              number_2 = 9;
            }
          }

          break;
        }

        case 3:
        {
          number_3 -= 1;

          if ((number_1 == 2) && (number_2 == 4))
          {
            number_3 = 0;
          }
          else if ((number_1 == 0) && (number_2 == 3))
          {
            if (number_3 < 5)
            {
              number_3 = 9;
            }
          }
          else          
          {
            if (number_3 < 0)
            {
              number_3 = 9;
            }
          }

          break;
        }

        case 4:
        {
          number_4 -= 1;

          if ((number_1 == 2) && (number_2 == 4))
          {
            number_4 = 0;
          }
          else
          {
            if (number_4 < 0)
            {
              number_4 = 9;
            }
          }

          break;
        }
      }
    }
  }

  if (get_button_short (BUTTON_3))
  {
    if ((number_1 == 2) && (number_2 >= 4))
    {
      number_2 = 4;
      number_3 = 0;
      number_4 = 0;
    }
    else if ((number_1 == 0) && (number_2 <= 3))
    {
      number_2 = 3;
      number_3 = 5;
      number_4 = 0;
    }

    position += 1;

    if (position > 5)
    {
      position = 1;
    }
  }

  if (get_button_long (BUTTON_3))
  {
    if ((number_1 == 2) && (number_2 >= 4))
    {
      number_2 = 4;
      number_3 = 0;
      number_4 = 0;
    }
    else if ((number_1 == 0) && (number_2 <= 3))
    {
      number_2 = 3;
      number_3 = 5;
      number_4 = 0;
    }

    position = 5;

    dac_test_value = (number_1 * 1000);
    dac_test_value += (number_2 * 100);
    dac_test_value += (number_3 * 10);
    dac_test_value += number_4;

    if ((dac_test_value > 2000) || (dac_test_value < 400))
    {
      dac_test_value = (dac_test_value * 131072);
      dac_test_value = (dac_test_value / 3200);
      dac_write (dac_test_value, ALARM);
    }
    else
    {
      dac_test_value = (dac_test_value - 400);
      dac_test_value = (dac_test_value * 65536);
      dac_test_value = (dac_test_value / 1600);
      dac_write (dac_test_value, NORMAL);
    }      
  }

  if (BUTTON_P_M) // Verlassen
  {
    number_1 = 0;
    number_2 = 4;
    number_3 = 0;
    number_4 = 0;

    menu_item = 0;
  }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sieht jetzt für mich erst mal so aus, als ob du den Strom zwischen 0 
und 2500 einstellen können willst.

Melde mich gleich noch mal

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Strom kann ich damit zwischen 3,5 und 24mA einstellen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein nicht unerklecklicher Teil deiner Funktion beschäftigt sich damit, 
die 4 einzelnen Stellen und deren Zusammenhänge zu 'verwalten'.

Da würde ich einen Ansatzpunkt sehen um den Code zu vereinfachen.
Wenn du grundsätzlich nur einen int16_t hättest, der den momentan 
eingestellten Strom enthält, dann ist ja das Drücken von +/- an den 
einzelnen Position gleichwertig damit, dass dieser Strom um 1; 10; 100; 
1000 erhöht/erniedrigt wird. Damit fällt dir dann aber auch vieles weg, 
was sich jetzt nur um Überträge, Bereichsgrenzen etc. dreht.

Das ist das eine.
Das andere ist: In einem guten Software Design, macht eine Funktion eine 
Aufgabe und nur diese Aufgabe.
Ich würde daher trennen: Die Funktion soll sich um die Benutzereingabe 
kümmern, einen übergebenen Wert entsprechend der Tastendrücke 
manipulieren und als Rückgabewert auch noch mitteilen, ob der Wert jetzt 
zum DAC gegeben werden soll oder nicht.

D.h. nicht die Funktion speicher den aktuellen Wert für current, sondern 
der existiert entweder beim Aufrufer oder überhaupt in einer globalen 
Variablen. Das ebnet dann auch den Weg um zb den Wert im EEPROM 
zwischenzuspeichern (damit er beim Ein/Ausschalten des Geräts wieder 
verfügbar ist) oder eine PC-Schnittstelle über UART nachzurüsten etc.
//
// wandelt einen Wert in seine ASCII Darstellung
// es werden immer 4 Stellen generiert, wobei mit
// führenden 0-en aufgefüllt wird.
//
void my_itoa( int16_t wert, char* buffer )
{
  //
  // das wäre die simpelste Variante
  // sprintf( buffer, "%04d", wert );

  buffer[0] = wert / 1000 + '0';
  wert = wert % 1000;
  buffer[1] = wert / 100 + '0';
  wert = wert % 100;
  buffer[2] = wert / 10 + '0';
  buffer[3] = wert % 10 + '0';
  buffer[4] = '\0';
}
  
//
// Die Funktion wendet Tastendrücke auf den übergebenen Wert an
//
//   '+'     Wert wird erhöht
//   '-'     Wert wird erniedrigt
//
// Rückgabe:
//     TRUE     Wert soll an den DAC geschickt werden, Eingabe abgeschlossen
//     FALSE    Wert ist manipuliert, Eingabe aber noch nicht abgeschlossen
//
// Argumente:
//     *wert     Zeiger auf eine int16_t Variable, die verändert werden soll
//     *digitPos Welche Ziffer ist drann mit editieren
//               0 ... Einer
//               1 ... Zehner
//               2 ... Hunderter
//               3 ... Tausender
//
uint8_t current_test_out( int16_t* wert, uint8_t* digitPos )
{
  char buffer[5];
  int16_t increment[] = { 1, 10, 100, 1000 };

  if( ten_ms_toggle )
  {
    ten_ms_toggle = FALSE;
    
    lcd_clear_display ();
    lcd_jump_to (2,4);
    lcd_send_string ("mA");
    lcd_jump_to (1,1);

    //
    // die Zahl einfach mal mit allen 4 Stellen ausgeben
    //
    my_itoa( *wert, buffer );
    lcd_send_string( buffer );

    //
    // Für das Blinken die richtige Stelle mit einem Leerzeichen
    // überschreiben
    //
    if( toggle_display ) {
      lcd_jump_to( 1, 4 - digitPos );
      lcd_send_string( " " );
    }

    //
    // die Tasten auswerten
    //
    if( BUTTON_PLUS )
      *wert = *wert + increment[digitPos];

    if( BUTTON_MINUS )
      *wert = *wert - increment[digitPos];

    // sicherstellen, dass der Wert im Rahmen bleibt
    // dabei auch Overflows und Underflows handhaben
    if( *wert > 3499 )
      *wert = 3499

    if( *wert < 35 )
      *wert = 35;

    //
    // wenn jetzt noch die 3.te Taste
    //
    // Ein kurzer Druck bedeutet: ab zur nächsten Stelle
    //
    if( get_button_short( BUTTON_3 ) )
      *digitPos += 1;
      if( *digitPos == 4 )
        *digitPos = 0;
    }
 
    //
    // ein langer Druck bedeutet:
    // Wert am DAC setzen. Das wird einfach dem Aufrufer gemeldet
    //
    if( get_button_long( BUTTON_3 ) )
      return 1;
  }

  return 0;
}

int main()
{
  int16_t current = 35;
  uint8_t digitPos = 0;

  ...


  while( 1 ) {
    ....
 

    if( .....

      if( current_test_out( &current, &digitPos ) )
        set_Current_DAC( current );

      ...

Warnung: ungetesteter Code

Ob ich mir allerdings den ganzen Teil mit Editierung der Einzelstellen 
antun würde, weiß ich ehrlich gesagt nicht.
Ich hätte mir die PeDa Entprellung genommen und ganz einfach mit dessen 
Autorepeat den Wert einfach um +/- 1 erhöht, bzw. wenn der Autorepeat 
einsetzt, den Wert um +/- 100 erhöht/erniedrigt. Letztendes ist das für 
den Benutzer wahrscheinlich angenehmer, als wie wenn er erst mit einer 
3.ten Taste kompliziert auf die Stelle manövrieren muss, die er braucht 
und die um 1 erhöhen/erniedrigen muss.

Autor: Ewald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, vielen Dank schonmal, das werde ich mir jetzt erstmal zu Gemüte 
führen!

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was für ein Display benutzt du eigentlich?
der standard text-display-controller (k.A. wie der heißt) hat einen 
einschaltbaren cursor, der blinkt entweder als ganzer Block, oder als 
Unterstrich.
Da braucht man sich nicht selbst um das blinken kümmern

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.