Forum: Mikrocontroller und Digitale Elektronik ISR mit Zustandsmaschine


von Jens K. (Gast)


Angehängte Dateien:

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

von Stefan E. (sternst)


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
1
    static U8 Zustand;
2
    Zustand = LED_Ein;
durch
1
    static U8 Zustand = LED_Ein;

von static_LED_Ein (Gast)


Lesenswert?

schreib anstatt:

 static U8 Zustand;
 Zustand = LED_Ein;

einfach:
 static U8 Zustand = LED_Ein;

von Jens K. (Gast)


Lesenswert?

Danke für den Tipp.
Leider besteht das Problem weiterhin.

Was könnte denn noch falsch sein?

von Jens K. (Gast)


Angehängte Dateien:

Lesenswert?

Hier nochmal die aktuelle ISR-Routine...

von Karl H. (kbuchegg)


Lesenswert?

Diese Dinge hier
1
        AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
2
3
        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?

von Jens K. (Gast)


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?

von Karl H. (kbuchegg)


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
1
enum {LED_Ein, LED_Aus};
2
3
__ramfunc void ISR_Clock_Ausgabe (void)
4
{
5
    static U8 Zustand = LED_Ein;
6
    static U8 Counter = 0;
7
8
    Counter++;
9
    if( Counter == 10 ) {
10
      Counter = 0;
11
12
      switch (Zustand)
13
      {
14
      case LED_Ein:
15
        AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
16
        Zustand = LED_Aus;
17
        break;
18
19
      case LED_Aus:
20
        AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
21
        Zustand = LED_Ein;
22
        break;
23
24
      default:
25
        break;
26
    }
27
  }
28
}

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
1
    if( Counter == 10 ) {
2
      Counter = 0;
3
4
      .... 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

von Jens K. (Gast)


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!?

von Karl H. (kbuchegg)


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?

von Jens K. (Gast)


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???

von Karl H. (kbuchegg)


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)

von Jens K. (Gast)


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.

von Jens K. (Gast)


Lesenswert?

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

von Jens K. (Gast)


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?

von gastlich (Gast)


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.

von Jens K. (Gast)


Lesenswert?

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

Welche Geschichte denn???

von gastlich (Gast)


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 :
1
enum {LED_Ein, LED_Aus};
2
static U8 Zustand = LED_Ein;
3
static U8 Counter = 0;
4
5
__ramfunc void ISR_Clock_Ausgabe (void)
6
{
7
    Counter++;
8
    if( Counter == 10 ) {
9
      Counter = 0;
10
11
      switch (Zustand)
12
      {
13
      case LED_Ein:
14
        AT91C_BASE_PIOA->PIO_CODR = LED_AUSGABE; // LED on
15
        Zustand = LED_Aus;
16
        break;
17
18
      case LED_Aus:
19
        AT91C_BASE_PIOA->PIO_SODR = LED_AUSGABE; // LED off
20
        Zustand = LED_Ein;
21
        break;
22
23
      default:
24
        break;
25
    }
26
  }
27
}

von gastlich (Gast)


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 :
1
static volatile U8 Zustand = LED_Ein;
2
static volatile U8 Counter = 0;

von Jens K. (Gast)


Lesenswert?

gastlich schrieb:
> probier mal das :

Leider hat dein Vorschlag das Problem nicht gelöst.

von Jens K. (Gast)


Lesenswert?

auch volatile hat keine Auswirkungen...

von gastlich (Gast)


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.

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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.

von gastlich (Gast)


Lesenswert?

initialisierung ? wo ?

innerhalb der ISR nutzt die nichts ...

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

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

gruss

von Karl H. (kbuchegg)


Lesenswert?

gastlich schrieb:
> initialisierung ? wo ?
>
> innerhalb der ISR nutzt die nichts ...

Oh Mann.
Lern C!

Du verzapfst hier einen Unsinn nach dem anderen.

von Karl H. (kbuchegg)


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.

von gastlich (Gast)


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 ...

von gastlich (Gast)


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 ...

von Karl H. (kbuchegg)


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.

von Jens K. (Gast)


Angehängte Dateien:

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.

von Karl H. (kbuchegg)


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

von Jens K. (Gast)


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!!!

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.