ISR mit Zustandsmaschine

Gast #1632153
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
Angehängte Dateien:
#1632202
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?
Gast #1632206
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?
#1632251
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
Gast #1632284
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!?
#1632289
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?
Gast #1632309
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???
#1632316
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)
Gast #1632326
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.
Gast #1632429
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.
Gast #1632437
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
}
Gast #1632440
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;
Gast #1632455
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.
#1632458
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.
#1632459
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.
Gast #1632463
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
#1632472
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.
Gast #1632475
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 ...
#1632481
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.
#1632504
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
Gast #1632521
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

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