Forum: Mikrocontroller und Digitale Elektronik LED ansteuerung interruptgesteuert


von Rafi D. (alexanderw)


Lesenswert?

Hallo Community,

LED's per µC zum leuchten zu bringen ist ja kein Ding. Jetzt wollte ich 
sie interruptgestuert steuern, da ich delay nicht verwenden möchte, bzw. 
nicht kann (mein Programm ist hauptsächlich interruptgestuert). Der Code 
soll ja nicht für ms immer angehalten werden.
Normalerweise hab ich mir gedacht das bei bestimmten Ereignisen, wo die 
LED's leuchten sollen, ein Timerinterrupt auslöst. Die LED leuchtet für 
500ms und dann gehts sie wieder aus und die Timer-ISR ist zu ende.

So jetzt hab ich das Problem das ich mehrere LED's ansteuern möchte. Für 
ein entsprechendes Erreignis leuchtet die entsprechende Diode auf. Zur 
zeit sind es 3 Zustände, später werden es mehr.

Wie kann ich jetzt die Timer-ISR etsprechend der 3 verschiedenen 
Zustände starten? Ein Controller hat doch meistens nicht so viele Timer, 
oder?
Oder gibts es eine andere Möglichkeit der LED ansteuerung ohne delay?

Achja: Die Ereignise laufen nicht nach einem Schema ab, sodass ich einen 
Zähler von 1-3 laufenlassen könnte und dann entsprechend der Zahl die 
LED's aufleuchten lasse.

Danek im vorraus

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

3 Zähler in einer Timer-ISR sollten Deinen Bedingungen genügen.

In dem Hauptprogramm setzt Du den Zähler (z.B. auf 100 für 500 msec), in 
der ISR zählst Du ihn runter. Wenn er auf 0 ist, schaltest Du die LED 
ab.

Wenn Du die 3 Zähler als Array realisierst, kannst Du das schnell auf 
5,7,usw. LEDs erweitern.

von Falk B. (falk)


Lesenswert?

@  Rafi Dafi (alexanderw)

>LED's per µC zum leuchten zu bringen ist ja kein Ding. Jetzt wollte ich
>sie interruptgestuert steuern, da ich delay nicht verwenden möchte,

Gute Einstellung.

>LED's leuchten sollen, ein Timerinterrupt auslöst. Die LED leuchtet für
>500ms und dann gehts sie wieder aus und die Timer-ISR ist zu ende.

Fast.

>Wie kann ich jetzt die Timer-ISR etsprechend der 3 verschiedenen
>Zustände starten? Ein Controller hat doch meistens nicht so viele Timer,
>oder?

Wozu auch. Alles was du brauchst ist EIN Timer und eine 
statemachine.

>Achja: Die Ereignise laufen nicht nach einem Schema ab, sodass ich einen
>Zähler von 1-3 laufenlassen könnte und dann entsprechend der Zahl die
>LED's aufleuchten lasse.

Jedes noch so merkwürdige Schema ist mit einer statemachine sehr 
einfach umsetzbar. Ist am Ende eine einfache Tabelle, wo man 
reinschreibt was man haben möchte.

von Karl H. (kbuchegg)


Lesenswert?

Rafi Dafi schrieb:

> Normalerweise hab ich mir gedacht das bei bestimmten Ereignisen, wo die
> LED's leuchten sollen, ein Timerinterrupt auslöst.

Hier hast du deinen Denkfehler.
Du setzt den Timer nicht so auf, dass du mit einem 'Timerlauf' genau die 
zu erzielende Zeit durch einen einzigen Interrupt erzeugst.

Stell dir das eher wie deine Uhr vor. Du stellst den Timer so ein, dass 
er dir den Sekundenzeiger deiner Uhr realisiert. Und mit dem kannst du 
ja auch 28 Sekunden abzählen, indem du mitzählst, wie oft der Zeiger um 
1 Position vorrückt (oder eben von 28 auf 0 runterzählst). Und das 
kannst du mit vielen Zeitdauern gleichzeitig machen, obwohl du nur 1 
Sekundenzeiger auf deiner Uhr hast.

Den Rest, wie man das dann technisch konkret machen kann, hat Frank ja 
schon angesprochen.

von Rafi D. (alexanderw)


Lesenswert?

AHA-Effekt...

Ich setzte beim Ereignis den Timer und schalte die LED ein. Wenn die 
Timer-ISR abgelaufen ist(500ms) dann werden einfach alle LED's 
ausgeschaltet...

Richtig,meine Denkweise?

von Detlev T. (detlevt)


Lesenswert?

Wie wäre folgendes: Die ISR wird Timer gesteuert regelmäßig aufgerufen 
(z.B alle 10ms). Für jede LED gibt es einen Zähler. Ist dieser ungleich 
null, dekrementiert die ISR ihn und schaltet die zugehörige LED ein, 
ansonsten schaltet er die LED aus.

Das Hauptprogramm muss dann nur noch den Zähler auf einen Wert ungleich 
null setzen.

von Falk B. (falk)


Lesenswert?

@  Rafi Dafi (alexanderw)

>Ich setzte beim Ereignis den Timer und schalte die LED ein. Wenn die
>Timer-ISR abgelaufen ist(500ms) dann werden einfach alle LED's
>ausgeschaltet...

>Richtig,meine Denkweise?

Fast. Du setzt einen Timer, der deine kleinste, benötigte Zeiteinheit 
darstellt, sei es nun 500ms oder sonstwas. Damit hast du ein festes 
Zeitraster, indem du deine Schaltvorgänge durchführen kannst. Siehe 
Artikel statemachine und Multitasking.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rafi Dafi schrieb:
> Richtig,meine Denkweise?

Nein. Du lässt einen Timer einfach durchlaufen und lässt diesen zum 
Beispiel die ganze Zeit jede hundertstel Sekunde einen Interrupt 
ausführen, normalerweise einen Overflow-Interrupt.

Jetzt hast Du also eine ISR, die 100 mal in der Sekunde aufgerufen wird,
also
1
static volatile uint8_t counter;
2
3
ISR(....)
4
{
5
   if (counter > 0)
6
   {
7
      counter--;
8
      if (counter == 0)
9
      {
10
         LED_AUS;
11
      }
12
   }
13
}
14
15
int main ()
16
{
17
    ...
18
19
    LED_AN;
20
    counter = 50;                // nach 500ms ist counter auf 0
21
    ...
22
}

Das Erweitern auf ein Array für N LEDs überlasse ich Dir.

von Karl H. (kbuchegg)


Lesenswert?

Rafi Dafi schrieb:
> AHA-Effekt...
>
> Ich setzte beim Ereignis den Timer

Kommt drauf an, wie du das jetzt meinst.

Der Timer, also das physische Teil in deinem µC, ... den lässt du 
einfach dauernd laufen! Es gibt keinen Grund warum man den dauernd 
starten und stoppen müsste.

Es sind die Countdown-Zähler, die dir die Software-Einzeltimer für 
unterschiedliche LED oder LED-Gruppen generieren!
1
volatile int16_t TimerA;
2
volatile int16_t TimerB;
3
4
5
ISR( .... )     // wird jede 1 Millisekunde aufgerufen
6
{
7
  if( TimerA > 0 )
8
  {
9
    TimerA --;
10
    if( TimerA == 0 )
11
      schalte LED
12
  }
13
14
  if( TimerB > 0 )
15
  {
16
    TimerB --;
17
    if( TimerB == 0 )
18
      schalte andere LED
19
  }
20
}
21
22
int main()
23
{
24
  Timer aufsetzen und starten
25
26
  sei();
27
28
  while( 1 ) {
29
30
     if( irgendwas )
31
     {
32
       LED einschalten
33
       cli();
34
       TimerA = 500;  // zb 500 Millisekunden, weil die ISR jede 1ms aufgerufen wird
35
                      // und bei jedem Aufruf wird der Wert um 1 runtergezählt
36
       sei();
37
     }
38
39
     if( irgendwas ganz anderes )
40
     {
41
       andere LED einschalten
42
       cli();
43
       TimerB = 300;   // zb 300
44
       sei();
45
     }
46
  }
47
}


Und was mit 2 Software-Countdowns geht, geht auch mit 200. Nur wird man 
dann sinnvollerweise ein Array nehmen und nicht 200 Einzeln-Variablen.

von Axel S. (a-za-z0-9)


Lesenswert?

Rafi Dafi schrieb:
> Normalerweise hab ich mir gedacht das bei bestimmten Ereignisen, wo die
> LED's leuchten sollen, ein Timerinterrupt auslöst. Die LED leuchtet für
> 500ms und dann gehts sie wieder aus und die Timer-ISR ist zu ende.

Du willst in der ISR 500ms warten? Blöde Idee!

Rafi Dafi schrieb:
> Wie kann ich jetzt die Timer-ISR etsprechend der 3 verschiedenen
> Zustände starten? Ein Controller hat doch meistens nicht so viele Timer

Du brauchst mitnichten so viele (Hardware-)Timer wie du LED hast. Du 
brauchst nur genau einen Timer und etwas Grips.

Eine mögliche Lösung für zwei LED und einen Timer sähe z.B. so aus:

1
volatile uint8_t led1_timer;
2
volatile uint8_t led2_timer;
3
4
void led_an(uint8_t led_nr, uint8_t zeit) {
5
  if (led_nr == 1) {
6
    led1_an();
7
    led1_timer= zeit;
8
  }
9
  if (led_nr == 2) {
10
    led2_an();
11
    led2_timer= zeit;
12
  }
13
}
14
15
void led_isr(void) {
16
  if (led1_timer) {
17
    led1_timer--;
18
    if (led1_timer == 0) {
19
      led1_aus();
20
    }
21
  }
22
  if (led2_timer) {
23
    led2_timer--;
24
    if (led2_timer == 0) {
25
      led2_aus();
26
    }
27
  }
28
}

die Makros ledX_an und ledX_aus mußt du natürlich bereit stellen. 
Und du mußt led_isr() regelmäßig aufrufen, z.B. jede Millisekunde aus 
einer Timer-ISR. Die zeit oben ist dann in Vielfachen der Timerperiode 
gemessen, die du aber dank CTC Mode und Compare-Einheit beliebig 
festlegen kannst.

Für viele LED nimmt man natürlich besser ein Array für die ledX_timer 
Variablen. Und für längere Zeiten und/oder feinere Auflösung braucht man 
evtl. einen breiteren Typ als uint8_t.


XL

von Peter D. (peda)


Lesenswert?

Rafi Dafi schrieb:
> Die Ereignise laufen nicht nach einem Schema ab

Alles läßt sich in einem Schema ausdrücken. Du mußt nur erstmal 
festlegen, was Du eigentlich willst.

Da es um LEDs geht, dürften 10ms als kleinste Schrittweite ausreichend 
sein. d.h. Du setzt einen Timer 10ms auf.
Und jedesmal, wenn der Timer abläuft, liest Du aus einer Tabelle das 
Muster der LEDs und die Dauer (in 10ms Schritten) bis zur nächsten 
Änderung.
Die Zeitdauer 0 kann man dafür reservieren, daß die Tabelle zuende ist 
und Du fängst wieder von vorn an.


Peter

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.