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
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.
@ 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.
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.
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?
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.
@ 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.
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
staticvolatileuint8_tcounter;
2
3
ISR(....)
4
{
5
if(counter>0)
6
{
7
counter--;
8
if(counter==0)
9
{
10
LED_AUS;
11
}
12
}
13
}
14
15
intmain()
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.
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.
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 zweiLED und einen Timer sähe z.B. so aus:
1
volatileuint8_tled1_timer;
2
volatileuint8_tled2_timer;
3
4
voidled_an(uint8_tled_nr,uint8_tzeit){
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
voidled_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
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