Hallo! Ich habe ein Problem mit einer globalen Variable und der Timer ISR. Es werden per Funk 3 Bytes Empfangen. "BA1" "000" ... "BA2" "000" ... "BA1" "000" ... Wenn nun ein "BAx" kommt, soll eine Gewisse Zeit lang Led1 bzw Led2 leuchten. Das ganze funktioniert auch so wies soll, wenn die if-Abfragen in der ISR sind. Verschiebe ich jedoch die Abfragen in die while(1)-Schleife, leuchten beide Leds dauerhaft. Sieht so aus, als ob es was mit der Zähl-Variable zu tun hat. Ich hab hier im Forum schon gesucht, hab volatile hinzugefügt, funktioniert aber leider immer noch nicht. Programmiert wird ein ATmega8 in C. Getestet wird mit einer realen Hardware. Code ist im Anhang. Danke für eure Hilfe.
Alle globalen Variablen, auf die Du in der ISR und woanders zugreifst, müssen volatile deklariert werden. Bei "counter_light" hast Du dieses gemacht, warum nicht auch bei "name"?
Frank M. schrieb: > Verschiebe ich jedoch die Abfragen in die while(1)-Schleife, > leuchten beide Leds dauerhaft. Und wie erzeugst Du in diesem Fall das Zeitverhalten? Zeig doch mal den Code, der nicht tut!
Ziel ist eigentlich, dass die if(counter_light <= DAUER_LICHT)-Abfrage in die while(1)-Schleife kommt. In die ISR sollte doch möglichst wenig Code oder? Verschiebe ich die Abfrage ins Hauptprogramm, greife ich in der ISR nur mehr auf counter_light, und auf name nur mehr im Hauptprogramm zu. Jedoch leuchten dann beide Leds dauerhaft. Ich werd aber auch name volatile deklarieren und schauen obs was bringt.
Im Anhang ist jetzt das Programm, wo beide Leds nach einem empfangenen "BA1" und "BA2" dauerhaft leuchten.
Philipp S. schrieb: > Ziel ist eigentlich, dass die if(counter_light <= DAUER_LICHT)-Abfrage > in die while(1)-Schleife kommt. In die ISR sollte doch möglichst wenig > Code oder? Jain. Es ist aber auch nicht so, dass man in einer ISR gar nichts tun darf und ausnahmslos alles und jedes in die Hauptschleife verschieben muss. In einer ISR sollte man sich hüten vor * Ausgaben aller Art auf LCD und UART * längere Berechnungen ein paar Variablen zu erhöhen, gegen eine Grenze zu testen und daraufhin ein paar Portpins zu schalten (die nur in der ISR benutzt werden), ist schon ok. Das ist beileibe noch nicht 'zuviel'. Ganz im Gegenteil hat man dadurch die Gewissheit, dass genau diese Funktionalität auch dann weiterläuft, wenn in der Hauptschleife viel zu tun ist, weil zb der Benutzer in einem Menü rumfuhrwerkt. Es ist schliesslich nicht wirklich einzusehen, warum ein Lauflicht plötzlich aufhören soll zu laufen, nur weil der Benutzer gerade an einem Parameter für die UART rumstellt und die Hauptschleife keine Zeit hat sich um das Lauflicht zu kümmern. Legt man aber das Weiterschalten des Lauflichts (das ja nicht viel Zeit kostet) in die ISR, dann läuft das dann auch in diesen Fällen noch sauber weiter. Dei Abschaltung einer Lampe nach 10 Sekunden muss auch dann zuverlässig nach 10 Sekunden erfolgen, wenn der Benutzer gerade am Einstellmenü für die Helligkeit der LCD Beleuchtung rumspielt. Also: Es stimmt schon, dass man ISR nicht zu lang machen soll. Aber man muss das auch nicht als Dogma sehen, dass man gar nichts tun darf.
Tja. Wenn rf01_rxdata(data, 3); darauf wartet, dass 3 Bytes empfangen werden, dann wird der restliche Code danach solange nicht ausgeführt, BIS dann irgendwann 3 Bytes empfangen werden. Dein Code ist ein klassisches Beispiel dafür, was man besser mit einer ISR abhandelt. In der Hauptschleife wird etwas eingeschaltet, ein entsprechender Timer-Mechanmismus wird installiert, der nach einer gewissen Zeit selbsttätig und ohne Zutun der Hauptschleife die Abschaltung vornimmt.
oh. Soweit hab ich nicht gedacht, dass der Fehler beim Daten empfangen liegt. Vielen Dank Karl Heinz. Werd die Abfragen nun in der ISR lassen.
Und PS. AM einfachsten ist es, wenn du für jede LED so etwas wie eine Countdown-Uhr vorsiehst (eine Eieruhr) D.h. in der Hauptschleife wird die Uhr auf 10 Sekunden gestellt und in der ISR wird jede Sekunde der der LED zugeordnete Countdown um 1 heruntergezählt. Hat der jeweilige Countdown den Wert 0 erreicht, dann schaltet man in der ISR den entsprechenden Ausgang aus. So rum geht es einfacher. Vor allen Dingen auch deshalb, weil du in der Hauptschleife dann diesen Countdown auch ganz einfach wieder zurücksetzen kannst und weil du viele derartige Stufen einbauen kannst, die dann auch unabhängig voneinander eine Zeit abzählen. Warum soll LED 1 nicht nach 20 Sekunden abschalten und irgendwann mitten drinnen (während LED 1 noch 13 Sekunden zu brennen hat) kommt der Befehl LED 2 einzuschalten und nach 4 Sekunden wieder auszuschalten? Mit einer 'Eieruhr' für jede LED ist das alles kein Thema. Sind nur ein paar Variablen. Mehr nicht
1 | volatile uint8_t Timer1; |
2 | volatile uint8_t Timer2; |
3 | |
4 | ISR( .... ) |
5 | {
|
6 | if( Timer1 > 0 ) |
7 | {
|
8 | Timer1--; |
9 | if( Timer1 == 0 ) |
10 | PORT..... // LED 1 ausschalten |
11 | }
|
12 | |
13 | if( Timer2 > 0 ) |
14 | {
|
15 | Timer2--; |
16 | if( Timer2 == 0 ) |
17 | PORT.... // LED 2 ausschalten |
18 | }
|
19 | }
|
20 | |
21 | int main() |
22 | {
|
23 | ...
|
24 | |
25 | while( 1 ) |
26 | {
|
27 | |
28 | ....
|
29 | if( irgendwas ) |
30 | {
|
31 | PORT.... // LED 1 einschalten |
32 | Timer1 = ... // und Timer1 auf einen Wert setzen, so dass die |
33 | // ISR die LED nach der gewünschten Zeit wieder
|
34 | // ausschaltet
|
35 | }
|
36 | |
37 | if( irgendwas_anderes ) |
38 | {
|
39 | PORT.... // LED 2 einschalten |
40 | Timer2 = ... // und Timer2 auf einen Wert setzen, so dass die |
41 | // ISR die LED nach der gewünschten Zeit wieder
|
42 | // ausschaltet
|
43 | }
|
44 | }
|
45 | }
|
Und PS: den Timer lässt du ganz einfach ständig durchlaufen und die Konfigurationsflags lässt du in in der Hauptschleife in Ruhe. Es stört nicht, wenn man einen bereits abgeschalteten Pin nochmals abschaltet.
Danke für deinen Denkanstoß! Klingt einfacher so. Werd ich gleich ausprobieren. Danke!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.