mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ISR mit Zustandsmaschine


Autor: Jens K. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte auf einem Evaluation Board LEDs blinken lassen. Die LEDs 
sollen in der ISR ein- und ausgeschaltet werden. Dazu benutze ich einen 
Timer, der alle 0,5s einen Interrupt auslöst. Bei jedem Interrupt soll 
sich der LED-Zustand ändern.
Das Problem ist, dass die LEDs immer eingeschaltet sind.

Da mir diese Lösung nahegelegt wurde und ich selbst nicht unbeding eine 
Ahnung von Zustandsmaschinen habe, bitte ich euch um Hilfestellung.

Im Anhang habe ich die ISR-Routine beigefügt.

Gruß Jens

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:
> Das Problem ist, dass die LEDs immer eingeschaltet sind.

Logisch, das erste, was du in der ISR auch machst, ist "Zustand" auf 
"LED_Ein" zu setzen.

Ersetze
    static U8 Zustand;
    Zustand = LED_Ein;
durch
    static U8 Zustand = LED_Ein;

Autor: static_LED_Ein (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
schreib anstatt:

 static U8 Zustand;
 Zustand = LED_Ein;

einfach:
 static U8 Zustand = LED_Ein;

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Tipp.
Leider besteht das Problem weiterhin.

Was könnte denn noch falsch sein?

Autor: Jens K. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier nochmal die aktuelle ISR-Routine...

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

Bewertung
0 lesenswert
nicht lesenswert
Diese Dinge hier
        AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on

        AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
sind korrekt?

Die ISR wird regelmässig aufgerufen?
Wie schnell wird die eigentlich aufgerufen? (*)

Wenn die mehr als, sagen wir mal 30 mal in der Sekunde aufgerufen wird, 
wirstdu das Blinken nicht mehr sehen.

(*) Ich zieh die Frage zurück und stelle eine Neue
> Dazu benutze ich einen Timer, der alle 0,5s einen Interrupt auslöst.
Hast du das kontrolliert?

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Diese Dinge hier
>         AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
>
>         AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
> sind korrekt?

das ist korrekt.
Der Timer ist so eingestellt, dass die ISR-Routine alle 0,5s aufgerufen 
werden sollte.
Wie kann ich denn überprüfen, wie oft uns schnell sie aufgerufen wird?

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

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:
> Karl heinz Buchegger schrieb:
>> Diese Dinge hier
>>         AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
>>
>>         AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
>> sind korrekt?
>
> das ist korrekt.
> Der Timer ist so eingestellt, dass die ISR-Routine alle 0,5s aufgerufen
> werden sollte.
> Wie kann ich denn überprüfen, wie oft uns schnell sie aufgerufen wird?

Led blinken lassen :-)
(Jetzt haben wir ein Henne/Ei Problem)

Probier mal sowas
enum {LED_Ein, LED_Aus};

__ramfunc void ISR_Clock_Ausgabe (void)
{
    static U8 Zustand = LED_Ein;
    static U8 Counter = 0;

    Counter++;
    if( Counter == 10 ) {
      Counter = 0;

      switch (Zustand)
      {
      case LED_Ein:
        AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
        Zustand = LED_Aus;
        break;

      case LED_Aus:
        AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
        Zustand = LED_Ein;
        break;

      default:
        break;
    }
  }
}

und dann schraubst du die 10 hoch, bis
* du bei einer sehr großen Zahl angelangt bist
* oder die LED irgendwann zu flimmern und dann zu blinken anfängt

In deinem Code ist jedenfalls nichts zu entdecken, warum das kein 
Blinken stattfinden sollte.

Hast du vielleicht noch eine 2-te LED zur Verfügung?
Wenn ja, dann schalte die mal hier
    if( Counter == 10 ) {
      Counter = 0;

      .... hier LED einschalten
zusätzlich ein und sieh nach, ob das passiert (dann weist du, dass die 
ISR aufgerufen wird.
Auch den Gegentest machen: dort die LED ausschalten

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe deinen Vorschlag ausprobiert Karl Heinz.

Die zweite LED leuchtet, also die ISR wird aufgerufen

Nachdem ich den Counter-Wert bis auf 300.000 hochgeschraubt habe, blinkt 
die LED nunannäherng mit 1 Hz.

Es scheint also an der Timereinstellung zu liegen!?

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

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:

> Nachdem ich den Counter-Wert bis auf 300.000 hochgeschraubt habe

Ich hoffe du hast auch berücksichtigt, dass ein U8 (8 Bit Datentyp?) von 
Haus aus nur bis 255 zählen kann :-)

> Es scheint also an der Timereinstellung zu liegen!?

Sieht wohl so aus :-)

Kann es sein, dass deine 0.5 sich nicht auf Sekunden sondern auf 
Millisekunden bezieht?

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Ich hoffe du hast auch berücksichtigt, dass ein U8 (8 Bit Datentyp?) von
> Haus aus nur bis 255 zählen kann :-)

Natürlich (habe auf 32 Bit angepasst)!

Ich habe was Lustiges festgestellt. Ändere ich die Timereinstellungen, 
dann ändert sich nichts an dem Takt; das heißt, die LED blinkt mit dem 
gleichen Takt weiter. Wie kann das denn sein???

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

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:
> Karl heinz Buchegger schrieb:
>> Ich hoffe du hast auch berücksichtigt, dass ein U8 (8 Bit Datentyp?) von
>> Haus aus nur bis 255 zählen kann :-)
>
> Natürlich (habe auf 32 Bit angepasst)!

Brav.
War nur so, dass mir 300000 ein wenig hoch vorgekommen ist.

> Ich habe was Lustiges festgestellt. Ändere ich die Timereinstellungen,
> dann ändert sich nichts an dem Takt; das heißt, die LED blinkt mit dem
> gleichen Takt weiter. Wie kann das denn sein???

Richtiger Timer benutzt?
(Keine Ahnung. Ich hab ja noch nicht einmal rausgefunden welchen µC du 
benutzt. Ein AVR-Mega oder Tiny ist es nicht. Und von anderen µC versteh 
ich nichts)

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich benutze den AT91SAM7S256 - µC.

Das komische ist, dass ich vorher was Anderes programmiert hatte mit 
genau denselben Timereinstellungen, allerdings wurde dort der Takt in 
der ISR ausgegeben, ohne zwischendurch daraus zu gehen.

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also der Timer läuft auf jeden Fall richtig. Es scheint so, dass der 
Interrupt zu schnell ausgelöst wird...

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine Frage Karl Heinz:

Könnte es sein, dass die ISR nach dem ersten Durchlauf sofort wieder
aufgerufen wird, weil der Interrupt nicht zurückgesetzt wurde?

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
> Logisch, das erste, was du in der ISR auch machst, ist "Zustand" auf
> "LED_Ein" zu setzen.

hier stehts geschrieben !!!!

nimm die definition der Variable "Zustand" aus der Interrupt Routine 
raus !!!

du initialisierts sie bei jedem Aufruf von neuem und zwar immer gleich 
!!!

und vergiss nicht die geschichte mit dem volatile ...

gruss Claudio

ps: die Variable Counter sollte auch nicht in der ISR definiert und 
initialisiert werden.

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> und vergiss nicht die geschichte mit dem volatile ...

Welche Geschichte denn???

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> In deinem Code ist jedenfalls nichts zu entdecken, warum das kein
> Blinken stattfinden sollte.

sorry da kann ich nicht schweigen ....

natürlich ist da was faul ...

probier mal das :
enum {LED_Ein, LED_Aus};
static U8 Zustand = LED_Ein;
static U8 Counter = 0;

__ramfunc void ISR_Clock_Ausgabe (void)
{
    Counter++;
    if( Counter == 10 ) {
      Counter = 0;

      switch (Zustand)
      {
      case LED_Ein:
        AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
        Zustand = LED_Aus;
        break;

      case LED_Aus:
        AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
        Zustand = LED_Ein;
        break;

      default:
        break;
    }
  }
}

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
varliablen die in ISR verändert werden müssen als volatile declariert 
werden, ansonsten könnte der Compiler die Zugriffe wegoptimieren.
Da diese Variablen aber asynchron (zufällig) von der ISR verändert 
werden können dürfen Lesezugriffe nicht wegoptimiert werden...

das sieht dann in etwa so aus :
static volatile U8 Zustand = LED_Ein;
static volatile U8 Counter = 0;

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> probier mal das :

Leider hat dein Vorschlag das Problem nicht gelöst.

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
auch volatile hat keine Auswirkungen...

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hasst du einen Debugger, mit dem du übeprüfen kannst ob du in die 
Routine Springst ? und kanns du damit feststellen ob das Interruptbit 
wieder Gelöscht wird? allefalls musst du das Timerinterruptbit wieder 
löschen.

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

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> Stefan Ernst schrieb:
>> Logisch, das erste, was du in der ISR auch machst, ist "Zustand" auf
>> "LED_Ein" zu setzen.
>
> hier stehts geschrieben !!!!
>
> nimm die definition der Variable "Zustand" aus der Interrupt Routine
> raus !!!

Nö.
Dieser Punkt ist schon längst abgehakt.

Die Variable ist static und anstatt der Zuweisung hat er jetzt eine 
Initialisierung.
Das ist soweit alles korrekt.

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

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> Karl heinz Buchegger schrieb:
>> In deinem Code ist jedenfalls nichts zu entdecken, warum das kein
>> Blinken stattfinden sollte.
>
> sorry da kann ich nicht schweigen ....
>
> natürlich ist da was faul ...

Jungs.
Lernt C!

Ich weiß, das static immer wieder für Verwirrungen sorgt. Aber das ist 
alles korrekt, so wie er das macht.

> varliablen die in ISR verändert werden müssen als volatile declariert

Und wenn du schon dabei bist, lies auch noch mal über volatile nach und 
wann man diesen Modifier tatsächlich benötigt und warum.

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
initialisierung ? wo ?

innerhalb der ISR nutzt die nichts ...

hab mal in meinen Routinen nachgeschaut, da kommt diese zeile in der 
timer ISR vor :
tmp = AT91C_BASE_TC0->TC_SR;

da wird das statusregister gelesen, bin nicht sicher ob dass dann das 
Interruptflag löscht ...

gruss

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

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> initialisierung ? wo ?
>
> innerhalb der ISR nutzt die nichts ...

Oh Mann.
Lern C!

Du verzapfst hier einen Unsinn nach dem anderen.

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

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:
> Noch eine Frage Karl Heinz:
>
> Könnte es sein, dass die ISR nach dem ersten Durchlauf sofort wieder
> aufgerufen wird, weil der Interrupt nicht zurückgesetzt wurde?

Hmm.
Kann ich dir nicht sagen. Da musst du das Datenblatt zum Prozessor 
befragen. Es wär zwar unüblich, aber möglich wärs.

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soll ichs noch ausführen ?

ISR {

 //initialisierung der varibale Zustand

 //verwender der varibale zustand

 //verändern der variable zustand

}

meiner meinung nach wir beim verwenden der varibale immer der gleiche 
wert drin stehen ... es sei denn der compiler verschiebt wie durch ein 
wunder die intialisierung aus der isr raus .....

und komm jetzt nicht mit static und so ... die initialisierung findet in 
der isr statt ...

Autor: gastlich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry geb mich geschlagen, static macht tasächlich, das die 
intialisierung nur einmal stattfindet ...

sehr verwirrend ...

aber das mit dem isr-flag könnte das problem sein ...

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

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> soll ichs noch ausführen ?
>
> ISR {
>
>  //initialisierung der varibale Zustand
>
>  //verwender der varibale zustand
>
>  //verändern der variable zustand
>
> }
>
> meiner meinung nach wir beim verwenden der varibale immer der gleiche
> wert drin stehen ...

Deine Meinung steht in starkem Kontrast zu dem was die ISO-Norm für C 
dem Compiler vorschreibt was zu passieren hat.

> es sei denn der compiler verschiebt wie durch ein
> wunder die intialisierung aus der isr raus .....

(Hinter vorgehaltener Hand:
letzten Endes bleibt dem Compiler nichts anderes übrig. Das definieren 
der static Variablen in einer Funktion limitiert lediglich den Scope 
unter dem die Variable sichtbar ist, auf die Funktion. Im Grunde hat man 
damit eine File-globale Variable erzeugt, die allerdings nur in dieser 
Funktion zugänglich ist. Und genau genommen findet die Intialisierung 
beim ersten Betreten der Funktion statt. Findet die Intialisierung aber 
mit einer Konstanten statt, kann kein Mensch den Unterschied 
herausfinden, denn wie gesagt: Ausserhalb der Funktion existiert die 
Variable offiziell gar nicht)

>
> und komm jetzt nicht mit static und so ... die initialisierung findet in
> der isr statt ...

Es ist im C-Standard exakt geregelt, was mit der Initialisierung einer 
Variablen in einer Funktion zu geschehen hat.

Autor: Jens K. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
gastlich schrieb:
> hab mal in meinen Routinen nachgeschaut, da kommt diese zeile in der
> timer ISR vor :
> tmp = AT91C_BASE_TC0->TC_SR;

das hat leider auch nichts gebracht...

Ich poste nochmal die aktuelle ISR.

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

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:
> gastlich schrieb:
>> hab mal in meinen Routinen nachgeschaut, da kommt diese zeile in der
>> timer ISR vor :
>> tmp = AT91C_BASE_TC0->TC_SR;
>
> das hat leider auch nichts gebracht...
>
> Ich poste nochmal die aktuelle ISR.

Die ISR wird nicht viel bringen.
Du musst im Datenblatt nachlesen:
  Timereinstellung
  Wie ist das Interrupt Flag zu handhaben

Autor: Jens K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jens K. schrieb:
> gastlich schrieb:
>> hab mal in meinen Routinen nachgeschaut, da kommt diese zeile in der
>> timer ISR vor :
>> tmp = AT91C_BASE_TC0->TC_SR;
>
> das hat leider auch nichts gebracht...
>
> Ich poste nochmal die aktuelle ISR.

Leute, Entwarnung!
gastlich hat mit der obigen Aussage ins Schwarze getroffen. Ich habe nur 
vergessen, dass der Timer auf 250 kHz eingestellt war und nicht auf 1 
Hz. Jedenfalls funktioniert jetzt alles richtig!

Ich bedanke mich herzlich für Eure Hilfe!!!

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.