Hallo zusammen
Ich habe ein Problem: meine ISR soll eine Variable ändern, welchen auch
eine andere Funktion verwendet. Gibt es hierzu eine nicht-globale
Lösung?
Und welche Gründe gibt es, keine globalen Variabeln zu verwenden
(Anwendungsbereich uC)? Ich kenne:
- alle anderen Funktionen können darauf zugreifen
- mühsam, wenn eine Funktion, die globale Variabeln verwendet, woanders
wieder gebraucht wird
lucifer schrieb:> Gibt es hierzu eine nicht-globale> Lösung?
nimm statische variablen... die sind dann ausserhalb deiner
übersetzungseinheit nicht sichtbar. ISR und deine "andere" funktion
muessen dann innerhalb derselben übersetzungseinheit stehen.
lucifer schrieb:> Und welche Gründe gibt es, keine globalen Variabeln zu verwenden
gründe dafür pauschal festzulegen ist schwierig... es geht dabei einfach
nur darum, dass anfänger dazu tendieren alles global zu machen, damit
sie nicht über eine vernünftige programmstruktur nachdenken muessen. es
wird dann eben schnell unübersichtlich, wann welche funktion irgendeine
variable verändert... und wenn man dann nach nen halben jahr das
programm warten muss, traut man sich nicht mehr irgendwelche variablen
anzufassen, denn es könnte ja jederzeit eine andere funktion beim
variablenzugriff dazwischenfunken, an die man sich nicht mehr erinnert.
solange man also eine vernünftige programmstruktur hat, die einem die
übersicht über die globalen zugriffe gewährleistet, spricht nichts gegen
den einsatz von globalen geschichten.
Vielen Dank für die sehr informativen Antworten.
Mit anderen Worten sind globale Variabeln ok, wenn man sie gut überlegt
einsetzt, so nach dem Credo "think before code"...
lucifer schrieb:> Vielen Dank für die sehr informativen Antworten.> Mit anderen Worten sind globale Variabeln ok, wenn man sie gut überlegt> einsetzt, so nach dem Credo "think before code"...
das musst du sowieso.
Es kommt auch immer darauf an.
Bei kleinen µC vernwedet man konzeptionell öfter globale Variablen.
Warum?
Weil die Ausstattung mit Speicher nicht sehr üppig ist.
D.h. hier muss man ein Auge darauf haben, wieviel Speicher bereits
verbraucht wurde. Mit globalen Variablen geht das recht einfach, weil
man einfach nur den Speicherverbrauch der globalen Variablen addieren
muss, um zu wissen, wo man in etwa liegt.
Sind alle Variablen aber in main beheimatet bzw. hat man in einzelnen
Funktionen größere Arrays, dann tauchen die in der Speicherstatistik
nicht richtig auf. Bzw. wenn deine Tools versuchen den
Laufzeit-Speicherverbrauch zu schätzen, dann ist das recht schwierig,
weil ja a prioir nicht bekannt ist, welchen Weg der Programmfluss nehmen
wird, da der ja sehr oft auch von unbekannten Eingangswerten abhängt.
Auf Desktop System, mit mehr Speicher, sind globale Variablen aus den
genannten Gründen weitgehend verpöhnt, auch wenn man da teilweise aus
Gründen der Einfachheit einige Werte global halten kann bzw. wird, wenn
klar ist, dass diese Werte (wie zb Konfigurationswerte) praktisch
überall quer durch das Programm benutzt werden. Es macht dann wenig
Sinn, diese Werte quer durch komplexe Funktionshierarchien überall
durchzuschleusen.
Aber selbst wenn man auf einem µC aus praktischen Gründen globale
Variablen benutzt, heisst das nicht, dass man einfach auf Biegen und
Brechen alles global macht. Das ist nicht besonders sinnvoll. In
praktisch jeder Funktion gibt es Variablen wie zb Schleifenvariablen,
die sinnvollerweise eben nicht global gemacht werden, sondern
funktionslokal gehalten werden. Da das aber üblicherweise nicht viele
sind und die auch nicht allzuviel Speicher verbrauchen, ist es kein
großer Beinbruch, wenn die in der Speicherstatistik nicht auftauchen.
Speicher der zur Laufzeit für Daten benutzt wird, darf man sowieso nicht
zu 100% anfüllen, sondern muss sich eine kleine Reserve unter anderem
auch für die Laufzeitumgebung halten.
Hi,
> Auf Desktop System, mit mehr Speicher, sind globale Variablen aus den> genannten Gründen weitgehend verpöhnt, auch wenn man da teilweise aus> Gründen der Einfachheit einige Werte global halten kann bzw. wird, wenn> klar ist, dass diese Werte (wie zb Konfigurationswerte) praktisch> überall quer durch das Programm benutzt werden. Es macht dann wenig> Sinn, diese Werte quer durch komplexe Funktionshierarchien überall> durchzuschleusen.>
Die sind nicht nur verpönt, sondern meist schlicht verboten (dasselbe
gilt für die static-Konstrukte innerhalb Funktionen), nämlich dann, wenn
mehrere Threads eine Funktion durchlaufen. Bei lokal veränderten
Variablen müssen diese zwingend ausschliesslich im Kontext des Threads
(also auf dem Stack oder in einem spezifischen Register-Fenster)
existieren, sonst knallts (und ist teils übelst zu debuggen)
Gewollt ist dann was globales nur noch zum Austausch zwischen den
Threads (was dann auch entsprechend 'atomic' gehalten werden muss)
Manche Informatiker würden behaupten, dass genau eine einzige globale
Variable existieren darf/muss. Vom technischen Aspekt dieser Behauptung
abgesehen, macht es auf jeden Fall einen aufgeräumten Eindruck, wenn im
Programm ein globaler struct mit allen Konfigurations-Variablen
existiert, also zB:
1
struct my_context {
2
int setting_a;
3
....
4
} g_context;
Wenn nötig (-> Anforderungen an OO/thread-Sicherheit) hat man dann das
g_*-Konstrukt schnell wieder aus dem Code gesäubert.
Heiner schrieb im Beitrag #3968584:
> das uebliche globale Variablen bashing...
Beside - ist dir jemals der Gedanke gekommen das es für "bashing" auch
rationale Gründe geben könnte?
> - alle anderen Funktionen können darauf zugreifen> - mühsam, wenn eine Funktion, die globale Variabeln verwendet, woanders> wieder gebraucht wird
- man es verpennt, dass die Variable NUR von DER ISR gesetzt werden darf
Lösung:
* ISR schreibt in eine lokal sichtbare Variable (statisch, nicht global)
* global sichtbare Funktion gibt den Wert der Variablen zurück
(Optimierung schmeißt den Funktionsaufruf wieder raus (geht das bei C?)
und wenn du deinen Code portierst kann du ggf. eine Ersatzfunktion
schreiben)
Header:
lucifer schrieb:> Ich habe ein Problem: meine ISR soll eine Variable ändern, welchen auch> eine andere Funktion verwendet.
..und genau DARÜBER solltest du dir Gedanken machen. Dein Problem ist
also nicht die globale Variable an sich, sondern der geordnete
störungsfreie Zugriff mehrerer unabhängiger Instanzen auf gemeinsame
Ressourcen.
Da mußt du eben deine grauen Zellen anwerfen und dir ein sinnvolles
Lösungsprinzip ausdenken. Z.B. daß eine ISR eben nicht direkt
irgendwelche Systemparameter verstellt, sondern nur eine Botschaft ins
System einspeist, die das Neusetzen solcher Ressourcen an zentraler
Stelle veranlaßt. Stichwort: Entkopplung per Event-Handling
W.S.
> int getADCValue()
Die Gefahr von Namenskonflikten verändert sich dadurch nicht. Mit etwas
Pech hat dann eine Lib eine global sichtbare Funktion getADCValue().
Noch einer schrieb:> Die Gefahr von Namenskonflikten verändert sich dadurch nicht. Mit etwas> Pech hat dann eine Lib eine global sichtbare Funktion getADCValue().
Deswegen macht man z.B. Modul-Präfixe wie:
ADC_getADCValue();
Sensors_getADCValue()
was nebenbei die Lesbarkeit der Quelltexte erhöht, da der Kontext der
Funktion dadurch sichtbar wird.
Fall der uC mit Threads laeuft, haben die Threads und ggf auch der Main
Thread nur ein Stuck vom Stack zugeteilt bekomnen. Grosse Auto-Variable
konnen dann den Stack zum Ueberlauf bringen, daher also mit XXXalloc()
oder static allozieren
Auslesen der Temperatursensoren perfekt gekapselt... Und dann schlägt
die Realität zu.
Ein ganz anderes Modul soll einen freien ADC-Kanal nutzen und das muss
nun irgendwie in die Abfrage der Sensoren mit reingefrickelt werden.
FelixW schrieb:> Header:int getADCValue();> Source:int ADCValue;> int getADCValue(){return ADCValue;}
Vorsicht, das funktioniert auf einem 8-Bit avr nicht. Für den Zugriff
auf ein int (ADCValue) muss der Interrupt gesperrt werden damit die
beiden Bytes des int auch zusammengehören!
Und es fehlt ein volatile