C Globale Variablen

flopower1996

Lt. Junior Grade
Dabei seit
Aug. 2014
Beiträge
371
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.:(
 

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
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)​​​
 

alxtraxxx

Commander
Dabei seit
Dez. 2013
Beiträge
2.279
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? ;)
 

Aliosy

Ensign
Dabei seit
Feb. 2013
Beiträge
149
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++;
}
 

flopower1996

Lt. Junior Grade
Ersteller dieses Themas
Dabei seit
Aug. 2014
Beiträge
371
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++;
}
 

HamHeRo

Lieutenant
Dabei seit
Sep. 2009
Beiträge
1.008
Zuletzt bearbeitet:

Aliosy

Ensign
Dabei seit
Feb. 2013
Beiträge
149
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
}
 

slashmaxx

Cadet 3rd Year
Dabei seit
Okt. 2006
Beiträge
47
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
 

Aliosy

Ensign
Dabei seit
Feb. 2013
Beiträge
149
@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
 

HamHeRo

Lieutenant
Dabei seit
Sep. 2009
Beiträge
1.008
@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.
 

Aliosy

Ensign
Dabei seit
Feb. 2013
Beiträge
149
@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
 

kuddlmuddl

Commander
Dabei seit
Mai 2010
Beiträge
2.493
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:

kuddlmuddl

Commander
Dabei seit
Mai 2010
Beiträge
2.493
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:

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
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.
 

kuddlmuddl

Commander
Dabei seit
Mai 2010
Beiträge
2.493
Und wie nutzt du das dann in der ISR ohne es global zu machen? Das war doch das Thema hier.
 
Zuletzt bearbeitet:

Miuwa

Commander
Dabei seit
Dez. 2011
Beiträge
2.474
@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.
 

kuddlmuddl

Commander
Dabei seit
Mai 2010
Beiträge
2.493
@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 ;).
 
Top