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?
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.
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.
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.
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.
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.
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.
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.
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.
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.
1
//
2
// wandelt einen Wert in seine ASCII Darstellung
3
// es werden immer 4 Stellen generiert, wobei mit
4
// führenden 0-en aufgefüllt wird.
5
//
6
voidmy_itoa(int16_twert,char*buffer)
7
{
8
//
9
// das wäre die simpelste Variante
10
// sprintf( buffer, "%04d", wert );
11
12
buffer[0]=wert/1000+'0';
13
wert=wert%1000;
14
buffer[1]=wert/100+'0';
15
wert=wert%100;
16
buffer[2]=wert/10+'0';
17
buffer[3]=wert%10+'0';
18
buffer[4]='\0';
19
}
20
21
//
22
// Die Funktion wendet Tastendrücke auf den übergebenen Wert an
23
//
24
// '+' Wert wird erhöht
25
// '-' Wert wird erniedrigt
26
//
27
// Rückgabe:
28
// TRUE Wert soll an den DAC geschickt werden, Eingabe abgeschlossen
29
// FALSE Wert ist manipuliert, Eingabe aber noch nicht abgeschlossen
30
//
31
// Argumente:
32
// *wert Zeiger auf eine int16_t Variable, die verändert werden soll
33
// *digitPos Welche Ziffer ist drann mit editieren
// die Zahl einfach mal mit allen 4 Stellen ausgeben
55
//
56
my_itoa(*wert,buffer);
57
lcd_send_string(buffer);
58
59
//
60
// Für das Blinken die richtige Stelle mit einem Leerzeichen
61
// überschreiben
62
//
63
if(toggle_display){
64
lcd_jump_to(1,4-digitPos);
65
lcd_send_string(" ");
66
}
67
68
//
69
// die Tasten auswerten
70
//
71
if(BUTTON_PLUS)
72
*wert=*wert+increment[digitPos];
73
74
if(BUTTON_MINUS)
75
*wert=*wert-increment[digitPos];
76
77
// sicherstellen, dass der Wert im Rahmen bleibt
78
// dabei auch Overflows und Underflows handhaben
79
if(*wert>3499)
80
*wert=3499
81
82
if(*wert<35)
83
*wert=35;
84
85
//
86
// wenn jetzt noch die 3.te Taste
87
//
88
// Ein kurzer Druck bedeutet: ab zur nächsten Stelle
89
//
90
if(get_button_short(BUTTON_3))
91
*digitPos+=1;
92
if(*digitPos==4)
93
*digitPos=0;
94
}
95
96
//
97
// ein langer Druck bedeutet:
98
// Wert am DAC setzen. Das wird einfach dem Aufrufer gemeldet
99
//
100
if(get_button_long(BUTTON_3))
101
return1;
102
}
103
104
return0;
105
}
106
107
intmain()
108
{
109
int16_tcurrent=35;
110
uint8_tdigitPos=0;
111
112
...
113
114
115
while(1){
116
....
117
118
119
if(.....
120
121
if(current_test_out(¤t,&digitPos))
122
set_Current_DAC(current);
123
124
...
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.
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