Forum: Compiler & IDEs Zugriff auf Array aus Main in Interrupt-Routine


von Christian B. (chrblank)


Lesenswert?

Moin Leute,

das Problem das mir mittlerweile Kopfschmerzen macht ist:

Ich habe in der "int main(void)" ein Array definiert "int zeit[8];". 
Jetzt wird die Interruptroutine "ISR(TIMER1_OVF_vect)" ausgeführt. In 
dieser Interrupt Routine möchte ich das Integer Array aus der Main 
verändern. Die Veränderung soll später in der Main verfügbar sein.

Ich programmiere einen ATmega644 mit WinAVR im AVRstudio.

Vielen Dank für Eure Hilfe!

Gruß,
Christian.

von Ahem (Gast)


Lesenswert?

Das wird ohne Änderungen des Designkonzepts nicht gehen.

Ich verstehe Dich etwa so:
1
INTERRUPT (...)
2
{
3
   böses_array[13] = irgendwas;   // geht nicht
4
   nochwas = bböses_array[7];     // geht nicht
5
}
6
7
main ()
8
{
9
   char boeses_array[1234];
10
}

Auf diese Weise ist aber in der Interruptroutine das böse array garnicht 
sichtbar. Es ist nur_ und _ausschliesslich innerhalb von main 
sichtbar.

Du hast nun zwei Möglichkeiten, die aber letztlich darauf hinauslaufen 
eine Variable zu definieren, die zumindest innerhalb der 
Quelltexteinheit sichtbar ist (wenn nicht im gesamten Projekt).

Hier also die im allgemeinen gewählte Variante
1
volatile char gutes_array[1234];
2
3
INTERRUPT (...)
4
{
5
   gutes_array[2] = schoenes;
6
   bedeutendes = gutes_array[4];
7
}
8
9
main ()
10
{
11
   // irgendwas nettes
12
}

Die zweite Variante deklariert einen globalen Zeiger auf das Array.
Beachte, das kein Interrupt auftreten darf, ehe x gesetzt ist.
1
char * volatile x;
2
3
INTERRUPT (...)
4
{
5
   x + 2 = schoenes;
6
   bedeutendes = x + 4;
7
}
8
9
main ()
10
{
11
   volatile gutes_array[1234];
12
   x = gutes_array;
13
   // enable interrupts   
14
   // irgendwas nettes
15
}

von Ahem (Gast)


Lesenswert?

Sorry, in der zweiten Variante lautet der Code sinnvollerweise etwa
1
...
2
3
INTERRUPT (...)
4
{
5
   *x + 2 = schoenes;
6
   bedeutendes = *x + 4;
7
}
8
9
...

von ... (Gast)


Lesenswert?

... noch sinvoller wäre allerdings:
1
...
2
3
INTERRUPT (...)
4
{
5
   *(x + 2) = schoenes;
6
   bedeutendes = *(x + 4);
7
}
8
9
...
bzw.
1
...
2
3
INTERRUPT (...)
4
{
5
   x[2] = schoenes;
6
   bedeutendes = x[4];
7
}
8
9
...

von Christian B. (chrblank)


Lesenswert?

Moin!

Herzlichen Dank! Man war ich verbohrt, klar, so geht es! Danke! Bin aus 
diesem Übergabe-Denken nicht raus gekommen, anstatt es einfach mal 
"global" zu machen.

Vielen Dank noch mal!
Christian.

von tuppes (Gast)


Lesenswert?

> Du hast nun zwei Möglichkeiten, die aber letztlich
> darauf hinauslaufen eine Variable zu definieren,
> die zumindest innerhalb der Quelltexteinheit sichtbar
> ist (wenn nicht im gesamten Projekt).

> Hier also die im allgemeinen gewählte Variante ...

> Die zweite Variante deklariert einen globalen Zeiger
> auf das Array. Beachte, das kein Interrupt auftreten
> darf, ehe x gesetzt ist.

Was ist der Vorteil der zweiten Variante gegenüber der ersten? Ich kann 
keinen erkennen. Nachteile sind dagegen erheblich:

1. Du sagst es schon, man muss verhindern, dass ein Interrupt ausgelöst 
wird, bevor die Zeigervariable vorbereitet ist.
2. Globale Zeiger auf lokale Daten und Schreibzugriff zu unbestimmten 
Zeitpunkten - ganz böse. Ist hier nur deshalb nicht tragisch weil man in 
der Main-Funktion normalerweise immer drin bleibt. Bei jeder anderen 
Funktion, die auch wieder verlassen werden kann, wäre das der sichere 
Weg zur Stack-Corruption - absolut tödlich fürs Programm.
3. Das Ganze ist offenbar derart kompliziert, dass du selber drei 
Anläufe gebraucht hast, um es richtig hinzuschreiben.
4. Obendrein muss man sich Gedanken darum machen, ob char * volatile x 
wirklich dasselbe ist wie volatile char * x - ich bin mir da nicht 
sicher, hab aber keine Lust, drüber nachzudenken, weil ich so (aus o.g. 
Gründen) nie programmieren würde.

von Christian B. (chrblank)


Lesenswert?

Moin!

Ja dein Einwand ist mehr als berechtigt, ist aber für mich erst mal kein 
Problem. Die Interruptroutine dient nur, um einen Zähler im Sekundentakt 
hoch oder runter zu zählen. Erst wenn der Zähler und damit der Interrupt 
abgestellt ist, möchte ich den letzten Wert des Zählers in das Array 
speichern. Sprich, wenn ich auf das Datenelement zugreife, kann 
programmtechnisch kein Interrupt mehr aktiv sein, der diese Daten 
korrumpieren könnte.

Nichts desto trotz interessiert mich, falls du magst, der saubere 
Lösungsansatz sehr. Wenn ich mich nicht irre kann man ja einer Interrupt 
Routine keine Werte übergeben oder welche zurückgeben. Wie kann man also 
Ergebnisse aus einer Interrupt Routine in den sonstigen Programmlauf 
einbringen ohne globale Variablen?

Gruß,
Christian.

von Karl H. (kbuchegg)


Lesenswert?

Christian Blank wrote:

> Ergebnisse aus einer Interrupt Routine in den sonstigen Programmlauf
> einbringen ohne globale Variablen?

Gar nicht.
Egal welchen Weg du gehst, es ist immer mindestens eine globale 
Variable beteiligt.

von Stefan E. (sternst)


Lesenswert?

tuppes wrote:

> Was ist der Vorteil der zweiten Variante gegenüber der ersten? Ich kann
> keinen erkennen. Nachteile sind dagegen erheblich:

Es gibt durchaus sinnvolle Anwendungen für sowas.

> 1. Du sagst es schon, man muss verhindern, dass ein Interrupt ausgelöst
> wird, bevor die Zeigervariable vorbereitet ist.

Sinnvollerweise überprüft man in der ISR den Pointer erstmal auf 
ungleich 0.

> 2. Globale Zeiger auf lokale Daten und Schreibzugriff zu unbestimmten
> Zeitpunkten - ganz böse. Ist hier nur deshalb nicht tragisch weil man in
> der Main-Funktion normalerweise immer drin bleibt. Bei jeder anderen
> Funktion, die auch wieder verlassen werden kann, wäre das der sichere
> Weg zur Stack-Corruption - absolut tödlich fürs Programm.

Man benutzt sowas normalerweise nur mit statischen lokalen Variablen, 
nicht mit automatischen.

> 4. Obendrein muss man sich Gedanken darum machen, ob char * volatile x
> wirklich dasselbe ist wie volatile char * x - ich bin mir da nicht
> sicher, hab aber keine Lust, drüber nachzudenken, weil ich so (aus o.g.
> Gründen) nie programmieren würde.

Was hat das miteinander zu tun? Bei einem Pointer muss man sich doch 
immer Gedanken machen, ob der Pointer selber, oder das Ziel des Pointers 
volatile sein muss.

von tuppes (Gast)


Lesenswert?

> Es gibt durchaus sinnvolle Anwendungen für sowas.

> Man benutzt sowas normalerweise nur mit statischen
> lokalen Variablen, nicht mit automatischen.

na gut, meinetwegen. Das ist zumindest nicht so gefährlich.

Aber trotzdem bleibt die Geschichte kompliziert. Die Funktion, die die 
Variable besitzt, muss einmal gelaufen sein, damit der Pointer gesetzt 
ist.

Bei diesem ersten Durchlauf darf sie die Daten in der Variablen noch 
nicht benutzen, das darf sie erst, nachdem sie den Pointer gesetzt hat 
UND DANACH der Interrupt einmal gekommen ist und die Variable mit was 
Sinnvollem gefüllt hat.

Die ISR ihrerseits muss zeitlebens den Pointer gegen 0 checken, bevor 
sie Daten setzen darf.

Ganz schön viel Protokoll.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.