C Globale Variablen

flopower1996

Lt. Junior Grade
Registriert
Aug. 2014
Beiträge
401
Hey an alle,

ich habe ein kleines Problem. Mein kleiner Bruder programmiert jetzt mit einem einfachen 8-Bit Micro-Controller. Jetzt sind sie in der Schule gerade bei Interrupt-Routinen. Der Compiler kann für die Interrupt-Funktionen keine Variablen übergeben. Heißt: man muss entweder lokale oder globale Variablen verwenden... Wenn man nun im Hauptprogramm z.B. die Interrupt Einsprünge zählen will, muss man eine globale Variable verwenden...
Mein kleiner Bruder weigert sich aber diese zu verwenden. Er meint, ein Lehrer hätte ihm erklärt, dass man keine globalen Variablen verwendet, sondern nur lokale Variablen. Ich bin echt am Ende. Wie kann man ihm zeigen, dass es manchmal halt notwendig ist, etwas anders zu denken. Vllt. kennt ihr diese Probleme auch...
Habs schon mit Beispielen, Erklärungen etc. probiert. Ohne wirklich einen Erfolg zu verzeichnen.:(
 
Lass ihn machen. Wenn es nicht geht, sag nur "globale Variablen" und geh weg/ignorier ihn.

Wenn er es nicht gelöst bekommt (ohne globale Variablen), dann wird er es vielleicht einsehen.

(Wenn du fies bist, sag ihm, dass man globale Variablen mit einem Singleton umgehen kann :D)​​​
 
Ist das Problem jetzt das er nicht weiß wie er es mit den Vorgaben des Lehrers programmieren soll oder ist das Problem das er eher auf den Lehrer als auf Dich hört? ;)
 
ich kann diese Ansicht nicht teilen. Ich muss dem Lehrer recht geben. man sollte lokale Variablen verwenden. Man sollte soviel kapseln wie es nur geht. Vorallem wenn der Code portierbar ist.
Wozu sollte man was falsch lernen, um dann wieder richtig? lieber gleich richtig.

Als Beispiel: er kann ja einfach so machen und das ist richtig so:

static u32_t v_EncoderCounter_u32;


u32_t F_GetEncoderCounter_u32(void)
{
return v_EncoderCounter_u32;
}


void __Interrupt__ F_EncoderCounterInterrupt_v(void)
{
v_EncoderCounter_u32++;
}
 
Hancock schrieb:
Lass ihn machen. Wenn es nicht geht, sag nur "globale Variablen" und geh weg/ignorier ihn.

Wenn er es nicht gelöst bekommt (ohne globale Variablen), dann wird er es vielleicht einsehen.

(Wenn du fies bist, sag ihm, dass man globale Variablen mit einem Singleton umgehen kann :D)​​​

Ok klingt gut. Dann mache ich das so :)



Normalerweise würde ich dem Lehrer voll und ganz recht geben. Der Unterschied ist, dass der Lehrer C++ am PC unterrichtet und nie mit einem Microcontroller programmiert hat. Der MC ist nur sehr beschränkt, müsste einer der T89-Reihe sein...

Ich mache mal ein Beispiel. Wir haben ein Interrupt Event jede Sekunde, woher das kommt spielt keine Rolle. Kann ein Timer sein der hochzählt oder ein Quarz, ist ja auch egal. Schauen wir uns mal den Code dazu vereinfacht an...
Code:
int counter; //globale Varibale

void main (void)
{
char txt[17];
while(1)
{
pos (0); //LCD-Zeiger-Position wird auf 0 gesetzt
sprintf(txt,"%d",counter);
lcdsend(txt); // String wird auf dem LCD ausgegeben
}
}

void unterbrechung(void) interrupt 4
{
counter++;
}
 
Aliosy schrieb:
...
Als Beispiel: er kann ja einfach so machen und das ist richtig so:
...

Wo ist denn da die lokale Variable ?

@TE: Kann man in dem Szenario durchaus so machen, da es nicht wirklich eine Race-Condition geben kann. Das "counter++" ist zwar theoretisch nicht atomar auf dem Microcontroller ist es das praktisch aber schon.
 
Zuletzt bearbeitet:
in diesem Fall spiel es keine Rolle, ob local oder global... die Variable wurde deklariert im selben C File.

was man aber sagen kann, dass man so von außen immer auf "Counter" zugreifen könnte, und das verhindert man mit dem Schlüsselwort "static".

weil u.B.

Datei Name ... hack.c


extern counter; /// hier wird externe Variable bekannt gemacht

void hack(void)
{
counter = 0; // und hier manipuliert man diese variable
}
 
Aliosy schrieb:
ich kann diese Ansicht nicht teilen. Ich muss dem Lehrer recht geben. man sollte lokale Variablen verwenden. Man sollte soviel kapseln wie es nur geht. Vorallem wenn der Code portierbar ist.
Wozu sollte man was falsch lernen, um dann wieder richtig? lieber gleich richtig.

Als Beispiel: er kann ja einfach so machen und das ist richtig so:

static u32_t v_EncoderCounter_u32;


u32_t F_GetEncoderCounter_u32(void)
{
return v_EncoderCounter_u32;
}


void __Interrupt__ F_EncoderCounterInterrupt_v(void)
{
v_EncoderCounter_u32++;
}

Inwiefern ist v_EncoderCounter_u32 lokal?... Fehlt noch was drumherum, was ich überlesen haben könnte?


Gruß slash
 
@hamhero
Modullokal ... nicht Funktionslokal

sonst würde es keinen Sinn so zu machen ->
void unterbrechung(void) interrupt 4
15.{
int counter; // funktionslokale Variable deklarieren
16.counter++; // verwenden
17.} // und vergessen
 
@Aliosy: Das Problem ist hier wohl weniger der Scope der Variablen sondern eine mögliche Race-Condition wegen der Verwendung von Interrupts.

BTW: Eine lokale Variable ist eine Variable, die im Scope einer Funktion deklariert wurde (technisch: Sie wird auf dem Stack alloziiert). Das hat absolut nichts damit zu tun, ob sie im gleichen C-File dekalriert wurde oder nicht.
 
@HamHero
da hast du recht. Der Bereich ist egal. Nur richtigkeitshalber sollte man die Unterschiede kennen und die Auswirkungen.
Die Race-Condition stand nicht zur Debatte. Dass es nicht Interrupt-Sicher ist, das ist schon mal eine andere Baustelle ;)
hier gibt's unterschiedliche Ansätze.
-> ATOMIC -> lesen in einem Zyklus
-> INTERRUPT Sperren Lesen und INTERRUPT Freigeben
-> oder Pollen -> auf Unterschiede achten
 
Er hat recht würde ich sagen.. vermeidet globale Variablen.
Auch auf kleinen µC kann man C++ und OOP verwenden. Die ISR ruft dann zB eine Memberfunktion an einem Objekt auf. Das einzige was man natürlich sharen muss (zB global) ist dann ein Pointer auf die Instanz des Objekts.
Und ganz wichtig - was hier bisher komplett fehlt:
Wenn Daten (eine variable) innerhalb einer ISR verändert werden, sollten diese volatile markiert sein!
Ansonten wird die main-loop die zB 1/sekunde den Wert printed nicht den realen aktuellen Wert des counters auslesen.
 
Zuletzt bearbeitet:
Dein Vorschlag ist ja super, statt einer globalen Variable ein globalen Zeiger, wo man sich noch um den Speicher kümmern muss...
Du wirst es nicht schaffen in einer ISR den selben Speicher zu erreichen den auch der rest des Codes benutzt komplett ohne eine globale Variable denn wie bereits erklärt wurde haben ISRs nunmal keine Argumente.
Um den Speicher muss man sich nicht wirklich kümmern: Man initialisiert den Pointer direkt zu Beginn der main und aktiviert erst danach die Interrupts - das wars. So ist der Pointer immer gültig wenn er verwendet/gebraucht wird.
Der Unterschied ist eben, dass nicht unzählige Variablen und immer mehr structs etc global werden sondern genau ein Pointer auf eine Instanz. Das erlaubt OOP mit C++ in µC und funktioniert sehr gut, wie ich aus eigener Erfahrung sagen kann.
Wenns reines C bleiben soll kann man das selbe natürlich auch mit nem struct statt ner Klasse machen.
 
Zuletzt bearbeitet:
OK, was ist der Unterschied zwischen:
Code:
struct s{
...
};
​​​struct s*p=malloc(sizeof(struct s));
und
Code:
struct s{
...}p;
​​​
bzw.
Code:
struct s{
...};
struct s p;
​​​

Selbst mit C++ lass ich das Argument nicht gelten, du führst ein Pointer ein, der absolut nicht notwendig ist, und gleichzeitig verlierst du die Möglichkeit, alles statisch zu initialisieren (bei Klassen mit trivialem Konstruktor). Der einzige Unterschied ist, dass du . statt -> schreibst.

Und
​​
Um den Speicher muss man sich nicht wirklich kümmern: Man initialisiert den Pointer direkt zu Beginn der main und aktiviert erst danach die Interrupts - das wars.
Das sind für mich zwei Dinge, die man explizit beachten muss, das ist für mich nicht nicht wirklich.
 
Und wie nutzt du das dann in der ISR ohne es global zu machen? Das war doch das Thema hier.
 
Zuletzt bearbeitet:
Hancock schrieb:
(Wenn du fies bist, sag ihm, dass man globale Variablen mit einem Singleton umgehen kann :D)​​​

Was dann bloß eine globale Variable in edlem OOP-Gewand ist, aber das meintest du damit wahrscheinlich. ;P
 
@kuddlemuddl: Ich sehe ebenfalls nicht, was ein globaler Pointer gegenüber einer globalen Variable für Vorteile haben soll (ganz davon abgesehen, dass ein globaler Pointer natürlich auch eine globale Variable ist).

@HamHeRo: Ich kann mir nicht vorstellen, dass auf einem 8bit Mikrocontroller der int++-Operator in eine atomare Instruktion übersetzt werden kann. Wenn überhaupt dann gilt das nur für 8 bit Typen.
 
@kuddlemuddl: Ich sehe ebenfalls nicht, was ein globaler Pointer gegenüber einer globalen Variable für Vorteile haben soll (ganz davon abgesehen, dass ein globaler Pointer natürlich auch eine globale Variable ist).
Ich habe nie behauptet das das ein Vorteil wäre.
Mir ging es darum, dass man nicht dahin geht alles global zu machen auf dem gearbeitet wird sondern zu kapseln.
zB ein scruct mit einem volatile int numOfInterrupt0 pro interrupt und die isr inkrementiert den Wert. Die main() ruft eine Funktion handleInterrupts() auf und führt für numOfInterrupt0>0 handleInterrupt0() aus.
Der Pointer oder die Instanz dieses scructs muss nun halt für die ISRs erreichbar sein - mehr sag ich nicht ;).
 
Zurück
Oben