Hallo,
ich weis es gibt sehr viele Threads zu volatile, aber die kreisen alle
um die Standardsituation "Variable wird im Hauptprogramm UND
InterruptServiceRoutine (ISR) verwendet".
Ich würde gerne wissen, ob eine globale Variable, die ich NUR in der ISR
verwende, auch volatile sein muss?
Also ist folgendes Beispiel auch ohne volatile safe?
1
#define LED0_TOG() PORTA ^= (1<<PA0)
2
#define LED1_TOG() PORTA ^= (1<<PA1)
3
4
volatileuint8_tints_cnt=0;
5
6
ISR(INT0)
7
{
8
if(ints_cnt==100)
9
{
10
ints_cnt=0;
11
LED0_TOG();
12
}
13
elseif{ints_cnt==0||ints_cnt==50}
14
{
15
LED1_TOG();
16
}
17
ints_cnt++;
18
}
Meine vermutung wäre, dass es safe ist, da ints_cnt ja nicht anderweitig
verändert werden kann, und der Compiler das "Variablen cachen" daher
gerne aktivieren darf (das er hier wohl anwenden dürfte).
Danke für Antworten!
Da geht es auch ohne "volatile". Sicherer ist es dann freilich, wenn du
die Variable innerhalb der ISR als "static" definierst, denn dann ist
der Sachverhalt offensichtlich und niemand kommt später auf dumme
Gedanken.
Mario Fischer schrieb:> Ich würde gerne wissen, ob globale eine Variable, die ich NUR in der ISR> verwende, auch volatile sein muss?
Nein.
Aber wenn sie wirklich nur in dieser einen ISR verwendet wird, wäre es
sinnvoll, sie static local zu machen, statt global.
Mario Fischer schrieb:> Ich würde gerne wissen, ob eine globale Variable, die ich NUR in der ISR> verwende, auch volatile sein muss?
Nein, muss sie nicht.
> Also ist folgendes Beispiel auch ohne volatile safe?
Ja, aber wenn Du sie ausschließlich in der ISR benutzt, dann schreibe
sie auch dort hinein!
Also:
1
ISR(INT0)
2
{
3
staticuint8_tints_cnt=0;// static, damit sie "weiterlebt"
4
...
Damit ist dann klar, wo sie benutzt wird, nämlich ausschließlich in der
ISR.
Gruß,
Frank
Eigentlich sollte man immer berücksichtigen, warum es volatile gibt:
Wenn für den Compiler nicht ersichtlich ist, daß sich eine Variable
ändern kann. Eine ISR ist dabei zwar der Klassiker, aber nicht alleine.
Mario Fischer schrieb:> Hallo,> ich weis es gibt sehr viele Threads zu volatile, aber die kreisen alle> um die Standardsituation "Variable wird im Hauptprogramm UND> InterruptServiceRoutine (ISR) verwendet".>> Ich würde gerne wissen, ob eine globale Variable, die ich NUR in der ISR> verwende, auch volatile sein muss?
Wird Zeit das Thema mal in der FAQ anzusprechen :-)
Nein!
Das volatile sagt dem Compiler, dass sich eine Variable verändern kann,
ohne dass er das mit seinen Datenflussanalysen rausfinden kann. volatile
verlangt vom Compiler, dass jeder Zugriff auf die Variable so wie
hingeschrieben durchgeführt werden muss.
Warum ist das wichtig?
Weil du in der Hauptschleife zb so was machen kannst
while( Flag_welches_von_einer_ISR_verändert wird )
;
Die Datenflussanalyse des Compilers findet raus, dass sich in dieser
Schleife die Variable überhaupt nicht verändern kann, weil es keinen
Funktionsaufruf oder sonst irgendeine Zuweisung an diese Variable gibt.
Für den Compiler ist daher diese while Schleife:
entweder
* wird sie nie ausgeführt (wenn die Variable vor der Schleife
auf 0 ist)
* oder es ist eine Endlosschleife (wenn die Variable vor der Schleife
nicht 0 ist)
er kann daher dieses while so implementieren
if( Flag_welches_von_einer_ISR_verändert wird )
while( 1 )
;
und spart damit die Zugriffe auf die Variable ein.
Das ist aber nicht das was du willst. Denn du als Programmierer weißt,
dass es sehr wohl eine Möglichkeit gibt, wie die Variable ihren Wert
verändern kann. Nur für den Compiler ist das nicht ersichtlich. Also
musst du ihm mit dem volatile helfen.
Danke für die Antworten!
Stimmt, da habt ihr recht, das Beispiel hätte besser ausgesehen, wenn
ich ints_cnt als static in die ISR reingeschrieben hätte...
>Aber wenn sie wirklich nur in dieser einen ISR verwendet wird, wäre es>sinnvoll, sie static local zu machen, statt global.
Ähm, wieso static? Dann muss die variable ja auch gehalten werden, wenn
die ISR nicht läuft.
chris schrieb:>>Aber wenn sie wirklich nur in dieser einen ISR verwendet wird, wäre es>>sinnvoll, sie static local zu machen, statt global.>> Ähm, wieso static? Dann muss die variable ja auch gehalten werden, wenn> die ISR nicht läuft.
Schau Dir die ISR oben an. Der Wert der Variablen muss "gehalten"
werden, wenn die ISR nicht läuft. Genau das ist der Sinn einer globalen
Variablen, deshalb hat der TO das ursprünglich auch so gemacht. Den
gleichen Effekt erzielt man aber auch mit einer static-Variablen. Sie
"überlebt".
chris schrieb:> Ähm, wieso static? Dann muss die variable ja auch gehalten werden, wenn> die ISR nicht läuft.
Das ist bei einer solchen Zählvariable nunmal unabdingbar.
Oliver
>Schau Dir die ISR oben an. Der Wert der Variablen muss "gehalten">werden, wenn die ISR nicht läuft. Genau das ist der Sinn einer globalen>Variablen, deshalb hat der TO das ursprünglich auch so gemacht.
Tschuldigung, ein Versehen von mir. Ich dachte es geht um die allgemeine
Frage, wie Variablen in der ISR zu definieren sind.
Lutz schrieb:> Eigentlich sollte man immer berücksichtigen, warum es volatile gibt:> Wenn für den Compiler nicht ersichtlich ist, daß sich eine Variable> ändern kann.
Dafür muß man erstmal die Sichtweise des Compilers kennen. Eigentlich
ist es doch eine Macke des Compilers, wenn er nicht mal den Klassiker
erkennt und man, um diese Unzulänglichkeiten zu verdecken, extra ein
Keyword wie "volatile" einführt.
C-Kritiker schrieb:> Dafür muß man erstmal die Sichtweise des Compilers kennen. Eigentlich> ist es doch eine Macke des Compilers, wenn er nicht mal den Klassiker> erkennt und man, um diese Unzulänglichkeiten zu verdecken, extra ein> Keyword wie "volatile" einführt.
Und woher soll ein Compiler wissen, ob eine Variable
- ein I/O-Register darstellt,
- im Adressraum mehrfach gemappt ist (mal cachable mal nicht)
- von einem Interrupt-Handler verändert wird,
- von einem anderen Prozess oder Thread genutzt wird,
- von einem anderen Prozessor oder per DMA genutzt wird?
Nein, das ist allenfalls eine Macke der Sprache, die für diese Konzepte
keine individuelle Vereinbarung oder entsprechende Detaildeklarationen
kennt, sondern pauschal "volatile" vorschreibt.
C-Kritiker schrieb:> Eigentlich ist es doch eine Macke des Compilers, wenn er nicht mal> den Klassiker erkennt
Woran soll denn der Compiler erkennen, ob z.B. zum entsprechenden
Zeitpunkt ein Interrupt überhaupt enabled ist.
Früher wars compilerabhängig mal so, dass alle globalen Variablen
automatisch volatil waren. Erst mit den fortgeschrittenen
Optimierungsoptionen wurde die Sprachdefinition von C viel mehr auf
"Schlupflöcher" abgeklopft. Die volatile Geschichte ist nur die
einfachste Ausprägung, an der die Optimierungsstrategien am deutlichsten
sichtbar sind.
Fazit: schalt einfach die Optimierung aus, dann macht der Compiler da
nichts weg...
C-Kritiker schrieb:> Eigentlich> ist es doch eine Macke des Compilers, wenn er nicht mal den Klassiker> erkennt
C kennt das Konzept "Interrupt" nicht, daher muß ein C-Compiler das auch
nicht erkennen können.
KLassiker in diesem Zusammenhang sind allerdings vor allem memory-mapped
Zugriffe auf Register, dis sich alleine ändern (IO-Register, Zähler,
ADC-Wandler, usw.). Von dem Problem bekommst du nur nichts mit, weil die
volatile-Deklarationen dafür ihn den avrlibc-headern stehen.
Oliver