Datum:
Hallo Freunde ich möchte eine Variable (wait10), die von einem Timer über die ISR alle 10ms kommt mehrfach abfragen. Habe mal ein Stück eingestellt: if (wait10 == 0xFF) // Steuerung LED 5 { //wait10 = 0; led1++; if ( led1 == 100 ) // Einstellung Zeit 10ms mal x { led1 = 0; if(!(PINC&(1<<PC5))) // Abfrage PC5 LED 5 Grün leds_set_status(1,5); // schaltet LED 5 auf ein else leds_set_status(0,5); // schaltet LED 5 auf aus } } if (wait11 == 0xFF) // Steuerung LED 4 { //wait10 = 0; led2++; if ( led2 == 50 ) // Einstellung Zeit 10ms mal x { led2 = 0; if(!(PINE&(1<<PE4))) // Abfrage PortC PC5 LED 5 Grün leds_set_status(2,4); // schaltet LED 5 Grün auf ein else leds_set_status(0,4); // schaltet LED 5 Grün auf aus } } wait10=0; Habe vorher in jeder Abfrage wait auf 0 gestellt. Ergebnis, die Sachen blinken unterschiedlich schnell. Habe dann die wait10=0 ans ende gesetzt. Beinflussen sich wieder gegenseitig. Mir ist leider unklar wieso. Wie kann ich wait zurücksetzen ohne zusätzliche Timer oder andere Variablen? Eigentlich ist es gedacht, irgendwo im Prg mehrfach wait10 zu verwenden für alle möglichen wartescheilfen. achim
Datum:
@ Achim Seeger (achims) >ich möchte eine Variable (wait10), die von einem Timer über die ISR alle >10ms kommt mehrfach abfragen. Eher nicht. du willst in erster Linie ein paar LEDs mit verschiedenne Zeiten leuchten lassen. Ist das richtig? Das kann man u.a. mit einer statemachine. >gesetzt. Beinflussen sich wieder gegenseitig. Mir ist leider unklar >wieso. Uns ist unklar, was du INSGESAMT erreichen willst. Siehe Netiquette. MfG Falk
Datum:
Hallo Falk das mit der Statemaschine geht nicht. Das Prinzip ist einfach. Mit dem Timer ind der ISR erzeuge ich alle 10ms einen Impuls, das ist wait10. Dieser wird gezählt. Sobald ich den richten Wert erreicht habe schaltet die LED. Vorteil ist, es braucht dein delay. Dadurch schläft der Proz nicht und ich kann verschidene Sachen schnell hintereinander ausführen. wait10 wird in die Variablen Led 1 und zwei geschrieben und anschliessend wieder auf null gesetzt. LED 1 und 2 beeinflussen sich gegenseiti. mir ist leider unklar warum. achim
Datum:
Hey, also in dem von dir gezeigten Code beeinflussen sich die Variablen nicht gegenseitig. Sinnvol wäre es aber, die Variable wait10 nur einmal abzufragen, damit sichergestellt ist, dass sie sich zwischen zwei Abfragen nicht ändert. Warum fragst zu bei der zweiten If-Abfrage wait11 ab und nicht wait10?? Achim Seeger schrieb: > if (wait11 == 0xFF) // Steuerung LED 4 Die Kommentare passen nicht zum porgrammierten Code ;) Achim Seeger schrieb: > if(!(PINE&(1<<PE4))) // Abfrage PortC PC5 LED 5 Grün Vermutlich musst du noch etwas mehr Code zeigen, denn hier finde ich so nichts falsches, außer die Abfrage oben (wait11). Grüße
Datum:
Hallo Benjamin mit wait 10 und 11 hast du recht. habe es erst später gesehen. Ist aber geändert.Ab den If erfogt der Code für die jeweilige LED, daher der Code. Viel mehr Code gibt es kaum. Es fehlt der Timer und die ISR, Aufruf der Variablen und ein bischen Grundanzeige. Noch mal, damit es klar wir, wait10 brungt alle 10ms einen Impuls. Dieser wird in der led1++ und led2++ gezählt bis der eingestellte Wert erreicht ist (led1==100) das selbe auch in Led2. Am ende setze ich wait10 auf 0. 10ms später kommt das nächste. LED zählen wieder einen hoch. Da beide Zeiten gleich gestellt sind müssen auch beide gleichzeitig an und aus gehen. das machen sie nicht. Bloss woeso? achim
Datum:
Hey, dein Problem hab ich verstanden, jedoch fürchte ich, kann ich dir nicht helfen, wenn du behauptest: Achim Seeger schrieb: > Da beide Zeiten > gleich gestellt sind müssen auch beide gleichzeitig an und aus gehen. Ich muss im Code aber folgendes Lesen: Achim Seeger schrieb: > if ( led1 == 100 ) // Einstellung Zeit 10ms mal x Achim Seeger schrieb: > if ( led2 == 50 ) // Einstellung Zeit 10ms mal x led2 sollte also doppelt so schnell blinken. so far!
Datum:
Poste doch mal den richtigen Code. Und zwar vollständig.
Datum:
Das Resetten von wait10 (wait10=0) auf der obersten gezeigten Codeebene ist nicht hilfreich. Du erwischst den Alarmfall (wait10==0xFF) nur wenn zwischen dem Resetten und der ersten if-Abfrage die ISR gerade wait10 auf 0xFF gesetzt hat. Das ist besonders kritisch, wenn wait10 innerhalb der ISR hochgezählt wird. Ein weiteres Problem kann in der nicht gezeigten ISR liegen, in der wait10 manipuliert wird: Dein Code kann Events verpassen, wenn in der ISR zwischen den beiden if-Abfragen gerade verändert wird. Das ist besonders kritisch, wenn wait10 innerhalb der ISR hochgezählt wird. Ein Codevorschlag ist
// Reset task timers and 10ms alarm flag // volatile uint8_t wait10; // defined elsewhere (globally) uint8_t alarm_10ms = 0; uint8_t led1 = 0; uint8_t led2 = 0; // init and start wait10 timer interrupt ... while (1) { // Check 10ms timer interrupt result/flag if (wait10 == 0xFF) { wait10 = 0; // 10ms stop watch reset alarm_10ms = 1; // trigger 10ms alarm check } // Check every 10ms all alarms for task #1, #2, ... if ( alarm_10ms ) { alarm_10ms = 0; // reset 10ms alarm flag // Check Task #1: LED 5: 100 * 10ms = 1s if ( ++led1 == 100 ) { led1 = 0; ... // pos#1 } // Check Task #2: LED 4: 50 * 10ms = 0.5s if ( ++led2 == 50 ) { led2 = 0; ... // pos#2 } ... other tasks ... // pos#3 } } |
Die Zeitverzögerung bei der Ausführung von Task #1 und Task #2 hängt davon ab, wie lange der Code von pos#1 bis pos#2 braucht. Man kann daran arbeiten, diese Zeit zu verkürzen, wenn man an den Positionen pos#1 und #2 nur einen Aktionscode berechnet (led1_action = 1 oder 0) und später die Aktionen in kurzen Funktionen möglichst nahe beieinander z.B. an pos#3 tatsächlich ausführt (leds_set_status(led1_action,5)).
Datum:
>as mit der Statemaschine geht nicht.
Mööp. Alles lässt sich mit einer Statemaschine realisieren.
(Alles? Nicht alles. Frauen nicht. Aber Frauen sind zeitinvariant und
nicht kausal)
Zum Thema:
Du musst das folgendermaßen machen.
In der ISR inkrementierst du (alle 10ms) eine Variable. Das ist dein
durchlaufender TimerTick.
Im Hauptprogramm nimmst du Zeitstempel und prüfst diese auf Differenzen.
Etwa so:#define PORT_LED1 PORTC #define PIN_LED1 PC4 #define PORT_LED2 PORTC #define PIN_LED2 PC8 volatile uint32_t u32TimerTickMs; ISR (...) // alle 10ms { u32TimerTickMs += 10; } uint32_t fTimeStampGet( void ) { return u32TimerTickMs; } uint32_t fTimeStampDiff( uint32_t u32TStamp ) { return ( u32TimerTickMs - u32TStamp ); } void main ( void ) { uint32_t u32TimeStamp_1; uint32_t u32TimeStamp_2; ... while ( 1 ) { ... //-- LED1 alle 500ms toggeln ------------------- if ( fTimeStampDiff(u32TimeStamp_1) >= 500 ) { // alle 500ms u32TimeStamp_1 = fTimeStampGet(); PORT_LED1 ^= (1<<PIN_LED1); // LED1 toggeln } //-- LED 2 alle 1000ms toggeln ----------------- if ( fTimeStampDiff(u32TimeStamp_2) >= 1000 ) { // alle 1000ms u32TimeStamp_2 = fTimeStampGet(); PORT_LED2 ^= (1<<PIN_LED2); // LED2 toggeln } ... } } |
Datum:
Matthias Lipinsky schrieb: > In der ISR inkrementierst du (alle 10ms) eine Variable. Das ist dein > durchlaufender TimerTick. Prinzipiell ist das Konzept richtig, bei Deiner Umsetzung gefallen mir ein paar Dinge nicht: 1. Überlauf der TimerTick-Variable: Sobald das passiert, ist für eine lange Weile Schluss. 2. Dein Zugriff auf TimerTick ist nicht atomar. Besser wäre eine TimerTick-Variable, die in ein uint8_t passt und gezielt wieder zurückgesetzt wird, statt dass sie überläuft. Dann wäre noch zu überlegen, ob man nicht direkt das Register TCNTx dafür verwendet. Gruß, Frank P.S. Wenn es sowieso nur darum geht, eine oder zwei LED zu togglen, kann man das direkt auch in der ISR tun - mit Hilfe der Zählvariablen. Der ganze Overhead mit fTimeStampGet und fTimeStampDiff entfällt.
Datum:
>bei Deiner Umsetzung gefallen mir ein paar Dinge nicht: Du hast recht. Der Zugriff muss atomar erfolgen. Das habe ich bei dem Beispiel vergessen. Meineswissens gibt es da Makros?? Der Überlauf allerdings spielt keine Rolle. Es ist ein kontinuierlich hochzählender Wert. Im Beispiel sind das Millisekunden. Ein u32 läuft dann nach 2E+32ms = 49d 17h 2m 47.296s über. Und selbst wenn. Die Zeitdifferenz wird ebenfalls nur! mit 32bit errechnet. Überläufe werden ignoriert. Somit klappt das auch während des Überlaufes. Bsp: Zeit = 0x0000_0100 = 256 Stamp = 0xFFFF_FF00 = 4'294'967'040 ¦ - --------------------------------- Diff = ..FF_0000_0200 = 512 Denn 4'294'967'040 + 512 = 4'294'967'552 ( > 2E+32 => passt nicht in u32 ) - 4'294'967'296 ( = 2E+32 ) ----------------- 256 Passt also immer. Einzig Zeiten grösser obige Zahl kann nicht gewartet werden. >Der ganze Overhead mit fTimeStampGet und fTimeStampDiff entfällt. Wenn der uC nur zwei LEDs toggeln soll, ja. Wenn man ein komplexes Programm hat, ist das (mM) die beste Lösung, zeitliche Abläufe zu programmieren. Ausserdem kann man die Fkt ja inlinen. Ich habe sie nur extern geschrieben, damit es übersichtlicher wirkt. Weiterhin hat die Kapselung mit den Get/Diff-Fkt den Vorteil, das nur in diesen Fkt. der Zugriff atomar sein muss.
Datum:
Hallo, Matthias Lipinsky schrieb: > //-- LED1 alle 500ms toggeln ------------------- > if ( fTimeStampDiff(u32TimeStamp_1) >= 500 ) > { // alle 500ms > u32TimeStamp_1 = fTimeStampGet(); > PORT_LED1 ^= (1<<PIN_LED1); // LED1 toggeln > } Dadurch dass u32TimeStamp_1 (und auch u32TimeStamp_2) auf den dann aktuellen TimeStamp gesetzt werden, könnten sich Fehler aufsummieren. Falls mal die Abfrage erst nach längerer Zeit erfolgt (so daß die Differenz nicht 500 sondern zum Beispiel 510 ergibt), so addieren sich diese Unterschiede im Laufe der Zeit. Je nach Anwendung mag es nicht wichtig sein oder auch so gewünscht sein, ich würde jedoch den Wert wie folgt berechnen:
u32TimeStamp_1 += 500; |
Datum:
>könnten sich Fehler aufsummieren.
Prinzipiell hast du recht, aber das Konzept geht davon aus, das die
Zykluszeit des Programmes (also wie oft kommt der uC an dieser
Diff-Abfrage vorbei) sehr viel kleiner ist, als die Zeiten, die
gewartet/verzögert werden sollen.
Also um Zeiten von einigen wenigen Millisekunden zu erzeugen, ist das
ungeeignet. Das macht man mit OCR in Timern. Aber um Programmabläufe im
Sekundenbereich oder grösser zu steuern, ist das ideal.
Das setze ich hier in den SPS Anlagen seit geraumer Zeit bestens ein. Da
nutze ich Zykluszeiten von 1, 2 oder 10ms.
Datum:
@ Matthias Lipinsky (lippy) >>könnten sich Fehler aufsummieren. >Prinzipiell hast du recht, aber das Konzept geht davon aus, das die >Zykluszeit des Programmes (also wie oft kommt der uC an dieser >Diff-Abfrage vorbei) sehr viel kleiner ist, als die Zeiten, die >gewartet/verzögert werden sollen. Schon richtig, torotzdem würde ich so ein potentielles Problem nicht einbauen wollen. Erst recht nicht, wenn es unlogischer ist als die richtige Version.
Datum:
Für mich ist das die logisch-ste Variante. Ich mach das ja zuhause, also im "Leben" auch so. Was ist denn die richtige Variante? Und wer hat diese als richtig deklariert?
Datum:
Hallo freunde war leider ein paar Tge ausser Haus. stelle den kompletten Code rein. /* Tset LED 25 Testet die Funktion Timer, ist eingestellt auf 10ms und wird mehrfach aufgerufen wiederholt. Abfrage LED auf an, sonst aus,danach wieder an, by h.j.seeger@web.de */ #include <nibo/niboconfig.h> #include <nibo/iodefs.h> #include <nibo/leds.h> #include <avr/interrupt.h> #include <nibo/gfx.h> #include <nibo/display.h> #include <nibo/pwm.h> #include <nibo/bot.h> volatile uint8_t wait10 = 0; // Timer 10ms volatile uint8_t wait11 = 0; // Timer 10ms volatile uint8_t wait = 0; // Timer 1ms uint8_t led1 = 0; // Variable für LED 1 uint8_t led2 = 0; // Variable für LED 2 void nibo_timer2() // Timer 10ms { TCNT2 = 0; OCR2=249; TCCR2=(1<<WGM21)|(1<<CS21)|(1<<CS20); TIMSK |= (1<<OCIE2); } ISR (TIMER2_COMP_vect) // wait1=1m { if( wait<9) // Takt 0,5s, bei 9 sind es 10ms { wait++; } // erhöht else // wenn dann ... { wait=0; // setzt wait1 auf 0 wait10=0xFF; // Signal alle 10ms wait11=0xFF; } } int main(){ //Start sei(); // Freigabe Interrups display_init(); pwm_init(); gfx_init(); bot_init(); leds_init(); leds_set_displaylight(800);// setzt Displaylicht nibo_timer2(); // Aufruf Timer 2 einmalig gfx_fill(0x00); // löschtSchirm gfx_move(5, 5); // Angabe Ort gfx_set_proportional(0);// Angabe Schrift gfx_print_text("Testprogramm Nibo 2"); // Ausgabe Text gfx_move(13, 15); // Angabe Ort gfx_set_proportional(1);// Angabe Schrift gfx_print_text("LED 25 Test c HJS 2012");// Ausgabe Text gfx_move(0,25); // Angabe Ort gfx_hline(128); // Ausgabe Strich gfx_move(5, 35); // Angabe Ort gfx_set_proportional(1); // Angabe Schrift gfx_print_text("2 x Frequenz mit Timer");// Ausgabe Text while(1) { if (wait10 == 0xFF) // Steuerung LED 5 { //wait10 = 0; led1++; if ( led1 == 100 ) // Einstellung Zeit 10ms mal x { led1 = 0; if(!(PINC&(1<<PC5))) // Abfrage PC5 LED 5 Grün leds_set_status(1,5); // schaltet LED 5 auf ein else leds_set_status(0,5); // schaltet LED 5 auf aus } } if (wait10 == 0xFF) // Steuerung LED 4 { //wait10 = 0; led2++; if ( led2 == 100 ) // Einstellung Zeit 10ms mal x { led2 = 0; if(!(PINE&(1<<PE4))) // Abfrage PortC PC5 LED 5 Grün leds_set_status(2,4); // schaltet LED 5 Grün auf ein else leds_set_status(0,4); // schaltet LED 5 Grün auf aus } } wait10=0; } return 0; } Habe alles drin, bitte nicht an den Kommentaren stören. Sind verruscht und habe mit den Zeiten experentiert. Habe es auch mit Softwaretimer getstet. Geht alles. LED schalten gleich und korrekt. Noch mal zum Prinzip. Bilde mit dem Timer und ISR einen wait10 (10ms) Impuls. dieser kann im gesamten Programm abgefragt werden. Bei jedem Durchlauf schaltet er Zähler (if LED ) weiter. Ist die voorgegebene Zeit abgelaufen, schaltet z.B. die LED oder anderes. Am Ende des Prg wird wait10 auf 0 gesetzt und es geht von vorn los. Dadurch verwende ich lein delay im gesamten Programm. Ich kann mehrere Arbeiten, Zähler oder Zeiten fast gleichzeitig ausühren. Sage immer wieder, kann den Prz 1 Sekunde warten lassen oder mit 10ms 100 andere Sachen ausführen. Bei dem oberen Teil geht ein LED korrekt, die andere aber nicht. Wie verhält sich die Sache , wenn ich noch eibe einfache Abfrage für einen Taster einbaue? Frage an KH: Wie kann ich das machen mit deiner Tasterabfrage 1. nur auf ein oder aus 2. mit Abfrage der zeit Kurz/lang gedrückt. Im Moment ist die Abfrage der taster teilweise 5x so lang wie das eigentlich Prg. achim
Datum:
if(!(PINC&(1<<PC5))) // Abfrage PC5 LED 5 Grün
|
willst du hier wirklich den Eingangszustand abfragen, oder den Ausgangszustand wissen und damit dann die LED togglen? Was soll dein Programm machen?
Datum:
ja das will ich, es soll die LED nur geschaltet werden, wenn si vorher aus ist. Hat auch damit zu tun das die Ein und aus Zeit geich ist. Das Thema hatten wir vor einiger Zeit hier schon. Es geht eigentlich nur um die Funktion des wait10. Das Prg dient in dieser Form als Testgrund für die Funktion vom Timer und ISR und besonders der Anwendung von wait10. Möchta damit die Möglichkeut haben, jeder zeit mehrere Aktionen auszuführen ohne delay. achim
Datum:
Formatiere den Code mal gescheit und bette ich in [ C ] Tags ein.
Datum:
Achim Seeger schrieb: > ja das will ich, es soll die LED nur geschaltet werden, wenn si vorher > aus ist. Sowas macht man so:
PORTC ^= (1<<PC5);
|
Achim Seeger schrieb: > Das Prg dient in dieser Form als Testgrund für die Funktion vom Timer > und ISR und besonders der Anwendung von wait10. Möchta damit die > Möglichkeut haben, jeder zeit mehrere Aktionen auszuführen ohne delay. > achim Und wenn du es 1000 Mal wiederholst, wird es auch nicht besser. Wieso fragst du wait10 zwei Mal ab? Die Anwort "Weil das später noch anders werden soll." lasse ich nicht gelten. Es übrigens eine ganz schöne Platzverschwendung, ein ganzen Byte als eigenen Status.Flag zu benutzen. Man kann das auch bitweise machen... Tut aber gerade nichts zur Sache. Gewöhn dir bitte an, auch in dem Teil deiner Post, der kein Programmcode ist, gelegentlich mal einen bewussten Zeilenwechsel zu machen. Das würde den Lesefluss doch sehr aufhübschen. Telegramm-Stil finde ich nicht so richtig prickelnd zu lesen.
Datum:
Hallo du sagst, du lässt es nicht gelten. Wie kann ich den wait10 mehrfach abfragen. das erste mal, z.B. um eine LED im Takt von 1s als blinklicht zu nehmen. beim 2 mal soll eine Hupe einen wechselnen ton bringen, wie bei Maschinen die Rückwärtsfahren, beim 3 mal sollen Anzeigen auf dem Display Blinken um den Abstand zu zeigen, beim 4 mal soll ein Taster abgefragt werdenum einen Prozess oder Ablauf zu stoppen oder zeitverzögernd anzu laufen. Sicher lassen sich noch andere Aufgaben finden. Es ist nur wichtig, das sie alle fast gleichzeitig laufen. Danke für den Hinweis mit der Abfrage. Werde es so berücksichtigen. achim
Datum:
Achim Seeger schrieb: > Hallo > du sagst, du lässt es nicht gelten. Wie kann ich den wait10 mehrfach > abfragen. das erste mal, z.B. um eine LED im Takt von 1s als blinklicht > zu nehmen. beim 2 mal soll eine Hupe einen wechselnen ton bringen, wie > bei Maschinen die Rückwärtsfahren, beim 3 mal sollen Anzeigen auf dem > Display Blinken um den Abstand zu zeigen, beim 4 mal soll ein Taster > abgefragt werdenum einen Prozess oder Ablauf zu stoppen oder > zeitverzögernd anzu laufen. Sicher lassen sich noch andere Aufgaben > finden. Es ist nur wichtig, das sie alle fast gleichzeitig laufen. > Danke für den Hinweis mit der Abfrage. Werde es so berücksichtigen. > achim Das tue ich mir jetzt nicht mehr an. Entweder lässt du den Telegramm-Stil, oder ich bin raus.
Datum:
Hallo Es ist nicht meine Absicht im Telegramm Stil zu schreiben. Ich fasse es auch nicht so auf. Ich habe nur versucht, meine Gedanken zum Ablauf des Programmes einiger massen klar darzustellen. Werde es nicht mehr machen. achim
Datum:
Achim Seeger schrieb: > Hallo > Es ist nicht meine Absicht im Telegramm Stil zu schreiben. Ich fasse es > auch nicht so auf. Ich habe nur versucht, meine Gedanken zum Ablauf des > Programmes einiger massen klar darzustellen. Werde es nicht mehr machen. > achim lol Du sollst Absätze machen!
Datum:
Es kam die Frage, ob ich den vollständigen Code reinstelln könnte. Da er verhältnismässig lang ist, habe ich erst mal komplett, ohne Zwischenzeilen oder ähnlichen reingestellt. Damit kann ich auch die Frage beantworten, woher wait10 kommt. In diesem Code stehen auch die ganzen Ansteuerungen für das Display mit drin. Eigentlich sind sie doch für das Verständnis nicht unmittelbar erforderlich. Es kommt doch, so weit ich es überblicken kann, auf die if(wait .. ) an. achim
Datum:
while(1) { if (wait10 == 0xFF) { wait10 = 0; // Steuerung LED 5 led1++; if ( led1 == 100 ) // Einstellung Zeit 10ms mal x { led1 = 0; PORTC ^= (1<<PC5); } // Steuerung LED 4 led2++; if ( led2 == 100 ) // Einstellung Zeit 10ms mal x { led2 = 0; PORTE ^= (1<<PE4); } } wait10=0; } |
Finde ich jetzt mal schöner...
Datum:
while(1) { if (wait10 == 0xFF) { wait10 = 0; // Steuerung LED 5 led1++; if ( led1 == 100 ) // Einstellung Zeit 10ms mal x { led1 = 0; PORTC ^= (1<<PC5); } // Steuerung LED 4 led2++; if ( led2 == 100 ) // Einstellung Zeit 10ms mal x { led2 = 0; PORTE ^= (1<<PE4); } } } |
Da war noch ein "wait10=0;" zu viel drin
Datum:
Hallo danke dir erst mal. Habe das Prg so eingebaut und probiert. Es geht auf Anhieb. Du hattest in der ersten Version noch ein wait10 mehr drin. Das hast du in der zweiten rausgenommen. Habe es auch so gemacht und getestet. Als erstes nur das obere wait10, geht alles. Dann nur das untere. Damit werden beide if Abfragen zurück gesetzt und die Zeiten sind korrekt. Kann es jetzt mit der Tastenabfrage testen. achim
Datum:
Hallo Habe es getestet. So wie es oben steht, geht es. Habe auch gesehen was du geänder hast.Damit könnte es ein Problem geben. Wenn ich ein LED Steuerung ausführe, geht es. Die zweite Steuerung komm viel später erst im Programm. Damit ist aber ein gemeinsame if nicht möglich. while(1) { if (wait10 == 0xFF) { // Steuerung LED 5 led1++; if ( led1 == 100 ) // Einstellung Zeit 10ms mal x { led1 = 0; PORTC ^= (1<<PC5); } } // Normales Programm über viele Zeilen if (wait10 == 0xFF) { // Steuerung LED 4 led2++; if ( led2 == 100 ) // Einstellung Zeit 10ms mal x { led2 = 0; PORTE ^= (1<<PE5); } } // anderes Programm } } wait10 = 0; return 0;
Datum:
Achim Seeger schrieb: > Die zweite Steuerung komm > > viel später erst im Programm. Damit ist aber ein gemeinsame if nicht > > möglich. Warum? Welchen Sinn sollte das haben? Du hast das Ereignis "10ms sind um". Damit kannst du dort alles machen, was mit diesem Ereignis zusammenhängt. Wenn du jetzt zwischen den beiden Aktionen noch so viel machst, dass wieder 10ms um sind, dann sind das bei der unteren Aktion schon andere 10ms... Eine Uhr wirst du damit nicht realisieren können. Meine Lösung dürfte für diese Anwendung soweit optimal sein. Wenn du jetzt noch mehr machen willst, was zu anderen Abhängigkeiten führt, dann solltest du das schon mal bekannt geben. Du hast - soweit ich das jetzt mitbekommen habe - noch nicht den endgültigen Zweck der Übung gepostet. Und schreib jetzt nicht wieder, dass durch deine Lösung der Controller nicht in einer Warteschleife hängen bleibt, sondern auch noch andere Sachen machen kann. Das weiß ich schon.
Datum:
Hallo es gibt einen (mehrere/viele) Beträge im Netz über Scheduler und anderen Möglichkeiten verschiedene Sachen gleichzeitig oder kurz hintereinander auszuführen. Einer dieser Beträge läuft unter dem Namen "Warten verboten". Dort wird beschrieben, wie die Auswirkung bei delay mit 0,5s oder 1s ist. Als Lösung wurde vorgeschalgen, delay auf 1ms zu nehmen und die einzelnen Ansteuerungen oder Abfragen mehrmals zu machen. Im Text heisst es dort: "Wir warten nicht auf die Eingabe, sondern fragen die einzelnen Zustände, Zeiten, Zähler usw. regelmässig ab. Das hat den Vorteil, viele Sachen ausführen zu können." Dabei wird eine Schleife durch das ganze Prg verwendet. Diese Schleife wird erst am Ende durch delay1ms weitergezählt. Im Text wird auch darauf hingewiesen, das man delay durch einen Timer mit ISR ersetzen kann. In anderen Artikelen, z.B. von Dannegger wird auch auf den Aufruf eines Timers z.B. bei Abfrage eines Tasters hingewiesen. Ein Sinn dieser Sache besteht z,B, darin, bestimmte Abfragen (Sicherheit) zu machen ohne das eigentliche Prg zu beenden/unterbrechen. Beispiel: Schalte einen Motor zur Bewegung ein. Ein Teil bewegt sich vorwärts, dabei wird eine Kante überfahren und es muss der Absturzsensor sofort reagieren. Bei Verwendung von delay kann es zu lange dauern. Es geht mit Schedulern und anderen Anwendungen. Leider sind manche Prg grösser als mein Prg und recht kompliziert, mit dem ich arbeite. Eine Uhr möchte ich damit nicht ansteuern. Es geht im Grunde um die Sicherheit. achim
Datum:
Achim Seeger schrieb: > Es geht mit Schedulern und anderen Anwendungen. Leider sind manche Prg > grösser als mein Prg und recht kompliziert, mit dem ich arbeite. > Eine Uhr möchte ich damit nicht ansteuern. Es geht im Grunde um die > Sicherheit. Mir ist noch nicht klar: Hast du jetzt verstanden, wie die Sache läuft? Du hast prinzipiell 2 Dinge, die erst mal nichts miteinander zu tun haben: Die Erzeugung eines 10-Millisekunden 'Signals' und dann das was daran gekoppelt ist. Das hier
ISR (TIMER2_COMP_vect) // wait1=1m { if( wait < 9 ) // Takt 0,5s, bei 9 sind es 10ms { wait++; } else { wait=0; wait10 = 0xFF; // Signal alle 10ms } } int main(){ //Start .... while(1) { if (wait10 == 0xFF) { wait10 = 0; // 10 Millisekunden sind um ... } // ... alles was nicht zeitabhängig ist } } |
erzeugt dir erst mal einen 10 Millisekunden 'Herzschlag' im Programm. Der markierte Teil in der Hauptschleife, wird in diesem Zeittakt ausgeführt. Brauchst du längere Zeiten, dann macht man dann eben zb. dort das Abzählen von Vielfachen von 10 Millisekunden, so wie du das mit deinen LED machst. Dinge, die nicht in dieses 10 Millisekunden Raster fallen (wie zb Überwachung von Endsensoren) kommen dann eben nicht in diesen Programmteil hinein. Sagt ja keiner, das ausnahmslos ALLES in diesem Zeitraster gemacht werden muss. > Schalte einen Motor zur Bewegung ein. > Ein Teil bewegt sich vorwärts, dabei wird eine Kante überfahren > und es muss der Absturzsensor sofort reagieren. 'Sofort' ist immer relativ in einem µC. Denn eine Reaktion mit 0-Zeit ist nun mal nicht möglich. Aber: In 99.9% aller Fälle genügt es, wenn die Reaktion ausreichend schnell erfolgt. Für praktische Zwecke sind ein paar µs genau so gut wie 'sofort'. In dieser Zeit kann dein µC zwar ein paar hundert Befehle abarbeiten, aber der Motor schafft es nicht das Angetriebene mehr als ein paar 10-tausendstel Millimeter (wenn überhaupt) weiterzubewegen. Lass dich nicht von deiner Vorstellung von 'sofort' ins Boxhorn jagen. Was wir Menschen unter 'sofort' einordnen, ist für einen µC immer noch 'ooch, da hab ich ja noch Zeit'.
Datum:
Achim Seeger schrieb: > Es geht mit Schedulern und anderen Anwendungen. Leider sind manche Prg > > grösser als mein Prg und recht kompliziert, mit dem ich arbeite. > > Eine Uhr möchte ich damit nicht ansteuern. Es geht im Grunde um die > > Sicherheit. Wieso redest du eigentlich die ganze Zeit um den heissen Brei rum? Wie ein Scheduler funktioniert, brauchst du nicht zum xten Mal rezitieren. Das weiß ich, Karl-Heinz und noch eine Menge Leute mehr. Was willst du eigentlich erreichen? Achim Seeger schrieb: > Bei Verwendung von delay kann > > es zu lange dauern. Dass delay "böse" ist, hast du ja schon festgestellt. Was willst am Ende damit steuern?
Datum:
Hallo sorry, muss mal blöd fragen. Ist das wait10 kein "Herzschlag" mit 10ms? Das mit der abarbeitung des Prg ist mir klar. Ich gehe da von aus, das alle Befehle nicht gleichzeitig abgearbeitet werden. Daher versuche ich die Zeit relativ klein zu halten für einen Befehl. Bei anderen Prg hatte ich bisher kaum das Problem mit delay. Je mehr ich aber machen will, um so früher kommt das Problem. Um trotzdem einen verhältnissässig schnellen Ablauf zu bekommen, habe ich nach einer Lösung gesucht. Dabei kommen die Sachen mit dem Scheuler. Ich habe die Funktion nicht noch mal erklärt. Kann ich gar nicht, da meine Kenntnisse nicht reichen. Mir geht es um eine kleine Lösung, die relativ einfach ist und nachvollziehbar. Eben für mich als Anfänger zu verstehen. Die Lösung mit den LED soll das machen. Bisher noch als Beispiel. Hattees auch mit Softwaretimer probiert. Problem dabei ist, das ich alles vorher angeben muss und die ISR zu gross werden kann. Ich möchte genau das damit steuern, was ich angegeben habe. Durch eine If Abfrage möchte ich zu jeder x Stelle im Programm genau das machen. Bei einer einfachen Abfrage des Tasters muss ich das entprellen einhalten. Das kann ich mit dealy20ms machen oder aber mit wait10 x 2. Das Beispiel mit den Motoren war blöd gewählt. Es tritt dabei ja immer eine Verzögerung auf durch die mechanik. Anderes Beispiel. Modell fährt rückwärts. Dabei sollen die LED rot blinken und Hupe gehen. Vielleicht noch die Kontrolle ob der Weg keine Hindernisse hat. Habe alle meine Überlegungen dazu angegeben. achim
Datum:
Achim Seeger schrieb: > Ist das wait10 kein "Herzschlag" mit 10ms? Doch, ist es. Achim Seeger schrieb: > Das kann ich mit dealy20ms machen oder aber mit wait10 x 2. richtig. > Anderes Beispiel. Modell fährt rückwärts. Dabei sollen die LED rot > blinken und Hupe gehen. kein Problem. Sogar unterschiedliche Frequenzen sind dabei möglich - allerdings mit einer Auflösung von 10ms... > Vielleicht noch die Kontrolle, ob der Weg keine Hindernisse hat. Bei solchen sicherheitsrelevanten Sachen braucht man gar nicht entprellen. Da reicht es, wenn man in regelmäßigen Abständen (bei jedem Durchlauf der Hauptschleife) nachguckt, ob der Taster ausgelöst wurde. Dann reagiert man entsprechend darauf, bis das "Gut"-Signal wieder hergestellt ist. Wobei man dann natürlich darauf achten muss, dass das "Gut"-Signal lange genug vorhanden ist, damit der Normalbetrieb wieder aufgenommen werden kann.
Datum:
Achim Seeger schrieb: > Beispiel. Hattees auch mit Softwaretimer probiert. Problem dabei ist, > das ich alles vorher angeben muss und die ISR zu gross werden kann. Alles eine Frage der Organisation bzw. der sinnvollen Aufteilung der Aufgaben. ISR sollten in der Durchlaufzeit zu kurz wie möglich sein. Wobei man dann aber auch auf eine sinnvolle Reduzierung achten muss. Ich mache zb einen Uhrenupdate (das hochzählen der Zeit über Sekunden, Minuten, Stunden) komplett in der ISR. Das sieht zwar nach viel Code aus, wenn man aber mal genauer darüber nachdenkt kommt man drauf: soviel ist das gar nicht. Die paar Takte hab ich allemal um eine Uhr komplett durchzuzählen. Dafür spar ich mir das Problem, dass an anderen Stellen unter Umständen auf eine inkonsistente Zeit zugegriffen wird, bzw. die Uhr überhaupt stehen bleibt, weil zb gerade ein Menü auf dem LCD angezeigt wird und ich dort vergessen habe, den Uhrenupdate zu machen. In deinem Fall mit den LED ist es so, dass die 'Aktion' kurz genug ist, dass man sie in die ISR mit aufnehmen könnte. Das würde dann wieder ganz neue Möglichkeiten eröffnen, indem du für eine LED so etwas wie eine Zustandsvariable haben könntest, die 3 mögliche Zustände haben kann: aus, ein und blinkend. Willst du an anderen Stellen im Programm die LED in einen bestimmten Zustand haben, dann setzt du einfach diese Variable auf den richtigen Wert und die ISR kümmert sich um den Rest. Allgemeine Lösungen sind meistens relativ komplex und aufwändig. Für den jeweiligen Fall massgeschneiderte Lösungen können abweichend davon oft viel einfacher aussehen. Auch sollte man sich vor Dogmen hüten. Die Regel 'ISR so kurz wie möglich' gilt bei klassischen LCD oder UART Ausgaben (aber auch da kann es Ausnahmen geben, wenn zb eine Queue dazwischen geschaltet wird). Man muss aber auf der anderen Seite auch nicht päpstlicher als der Papst sein. 'so kurz wie möglich' bedeutet nicht, dass man gar nichts in einer ISR machen darf.
Datum:
Hallo Herzschlag ist also ok. Taster auch. Dein Stück Code geht super. Habe es im Prg drin. Wenn ich aber 100 Zeilen später wieder sowas aufrufe, gibts Probleme. Auch wenn ich hintereinander solche Teile nehme, gibts Probleme. Komme leider nicht dahinter, woran es liegt. achim
Datum:
Achim Seeger schrieb: > Hallo > Herzschlag ist also ok. Taster auch. Dein Stück Code geht super. Habe es > im Prg drin. Wenn ich aber 100 Zeilen später wieder sowas aufrufe, gibts > Probleme. Wichtig: Nomenklatur! Was soll in diesem Zusammenhang 'aufrufen' bedeuten? Da wird nichts aufgerufen! Eine Funktion wird aufgerufen, aber da ist keine Funktion. > Auch wenn ich hintereinander solche Teile nehme, gibts Probleme. Komme > leider nicht dahinter, woran es liegt. Du schachtelst die Dinge gedanklich falsch ineinander. Ganz aussen steht Es ist eine 10 Millisekunden Zeitscheibe abgelaufen da rein geschachtelt ist Was gibt es jetzt alles zu tun? Und mit "alles" ist auch wirklich ALLES gemeint. Es gibt in deinem ganzen Programm nur diese eine 10 Millisekunden Weiche, die für einen Zeittakt sorgt. Es DARF nur diese eine geben.
Datum:
Hallo Karl Heinz mit der ISR hast du recht. Man kann was reinschreiben. Kenne auch einige Prg, wo Teile von Uhren oder ganze drin sind. Mir geht es eigentlich um die andere Sache. Ich möchte an jeder Stelle im Prg, wo ich es gerade brauche, wait10 nutzen und eine Verzögerung, Schleife oder anderes machen. Bei einzelnen Aufrufen klappt es sehr gut. Das Problem liegt im mehrfachen aufruf. Die LED nutze ich hierbei nur als Anzeige eines Zustandes. Habe als Beispiel 4 x die LED geschrieben, immer mit anderen Nummern. 2 gehen, zwei nicht, obwohl alle Nr stimmen. Habe da irgend ein Denkfehler drin. achim
Datum:
Hallo if (wait10 == 0xFF) // Steuerung LED 5 grün { led2++; if ( led2 == 100 ) // Einstellung Zeit 10ms mal x { led2 = 0; PORTE ^= (1<<PE4); } } ...... wait10 =0; Verwende als einziges wait10 um die led2 zu zählen bis 100 erreicht ist. Dann schaltet die LED ein. Es kommen och ein paar LEDs nach dieser Art. Am Ende setze ich wait10 = 0; Zwei mal LED machen das, die anderen nicht. Es gibt nur diese wai10. keine Andere. Weiter oben ist das ganze Prg drin. achim
Datum:
Achim Seeger schrieb: > Auch wenn ich hintereinander solche Teile nehme, gibts Probleme. Komme > leider nicht dahinter, woran es liegt. Ich glaube, Du hast noch einen Denkfehler. Aus Deinem obigen Beispiel:
while(1) { if (wait10 == 0xFF) { // Steuerung LED 5 ... } // Normales Programm über viele Zeilen if (wait10 == 0xFF) { // Steuerung LED 4 ... } // anderes Programm } } wait10 = 0; return 0; |
Hier steht das "wait10 = 0;" an der falschen Stelle. Es muß dann gesetzt werden, wenn erkannt worden ist, das wait10 auch den Wert 0xFF hat. Und dazu gibt es bei Deinem Beispiel 2 Möglichkeiten:
while(1) { if (wait10 == 0xFF) { // Steuerung LED 5 wait10 = 0; ... } // Normales Programm über viele Zeilen if (wait10 == 0xFF) { // Steuerung LED 4 wait10 = 0; ... } // anderes Programm } } |
Wenn man es aber so macht, dann wird immer nur eine der beiden if-Zweige abgearbeitet und der andere bekommt es nicht mit. Wenn man es nur an eine von beiden Stellen schreibt, dann hängt es davon ab, wann das Flag gesetzt wird. Denk dran, das kann zu jeder x-beliebigen Zeit sein und passiert nicht immer (oder besser absolut selten) genau am Anfang der while-Schleife. Wenn Du unbedingt eine Nach-Behandlung benötigst, dann geht das eigentlich nur über eine weitere Zwischenvariable:
wait10_merker = 0; while(1) { if (wait10 == 0xFF) { // Steuerung LED 5 wait10 = 0; wait10_merker = 1; ... } // Normales Programm über viele Zeilen if (wait10_merker == 1) { // Steuerung LED 4 wait10_merker = 0; ... } // anderes Programm } } |
Für eine konsistente Bearbeitung des Programmes darfst Du (wie Karl-Heinz geschrieben hat) den Zeittakt nur einmal abfragen. Sonst gibt es inkosistente Abläufe. Und überlege genau, warum Du nicht alles in dieser einen Abfrage machen kannst? Ich denke, es gibt nur wenige Gründe, wo dies notwendig ist. Im Regelfall ist dies nicht nötig.
Beitrag #2648722 wurde vom Autor gelöscht.
Datum:
Hallo Volkmar die erste Version habe ich schon probiert. Dabei ist der Ablauf genau der selbe. Manche schalten, manche nicht und die Zeit ist unterschiedlich. Wenn ich für beide if die selbe Zeit einstelle z.B. 100, so müssen doch beide fast gleich anfangen und die selbe Zei laufen und fast gleichzeitig ausschalten. Machen sie leider nicht. Zu deiner zweiten version. Ich setze wait10 auf 0 und gleichzeitig den Merker auf 1. Ist das nicht das gleiche, als wenn ich wait10 weiter verwende? achim
Datum:
Achim Seeger schrieb: > Zu deiner zweiten version. Ich setze wait10 auf 0 und gleichzeitig den > Merker auf 1. Ist das nicht das gleiche, als wenn ich wait10 weiter > verwende? Nein, denn Du weißt nicht wann wait10 gesetzt wird. Das kann vor dem ersten If sein, das kann aber auch nach dem ersten if sein. Im ersten Fall sind beide If-Bedingungen gültig und es werden beide LEDs behandelt. Im zweiten Fall wird nur die 2. If-Bedingung als gültig erkannt weil danach wait10 wieder zurückgesetzt wird und wenn das Programm zur 1. If-Abfrage kommt, die Bedingung nicht mehr erfüllt ist. In dem Fall wird die erste If-Bedingung also seltener als gültig erkannt und die LED blinkt langsamer. Wenn wait10 nur einmalig anstatt mehrfach abgefragt wird, dann werden alle zugehörigen If-Bedingungen in einem Schleifendurchlauf als gültig erkannt. Der wesentliche Unterschied ist hier, daß diese Abfragen dann synchron ablaufen. Der Interrupt jedoch, der wait10 setzt, läuft asynchron, und da muß man dann immer aufpassen wann der Interrupt erfolgt.
Datum:
Hallo habe mein Prg nach deinen Sachen umgestellt. Alle LED schalten jetzt korrekt und gleichmässig. Habe wait10_merker erst ganz zum Ende auf 0 gesetzt. Soweit ist es jetzt klar mit den LED. Welchen Takt nehme ich denn nun um andere Sachen zu machen, z.B. für Abfrage Taster usw. Sind jetzt Wait10 und wait10_merker gleich? achim
Datum:
Achim Seeger schrieb: > Soweit ist es jetzt klar mit den LED. Sicher? > Welchen Takt nehme ich denn nun um > andere Sachen zu machen, z.B. für Abfrage Taster usw. Die kleinste gemeinsame Zeit, die du brauchst. Taster zb sind aus µC Sicht langsam. Kein Mensch kann eine Taste in einer tausendstel Sekunde drücken und wieder loslassen. D.h. wenn du alle 10 Millisekunden die Tasten überprüfst, kannst du davon ausgehen, dass du einen Tastendruck auf keinen Fall übersehen wirst. Aber du hast ein anderes Problem: Tasten prellen. Das heißt: dein Benutzer drückt zwar die Taste nur einmal nieder, für den µC entstehen hier aber ein paar kurze 'gedrückt' - 'nicht gedrückt' Sequenzen, bis sich dann endlich der Zustand auf gedrückt stabilisiert. Es gibt da ein paar clevere Verfahren (die auch auf Zeitsteuerung und Mehrfachabtastung beruhen) um dieses Problem in den Griff zu bekommen. Entprellung > Sind jetzt Wait10 > und wait10_merker gleich? Nein! Wait10 ist die Benachrichtigung von der ISR zum Hauptprogramm, dass 10 Millisekunden um sind. wait10_merker ist eine Hilfsvariable, die dafür sorgt, dass alle Teile der Hauptschleife sich darüber einig sind, ob 10 Millisekunden um sind. wait10_merker ist quasi der Zustand der 'Uhr' jeweils am Beginn eines neuen Durchgangs durch die Hauptschleife. Dies deshalb, weil es sonst zu Inkonsistenzen kommt, wenn sich die Uhr ändert, während gerade der Durchmarsch durch den 'Regelsatz' der Hauptschleife stattfindet.
Datum:
Achim Seeger schrieb: > Soweit ist es jetzt klar mit den LED. Welchen Takt nehme ich denn nun um > andere Sachen zu machen, z.B. für Abfrage Taster usw. Sind jetzt Wait10 > und wait10_merker gleich? Das hängt davon ab mit welcher Frequenz und zu welchem Zeitpunkt die laufen lassen möchtest. Wenn sie auch im 10ms-Raster laufen sollen, dann ist Wait10 bzw. wait10_merker OK. Einfach in den jeweiligen if-Zweig hängen:
wait10_merker = 0; while(1) { if (wait10 == 0xFF) { // Steuerung LED 5 wait10 = 0; wait10_merker = 1; ... Taster_Abfrage(); // Taster abfragen ***** } // Normales Programm über viele Zeilen if (wait10_merker == 1) { // Steuerung LED 4 wait10_merker = 0; ... Noch_was_anderes(); // Hier auch mögliche ****** } // anderes Programm } } |
Wichtig ist halt, daß es nur eine Abfrage auf wait10 gibt!
Datum:
Hallo danke erst mal an alle. Hoffe es wird langsam klar.Versuche jetzt mal ein Prg draus zu machen, das gut läuft. Narütlich kommt dann noch die Entprellung dazu, wie schon Karl Heinz schreibt. Muss ich den die "grosse Version nehmen"? Möchte erst mal mit einer einfachen Sache anfangen. Es bleibt dann ja noch die Sache mit dem drücken. kurz/mittel/lang, achim
Datum:
Karl Heinz Buchegger schrieb: >> Sind jetzt Wait10 >> und wait10_merker gleich? > > Nein! > Wait10 ist die Benachrichtigung von der ISR zum Hauptprogramm, dass 10 > Millisekunden um sind. wait10_merker ist eine Hilfsvariable, die dafür > sorgt, dass alle Teile der Hauptschleife sich darüber einig sind, ob 10 > Millisekunden um sind. wait10_merker ist quasi der Zustand der 'Uhr' > jeweils am Beginn eines neuen Durchgangs durch die Hauptschleife. Dies > deshalb, weil es sonst zu Inkonsistenzen kommt, wenn sich die Uhr > ändert, während gerade der Durchmarsch durch den 'Regelsatz' der > Hauptschleife stattfindet. Denk mal über folgendes konstuierte Beispiel nach Situation 'Nachtwächter'. Dem gibst du eine Checkliste mit, auf der exakt verzeichnet ist, was er auf seinem Rundgang in einem bestimmten Raum zu tun hat (und er ist normalerweise extrem pünktlich). Er soll sich einfach nur stur an diese Regeln halten: * Um 03:00 öffnest du das Fenster * Um 05:00 schliesst du das Fenster (Sinn der Sache ist es offenbar, dass Nachts 2 Stunden lang gelüftet wird). Das geht auch lange Zeit gut. Nur gibst du ihm noch eine zusätzliche Aufgabe * Um 03:00 öffnest du das Fenster * Um 05:00 drehst du die Heizung auf * Um 05:00 schliesst du das Fenster Soweit so gut (mag man denken) Der Nachtwächter kommt wieder (so wie immer) alle 10 Sekunden in den Raum und geht seine Checkliste durch: er sieht auf seine Uhr und wenn die 03:00 anzeigt, macht er das Fenster auf. Er sieht wieder auf seine Uhr und wenn die 05:00 anzeigt, dreht er die Heizung auf. Und er sieht ein drittes mal auf seine Uhr und wenn die 05:00 anzeigt, dann schliesst er das Fenster. Bis es dann eines Tages soweit ist, dass zwar die Heizung an war aber das Fenster nicht geschlossen wurde. Was war geschehen? Wie immer hat er seine Runden gegangen und ist alle 10 Sekunden in diesen Raum gegangen. Um zu entscheiden, ob die erste Regel angewendet werden kann, hat er auf seine Uhr gesehen, die hat nicht 03:00 angezeigt, also hat er das Fenster in Ruhe gelassen. Für die 2.te Regel hat er erneut auf die Uhr geblickt und 05:00 abgelesen. Passt. Die Ausgangsbedingung für die 2.te Regel ist erfüllt * Um 05:00 drehst du die Heizung auf Genau das hat er getan. Aber das Heizungsventil hat etwas geklemmtn so dass er länger als gewöhnlich dafür gebraucht hat. Um seine 3-te Regel abzuarbeiten hat er erst mal wieder auf die Uhr gesehen. Er hat 05:01 abgelesen. Und damit war die Ausgangsbedingung für die 3.te Regel nicht erfüllt. 05:01 ist nicht dasselbe wie 05:00 und daher hat er das Fenster nicht angerührt. Wo liegt der Fehler? Der Fehler sind deine Regeln! Die sind unpräzise formuliert und so gestaltet, dass es zu solchen Fehlleistungen kommen kann. Das das im täglichen Leben kein Problem gibt, liegt daran, dass Menschen mitdenken! Etwas was Computer nicht tun. Die Regeln hätten so formuliert werden müssen * stelle die aktuelle Uhrzeit fest und merke sie dir * Ist die gemerkte Uhrzeit 03:00 dann öffne das Fenster * Ist die gemerkte Uhrzeit 05:00 dann drehe die Heizung auf * Ist die gemerkte Uhrzeit 05:00 dann mach das Fenster zu Dadurch, dass er ganz am Anfang erst mal die Uhrzeit feststellt und in weiterer Folge nur noch mit dieser gemerkten Uhrzeit operiert, kann das '5-Uhr' Problem jetzt nicht mehr entstehen. Denn selbst wenn das Heizkörperventil klemmt und er Zeit zur Behebung benötigt, die gemerkte Uhrzeit ist immer noch 05:00, selbst wenn die Armbanduhr durch den Zeitverzug schon 05:04 anzeigt. Und da das so ist, wird dann auch das Fenster geschlossen, weil die Voraussetzungen (Ist die gemerkte Uhrzeit 05:00?) gegeben sind. Wodurch ist das Problem entstanden? Dadurch, dass seine Armbanduhr weiterglaufen ist, während er gearbeitet hat. Wie ist es entschärft worden? Dadurch, dass die laufende Armbanduhr durch eine Stichzeit die als allererstes festgestellt wird, ersetzt wurde. Danach kann die Armbanduhr ruhig weiterlaufen, es gilt nur noch diese Stichzeit für diesen einen Besuch im Raum. Beim nächsten Besuch gilt dann eine andere Stichzeit. Aber die entscheidet sich erst, wenn er das nächste mal wieder reinkommt.
Datum:
Ich habs mir als Anfänger angewöhnt, immer wenn möglich bei solchen Timerfällen auf >= abzufragen. Nun auch mal ne Frage von mir, da ich zwar auch Überlegungen zu dem Programm angestellt hab, aber wie gesagt noch Anfänger bin und nich sicher ob das Funktioniert. In der ISR würde ich die Zählvariable ohne die else schleife betreiben. Zurücksetzen würd ich sie, wenn wirklich alle Bedingungen im Mainprogramm durchlaufen wurden. Dh ich zähle in der ISR bis zu 9 und setze im Mainprogramm alles zurück wenn die Bearbeitung abgeschlossen ist. Im Mainprogramm wie gesagt >= abgefragt, kann ich auch ruhig mal etwas Hardware umbauen und hab bei nem entstehenden Delay dadurch nicht gleich Probleme mit meinem Timer, da dieser halt etwas ungenauer ist, aber immernoch Funktioniert. Was würde gegen diese Vorgehensweise sprechen? Zu unübersichtlich in der Main die Zählvariable zurückzusetzen? Vielleicht der übersicht halber bei fertiger Bearbeitung eine weitere Globale Variable zu setzen, die in der ISR die Zählvariable zurücksetzt? (Das würde natürlich die Bearbeitungszeit der ISR unnötig erhöhen). Wäre dankbar wenn jemand meine Gedanken kritisch beurteilt, will mich ja weiterentwickeln :) Mit freundlichen Grüßen Christian Trohn
Datum:
Christian Trohn schrieb: > Mainprogramm durchlaufen wurden. Dh ich zähle in der ISR bis zu 9 und > setze im Mainprogramm alles zurück wenn die Bearbeitung abgeschlossen > ist. Im Mainprogramm wie gesagt >= abgefragt, kann ich auch ruhig mal > etwas Hardware umbauen und hab bei nem entstehenden Delay dadurch nicht > gleich Probleme mit meinem Timer, da dieser halt etwas ungenauer ist, > aber immernoch Funktioniert. Skizzier das mal in Code. Lese ich deine Beschreibung, dann denke ich, dass du in die gleiche Falle läufst, wie der TO > Was würde gegen diese Vorgehensweise sprechen? Zu unübersichtlich in der > Main die Zählvariable zurückzusetzen? Vielleicht der übersicht halber > bei fertiger Bearbeitung eine weitere Globale Variable zu setzen, die in > der ISR die Zählvariable zurücksetzt? (Das würde natürlich die > Bearbeitungszeit der ISR unnötig erhöhen). unnötig ist ein relativer Begriff. Wenn es der Systemstabilität dient, dann ist es nicht unnötig. Und ja, das wäre mein Ansatz: Zwei LED-Zeitzähler, die in der ISR dekrementiert werden bis sie 0 sind. In der Hauptschleife dient diese 0 als Trigger, die Aktion auszulösen (und dort werden sie dann wieder auf einen Startwert gesetzt). Mit zuvielen Flags und Variablen, die mehrere Aktionen auslösen, kann man sich nämlich auch ganz schnell ins Knie schiessen. Irgendwann überblickt dann keiner mehr, welche Variable auf welchem Wert stehen muss (bzw. Kombinationen von mehreren Variablen mit bestimmten Werten), damit welche Aktionen angestossen werden.
Datum:
@ Achim Seeger (achims) >Einer dieser Beträge läuft unter dem Namen "Warten verboten". >Dort wird beschrieben, wie die Auswirkung bei delay mit 0,5s oder 1s >ist. Als Lösung wurde vorgeschalgen, delay auf 1ms zu nehmen und die >einzelnen Ansteuerungen oder Abfragen mehrmals zu machen. Im Text heisst Meinst du das hier? http://www.mikrocontroller.net/articles/Multitaski... MfG Falk
Datum:
@Karl Heinz Buchegger Da mein Laptop defekt iskann ich nur im Wordpad programmieren, was für mich als Anfänger sehr, naja, suboptimal ist, weil ich desöfteren Leichtsinnsfehler in mein Programm bau. Aber ich habs versucht! Auch würde ich noch einen Zustand definieren, indem ich das Toggle der LED beispielsweise Aus schalten kann, wie in wait10 unten aufgezeigt. Mein Lösungsweg für diese Funktion wäre folgende: ISR (TIMER2_COMP_vect) { if((wait<10)&(wait>0)) { wait++; } // if((wait10<10)&(wait10>0)) { wait10++; } } In der Main dann die abfragen: if (wait>=10) { wait=1; LED_tog(0); // irgendeine Funktion halt } if (wait>=10) { wait=0; // Würde den Timer vorerst Deaktivieren bis wait==1 LED_tog(1); } Auch wenns jetzt nicht direkt auf die Fragestellung des TO bezogen ist würde ich doch gern ne ehrliche Meinung zu diesem Weg hören. Das einzige Problem was ich in diesem Weg selbst sehe ist, das der Timer schon beim setzen der wait=1 funktion bei 254 stehen könnte. Somit wäre der erste Umschlag der Zählvariable nicht spürbar. Man könnte diesen Fehler durch einen geringeren Prescaler und einen höheren Zählwert minimieren. Auch die Programmlaufzeit muss schön überdacht sein, da ich ja auch nen Programm mit 500ms Laufzeit haben kann und 10ms die LED Toggeln will. Das würde natürlich gar nicht gehen. Aber eigentlich wäre ich bei der Lösung frei von ner begrenzten Anzahl an Timern. Ich könnte natürlich auch 20 Zähl variablen hochzählen lassen und 20 LEDs toggeln mit einem Timer, was meiner Meinung nach die meißten Nachteile aufhebt. Vorrausgesetzt ich hab natürlich keinen blöden Leichtsinnsfehler im Programm und Merks grad nicht. Mit freundlichen Grüßen Christian Trohn
Datum:
Sry die 2. Funktion soll natürlich das Beispiel mit wait10 darstellen, sonst is ja Glücksache wo das Mainprogramm steht wenn ich 2 mal wait abfrage!
Datum:
Karl Heinz Buchegger schrieb: > Denk mal über folgendes konstuierte Beispiel nach [...] Sehr schöner Vergleich, aber auch Deine entschärfte Version kann noch schief gehen. Wenn z.B. das Einschalten der Heizung um 4:59 auf dem Programm steht und er drei Minuten mit dem klemmenden Ventil beschäftigt ist, bleibt das um 5:00 Uhr zu schließende Fenster wieder auf. Daher müßten die Bedingungen heißen:"Wenn es X Uhr oder später ist und die Aufgabe noch nicht erledigt wurde ..."
Datum:
R. Max Ich glaube du hast sein Beispiel falsch Verstanden. Ich denke er meint, dass du auch während er das Ventil repariert um 5 Uhr auf die Uhr schaut und sozusagen nen Harken in seine Checkliste bei "muss gemacht werden" setzt. Dann kann das Ventil auch 10 Minuten Dauern, der Harken in der Checkliste ist gesetzt und muss Bearbeitet werden. Mit freundlichen Grüßen Christian Trohn
Datum:
Hallo Falk diesen Artikel meine ich. Eigentlich bin ich dadurch auf diese Sache gestossen. Hatte vorher das Problem, wenn der Proz etwas macht, z.B. Motor ansteuert, Ventil oder anderes (mechanisch) und es tritt ein Verstoss der Sicherheit ein, Kante, Druck oder anderes. Dann arbeitet der Proz so lange bis das Teil fertig ist un macht damm sofort was anderes, das Gegenteil. Während dieser Zeit ist er blind und taub. Auf Grund der Verarbeitung kann ich zwar nicht sofort reagieren, ich brauche aber auch nicht unnötig zu warten. Dann habe ich mir die Sachen von KH+DA angesehen. Sind sehr gut gemacht. Aber zum schalten von 2 LED viel zu lang. Es sollte was einfaches sein, unkompliziert und vor allen für mich nachvollziehbar. Habe noch ca. 8 andere Artikel gefunden mit den verschiedenen Vorschlägen. Konnten mich aber nicht überzeugen. Ist doch was für unsere Kollegen KH+DA. Macht was kurzes prägnanntes draus, was überall eingebaut werden kann. achim
Datum:
@ Achim Seeger (achims) >KH+DA angesehen. Sind sehr gut gemacht. Aber zum schalten von 2 LED viel >zu lang. Es sollte was einfaches sein, unkompliziert und vor allen für >mich nachvollziehbar. Na dann bis DU erstmal in der Pflicht. Nämlich allgemein zu sagen WIE deine LEDs geschaltet werden sollten, OHNE deine verquere Lösung da mit reinzurühren. Siehe Netiquette. DANN kann man auch ein einfaches, problemorientierte Beispiel schreiben. MfG Falk
Datum:
Chrstian Trohn schrieb: > Ich glaube du hast sein Beispiel falsch Verstanden. Glaube ich nicht. > Ich denke er meint, dass du auch während er das Ventil repariert um 5 Uhr > auf die Uhr schaut und sozusagen nen Harken in seine Checkliste bei > "muss gemacht werden" setzt. Das würde aber der Analogie mit dem Programm widersprechen. Karl Heinz sagte, der Wächter merkt sich die aktuelle Uhrzeit und arbeitet dann alle Tätigkeiten ab, die mit genau diesem Zeitpunkt in der Liste stehen. Dauert das zusammen länger als der zeitliche Abstand zur nächsten Aufgabe, wird diese Aufgabe immer noch "übersehen", denn beim nächsten Blick auf die Uhr ist deren Zeit ja schon um.
Datum:
Ja du hast recht, ich hab da wohl irgendwie noch den funktionierenden Weg im Kopf gehabt und auf das Beispiel übertragen, mein Fehler. Mit freundlichen Grüßen Christian Trohn