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
@ 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
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
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
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
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 xAchim Seeger schrieb:> if ( led2 == 50 ) // Einstellung Zeit 10ms mal x
led2 sollte also doppelt so schnell blinken.
so far!
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
1
// Reset task timers and 10ms alarm flag
2
// volatile uint8_t wait10; // defined elsewhere (globally)
3
uint8_talarm_10ms=0;
4
uint8_tled1=0;
5
uint8_tled2=0;
6
7
// init and start wait10 timer interrupt
8
...
9
10
while(1){
11
// Check 10ms timer interrupt result/flag
12
if(wait10==0xFF){
13
wait10=0;// 10ms stop watch reset
14
alarm_10ms=1;// trigger 10ms alarm check
15
}
16
17
// Check every 10ms all alarms for task #1, #2, ...
18
if(alarm_10ms){
19
alarm_10ms=0;// reset 10ms alarm flag
20
// Check Task #1: LED 5: 100 * 10ms = 1s
21
if(++led1==100){
22
led1=0;
23
...// pos#1
24
}
25
// Check Task #2: LED 4: 50 * 10ms = 0.5s
26
if(++led2==50){
27
led2=0;
28
...// pos#2
29
}
30
...othertasks...
31
// pos#3
32
}
33
}
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)).
>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:
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.
>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.
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:
>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.
@ 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.
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?
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
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
Achim Seeger schrieb:> ja das will ich, es soll die LED nur geschaltet werden, wenn si vorher> aus ist.
Sowas macht man so:
1
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.
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
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.
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
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.> achimlol
Du sollst Absätze machen!
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
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
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;
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.
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
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
1
ISR(TIMER2_COMP_vect)// wait1=1m
2
{
3
if(wait<9)// Takt 0,5s, bei 9 sind es 10ms
4
{
5
wait++;
6
}
7
else
8
{
9
wait=0;
10
wait10=0xFF;// Signal alle 10ms
11
}
12
}
13
14
intmain(){//Start
15
16
....
17
18
while(1)
19
{
20
if(wait10==0xFF)
21
{
22
wait10=0;
23
// 10 Millisekunden sind um
24
...
25
}
26
27
// ... alles was nicht zeitabhängig ist
28
}
29
}
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'.
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?
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
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.
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.
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
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.
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
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
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:
1
while(1)
2
{
3
if(wait10==0xFF)
4
{// Steuerung LED 5
5
...
6
}
7
8
// Normales Programm über viele Zeilen
9
10
if(wait10==0xFF)
11
{// Steuerung LED 4
12
...
13
}
14
15
// anderes Programm
16
17
}
18
}
19
wait10=0;
20
return0;
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:
1
while(1)
2
{
3
if(wait10==0xFF)
4
{// Steuerung LED 5
5
wait10=0;
6
...
7
}
8
9
// Normales Programm über viele Zeilen
10
11
if(wait10==0xFF)
12
{// Steuerung LED 4
13
wait10=0;
14
...
15
}
16
17
// anderes Programm
18
19
}
20
}
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:
1
wait10_merker=0;
2
while(1)
3
{
4
if(wait10==0xFF)
5
{// Steuerung LED 5
6
wait10=0;
7
wait10_merker=1;
8
...
9
}
10
11
// Normales Programm über viele Zeilen
12
13
if(wait10_merker==1)
14
{// Steuerung LED 4
15
wait10_merker=0;
16
...
17
}
18
19
// anderes Programm
20
21
}
22
}
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.
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
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.
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
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.
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:
1
wait10_merker=0;
2
while(1)
3
{
4
if(wait10==0xFF)
5
{// Steuerung LED 5
6
wait10=0;
7
wait10_merker=1;
8
...
9
Taster_Abfrage();// Taster abfragen *****
10
}
11
12
// Normales Programm über viele Zeilen
13
14
if(wait10_merker==1)
15
{// Steuerung LED 4
16
wait10_merker=0;
17
...
18
Noch_was_anderes();// Hier auch mögliche ******
19
}
20
21
// anderes Programm
22
23
}
24
}
Wichtig ist halt, daß es nur eine Abfrage auf wait10 gibt!
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
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.
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
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.
@ 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/Multitasking#Ein_einfaches_Beispiel_f.C3.BCr_den_AVR
MfG
Falk
@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
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 ..."
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
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
@ 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
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.
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