Zugriff auf Array aus Main in Interrupt-Routine

OP #1214502
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.
Gast #1214513
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
}
Gast #1214543
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
...
Gast #1214721
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.
OP #1214736
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.
#1214747
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.
Gast #1214894
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren