Zugriff auf Array aus Main in Interrupt-Routine

OP #1214502
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
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
... 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
> 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
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
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
> 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

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.