www.mikrocontroller.net

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


Autor: Christian Blank (chrblank)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ahem (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wird ohne Änderungen des Designkonzepts nicht gehen.

Ich verstehe Dich etwa so:
INTERRUPT (...)
{
   böses_array[13] = irgendwas;   // geht nicht
   nochwas = bböses_array[7];     // geht nicht
}

main ()
{
   char boeses_array[1234];
}

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
volatile char gutes_array[1234];

INTERRUPT (...)
{
   gutes_array[2] = schoenes;
   bedeutendes = gutes_array[4];
}

main ()
{
   // irgendwas nettes
}


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

INTERRUPT (...)
{
   x + 2 = schoenes;
   bedeutendes = x + 4;
}

main ()
{
   volatile gutes_array[1234];
   x = gutes_array;
   // enable interrupts   
   // irgendwas nettes
}


Autor: Ahem (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, in der zweiten Variante lautet der Code sinnvollerweise etwa

...

INTERRUPT (...)
{
   *x + 2 = schoenes;
   bedeutendes = *x + 4;
}

...


Autor: ... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... noch sinvoller wäre allerdings:
...

INTERRUPT (...)
{
   *(x + 2) = schoenes;
   bedeutendes = *(x + 4);
}

...
bzw.
...

INTERRUPT (...)
{
   x[2] = schoenes;
   bedeutendes = x[4];
}

...

Autor: Christian Blank (chrblank)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian Blank (chrblank)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.