Soweit richtig, das bekommt der Threadersteller sicher hin. Was ergänzend genannt werden sollte: Schau dir das Beispiel BlinkWithoutDelay an, du darfst deinen Code nicht blockierend schreiben. Das heißt du darfst schon, es hilft dir aber nicht bei der Lösung des Problems. ![]()
#include <IRremote.h>
const byte Recv_PIN = 11;
const byte Hp0 = 2;
const byte Hp0r = 3;
const byte Hp1 = 4;
const byte Hp2 = 5;
const byte Ra121 = 6;
const byte Ra122 = 7;
const byte Zs7 = 8;
const byte IR_Empf = 11;
//int Blink = 0;
bool blinkanforderung;
const byte ledPin = 6;
bool ledState = LOW;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
const unsigned long interval = 1000;
IRrecv irrecv (IR_Empf);
decode_results results;
/// functions ///
void setLed(bool hp0, bool hp0r, bool hp1, bool hp2, bool ra121, bool ra122, bool zs7)
{
digitalWrite (Hp0, hp0);
digitalWrite (Hp0r, hp0r);
digitalWrite (Hp1, hp1);
digitalWrite (Hp2, hp2);
digitalWrite (Ra121, ra121);
digitalWrite (Ra122, ra122);
digitalWrite (Zs7, zs7);
}
////////
void setup()
{
// put your setup code here, to run once:
irrecv.enableIRIn ();
Serial.begin (9600);
pinMode (Hp0 , OUTPUT);
digitalWrite (Hp0, HIGH);
pinMode (Hp0r, OUTPUT);
digitalWrite (Hp0r, HIGH);
pinMode (Hp1, OUTPUT);
digitalWrite (Hp1, LOW);
pinMode (Hp2, OUTPUT);
digitalWrite (Hp2, LOW);
pinMode (Ra121, OUTPUT);
digitalWrite (Ra121, LOW);
pinMode (Ra122, OUTPUT);
digitalWrite (Ra122, LOW);
pinMode (Zs7, OUTPUT);
digitalWrite (Zs7, LOW);
pinMode (13, OUTPUT);
digitalWrite (13, LOW);
}
void irZeugs()
{
if (irrecv.decode(&results))
{
Serial.println (results.value, DEC);
switch (results.value)
{
case 16750695: setLed(1, 1, 0, 0, 0, 0, 0); blinkanforderung = false; break; //0
case 16753245: setLed(0, 0, 1, 0, 0, 0, 0); break; //1
case 16736925: setLed(0, 0, 1, 1, 0, 0, 0); break; //2
case 16769565: setLed(1, 0, 0, 0, 1, 1, 0); break; //3
case 16720605: setLed(1, 1, 0, 0, 0, 0, 1); break; //4
case 16712445: setLed(1, 0, 0, 0, 1, 0, 0); blinkanforderung = true; break; //5
case 16756815: setLed(1, 1, 1, 1, 1, 1, 1); break; //#
case 16738455: setLed(0, 0, 0, 0, 0, 1, 0); break; //*
case 16748655: setLed(1, 0, 1, 0, 1, 0, 0); break; //9
}
irrecv.resume();
}
}
void blinker()
{
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
ledState = not ledState;
}
digitalWrite (ledPin, ledState && blinkanforderung);
}
void loop()
{
currentMillis = millis();
irZeugs();
blinker();
}
** ungetestet **
Oh Vielen Dank da war ich gerade selber auf einem Holzweg mit meinem Versuch.
void Blink (bool Blinken)
{
Blinken = false;
}
hab ich versucht
hat nicht so funktioniert
Also Blinken tut es jetzt korrekt, aber
Beim Fall 3, 9 und hashtag leuchtet die LED nur kurz aus und bleibt dann aber Dunkel dort bräuchte man die LED wiederum im Dauerlicht
Tja...
So ist das , wenn ich kein Eisenbahner bin.
Und so kryptischen Bezeichner verwendet werden.....
Da wirste dann wohl noch eine Extrawurst backen müssen...
Da hast du recht ich bin gerade dabei und versuche das zu korregieren
Das ist wohl eine der Programmierer Todsünden.
Ach, nun wurde hier schon viel geschrieben, das habe ich nicht alles gelesen.
Die Notwendigkeit eines Merkers wurde ja schon erwähnt, dazu habe ich einen Vorschlag, bei dem ich mich an #5 orientiert habe:
#include <IRremote.h>
const byte Hp0 = 2; // Rote LED
const byte Hp0r = 3; // Rote LED
const byte Hp1 = 4; // Grüne LED
const byte Hp2 = 5; // Gelbe LED
const byte Ra121 = 6; // Weiße LED
const byte Ra122 = 7; // Weiße LED
const byte Zs7 = 8; // Gelbe LED
const byte IR_Empf = 11;
bool blinkenRa121 = false; // Merker für Blinken
// 0, 1, 2, 3, 4, 5, #, *, 9
//constexpr uint32_t IRCODE[] = {16750695, 16753245, 16736925, 16769565, 16720605, 16712445, 16756815, 16738455, 16748655};
constexpr uint32_t IRCODE[] = {0xFF6897, 0xFF30CF, 0xFF18E7, 0xFF7A85, 0xFF10EF, 0xFF38C7, 0xFF5AA5, 0xFF42BD, 0xFF52AD}; // Car mp3 Fernbedienung
IRrecv irrecv (IR_Empf);
decode_results results;
/// functions ///
void setLed(bool hp0, bool hp0r, bool hp1, bool hp2, bool ra121, bool ra122, bool zs7, bool _blinkenRa121) {
digitalWrite (Hp0, hp0);
digitalWrite (Hp0r, hp0r);
digitalWrite (Hp1, hp1);
digitalWrite (Hp2, hp2);
digitalWrite (Ra121, ra121);
digitalWrite (Ra122, ra122);
digitalWrite (Zs7, zs7);
blinkenRa121 = _blinkenRa121;
}
void blinken (void)
{
if (blinkenRa121)
{
const uint32_t INTERVALL = 500;
uint32_t jetzt = millis();
static uint32_t vorhin = -INTERVALL;
if (jetzt - vorhin >= INTERVALL)
{
vorhin = jetzt;
digitalWrite (Ra121, !digitalRead(Ra121));
}
}
}
////////
void setup()
{
// put your setup code here, to run once:
irrecv.enableIRIn ();
Serial.begin (9600);
Serial.println ("\nStart");
pinMode (Hp0 , OUTPUT);
digitalWrite (Hp0, HIGH);
pinMode (Hp0r, OUTPUT);
digitalWrite (Hp0r, HIGH);
pinMode (Hp1, OUTPUT);
digitalWrite (Hp1, LOW);
pinMode (Hp2, OUTPUT);
digitalWrite (Hp2, LOW);
pinMode (Ra121, OUTPUT);
digitalWrite (Ra121, LOW);
pinMode (Ra122, OUTPUT);
digitalWrite (Ra122, LOW);
pinMode (Zs7, OUTPUT);
digitalWrite (Zs7, LOW);
pinMode (13, OUTPUT);
digitalWrite (13, LOW);
}
void loop() {
blinken();
if (irrecv.decode(&results))
{
uint32_t fbcode = results.value;
Serial.print(fbcode, HEX); Serial.print ('\t'); Serial.println (fbcode, DEC);
switch (fbcode)
{
case IRCODE[0]: //0
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(1, 1, 0, 0, 0, 0, 0, 0);
break;
case IRCODE[1]: //1
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(0, 0, 1, 0, 0, 0, 0, 0);
break;
case IRCODE[2]: //2
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(0, 0, 1, 1, 0, 0, 0, 0);
break;
case IRCODE[3]: //3
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(1, 0, 0, 0, 1, 1, 0, 0);
break;
case IRCODE[4]: //4
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(1, 0, 0, 0, 1, 0, 0, 0);
break;
case IRCODE[5]: //5
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(1, 0, 0, 0, 0, 0, 0, 1);
break;
case IRCODE[6]: //#
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(1, 1, 1, 1, 1, 1, 1, 0);
break;
case IRCODE[7]: //*
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(0, 0, 0, 0, 0, 1, 0, 0);
break;
case IRCODE[8]: //9
// Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
setLed(1, 0, 1, 0, 1, 0, 0, 0);
break;
}
irrecv.resume();
}
}
Das Feld IRCODE[] habe ich eingeführt, um schneller zwischen Deiner und meiner Fernbedienung wechseln zu können.
Ob ein Lokführer damit glücklich wäre, weiß ich nicht, aber Leuchten tut etwas, Blinken auch.
EDIT: Funktion blinken() hinsichtlich Blinkzeit verändert: vorhin = jetzt;
Da hasste aber dem Nachtwächter eine Falle gestellt...
![]()
Was du da an die Funktion übergibst wird in die lokale Variable Blinken kopiert. Was du dann darin veränderst ist Außen nicht sichtbar. Stichwort "call by value"
Außerdem ist es in diesem Fall generell etwas übertrieben dafür eine Funktion zu schreiben. Sowas macht man bei Klassen. Aber aus anderen Gründen
Zur Info!
Das wollte ich nicht, habe ich mir was falsch gemerkt?
Sonst habe ich das immer so gemacht:
if (jetzt - vorhin >= INTERVALL)
{
vorhin = jetzt;
digitalWrite (Ra121, !digitalRead(Ra121));
}
Das wurde mir aber als ungenau angekreidet, daher die neue Variante. Da das Programm funktioniert, wo könnte der Nachtwächter stolpern?
Wie ist es denn nun richtig?
Naja....
Es wird der Zeitpunkt etwas verschleppt, aber ob das hier wichtig ist....
if (jetzt - vorhin >= INTERVALL)
{
vorhin += INTERVALL;
digitalWrite (Ra121, !digitalRead(Ra121));
}
Das unterbindet die Verschleppung(so gut es geht).
Ich nenne es den Aufholtimer, eben, weil er Zeitverluste wieder aufholt.
Zumindest addieren sich verlorene Millis nicht auf.
Weiß nicht...
Durch die Addition der Zeiten, fängst du dir einen Überlauf ein, welcher dir nach 49,x Tagen einen Stock in die Speichen schiebt.
Natürlich nicht, aber ich würde mir gerne nur eine Variante merken, die in den meisten Fällen funktioniert.
Da ich Deine Variante auf die Schnelle nicht zum Laufen bekomme, falle ich zunächst auf die Verschleppungs-Variante zurück. Das ändere ich in #27.
Aber ich melde mich ![]()
Meine Timer basieren auch alle auf der "Verschleppungsmethode" bzw. dem Nachtwächter
.
Das andere Verfahren wende ich nur an, wenn muss.
Das genaueste geht halt nur mit Hardwaretimern.
Das wundert mich....
Da #27 als Lösung markiert wurde, werde ich nun hemmumgslos hier weitermachen ![]()
Mich erst. Ich werde versuchen, es Dir deutlich zu machen.
Die Verschleppungsvaraiante:
void blinken (void)
{
if (blinkenRa121)
{
const uint32_t INTERVALL = 500;
uint32_t jetzt = millis();
static uint32_t vorhin = -INTERVALL;
if (jetzt - vorhin >= INTERVALL)
{
Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
vorhin = jetzt;
digitalWrite (Ra121, !digitalRead(Ra121));
}
}
}
Monitor:
17:25:14.737 -> Start
17:25:21.544 -> 6805 4294966796
17:25:22.046 -> 7305 6805
17:25:22.547 -> 7805 7305
17:25:23.049 -> 8305 7805
17:25:23.551 -> 8805 8305
17:25:24.052 -> 9305 8805
17:25:24.554 -> 9805 9305
17:25:25.050 -> 10305 9805
17:25:25.535 -> 10805 10305
17:25:26.032 -> 11305 10805
17:25:26.533 -> 11805 11305
17:25:27.035 -> 12305 11805
17:25:27.536 -> 12805 12305
17:25:28.038 -> 13305 12805
17:25:28.540 -> 13805 13305
17:25:29.041 -> 14305 13805
17:25:29.543 -> 14806 14305
17:25:30.071 -> 15306 14806
17:25:30.572 -> 15806 15306
17:25:31.074 -> 16306 15806
17:25:31.574 -> 16806 16306
So weit so bekannt.
Nun die Variante ohne Verschleppung:
void blinken (void)
{
if (blinkenRa121)
{
const uint32_t INTERVALL = 500;
uint32_t jetzt = millis();
static uint32_t vorhin = -INTERVALL;
if (jetzt - vorhin >= INTERVALL)
{
Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
vorhin += INTERVALL;
digitalWrite (Ra121, !digitalRead(Ra121));
}
}
}
17:29:51.583 -> Start
17:30:02.967 -> 11386 4294966796
17:30:02.967 -> 11387 0
17:30:03.021 -> 11388 500
17:30:03.021 -> 11388 1000
17:30:03.021 -> 11389 1500
17:30:03.021 -> 11389 2000
17:30:03.068 -> 11397 2500
17:30:03.068 -> 11409 3000
17:30:03.068 -> 11421 3500
17:30:03.068 -> 11433 4000
17:30:03.121 -> 11447 4500
17:30:03.121 -> 11459 5000
17:30:03.121 -> 11471 5500
17:30:03.121 -> 11484 6000
17:30:03.168 -> 11496 6500
17:30:03.168 -> 11509 7000
17:30:03.168 -> 11522 7500
17:30:03.168 -> 11534 8000
17:30:03.222 -> 11546 8500
17:30:03.222 -> 11558 9000
17:30:03.222 -> 11571 9500
17:30:03.222 -> 11584 10000
17:30:03.268 -> 11597 10500
17:30:03.268 -> 11611 11000
17:30:03.569 -> 12000 11500
17:30:04.071 -> 12500 12000
17:30:04.573 -> 13000 12500
17:30:05.074 -> 13500 13000
17:30:05.576 -> 14000 13500
17:30:06.077 -> 14500 14000
17:30:06.579 -> 15000 14500
17:30:07.080 -> 15500 15000
Hier stimmt wohl der Startwert nicht, da vorhin zunächst den aktuellen Zeitwert einholen muß. Das ergibt ein paar ungewollte Durchläufe der Funktion, die immer den Ausgang umschaltet.
Ein neuer Versuch mit Änderungsmerker:
void blinken (void)
{
const uint32_t INTERVALL = 500;
uint32_t jetzt = millis();
static uint32_t vorhin;
static bool altblinkenRa121 = blinkenRa121;
if (altblinkenRa121 != blinkenRa121)
{
altblinkenRa121 = blinkenRa121;
vorhin = jetzt - INTERVALL;
}
if (blinkenRa121)
{
if (jetzt - vorhin >= INTERVALL)
{
Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
vorhin += INTERVALL;
digitalWrite (Ra121, !digitalRead(Ra121));
}
}
}
Monitor:
17:44:17.077 -> Start
17:44:25.407 -> 8335 7835
17:44:25.909 -> 8835 8335
17:44:26.410 -> 9335 8835
17:44:26.912 -> 9835 9335
17:44:27.414 -> 10335 9835
17:44:27.915 -> 10835 10335
17:44:28.417 -> 11335 10835
17:44:28.918 -> 11835 11335
Die PC-Uhr scheint nicht synchron mit dem UNO, aber bezogen auf millis() könnte es so stimmen. Aber was passiert in 49 Tagen?
17:50:03.066 -> Start
17:50:03.715 -> 4294962981 4294962481
17:50:04.216 -> 4294963481 4294962981
17:50:04.718 -> 4294963981 4294963481
17:50:05.220 -> 4294964481 4294963981
17:50:05.721 -> 4294964981 4294964481
17:50:06.223 -> 4294965481 4294964981
17:50:06.724 -> 4294965981 4294965481
17:50:07.226 -> 4294966481 4294965981
17:50:07.727 -> 4294966981 4294966481
17:50:08.229 -> 185 4294966981
17:50:08.731 -> 685 185
17:50:09.232 -> 1185 685
17:50:09.734 -> 1685 1185
17:50:10.235 -> 2185 1685
17:50:10.737 -> 2685 2185
17:50:11.243 -> 3185 2685
17:50:11.745 -> 3685 3185
@combie: Bist Du so einverstanden?
Weiß nicht....
Mir ist das schon fast zu kompliziert.....
z.B. irritiert mich ein wenig, dass du if (jetzt - vorhin >= INTERVALL) hinter einem if versteckst.
Das bedingt dann wohl, dass du die Zeiten zurechtmogeln willst
--> vorhin = jetzt - INTERVALL;
Irgendwie habe ich wohl noch nicht verstanden, was du "wirklich" erreichen möchtest....
Hallo,
das if (jetzt - vorhin >= INTERVALL) ist doch korrekt.
Das entspricht if (millis() - lastMillis >= INTERVALL)
Nur die Subtraktion mit vorhin darüber ist Unsinn. Das bringt alles durcheinander.
void blinken (void)
{
const uint32_t INTERVALL {500};
uint32_t jetzt {millis()};
static uint32_t vorhin {0};
if (jetzt - vorhin >= INTERVALL)
{
Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
vorhin += INTERVALL;
}
}
Die Unterscheidung zwischen ohne oder mit "Verschleppung" ist nur davon abhängig was man genau möchte. Möchte man ein genaues Intervall unabhängig des Aufrufzeitpunktes einhalten. Oder möchte man den zeitlichen Aufrufabstand auf eine Mindestzeit festlegen. Mehr ist das nicht.
Edit:
Vielleicht so besser was agmue laut meiner Glaskugel testen möchte.
void blinken (void)
{
const uint32_t INTERVALL {500};
uint32_t jetzt {millis()};
static uint32_t vorhin {0};
if (jetzt - vorhin >= INTERVALL)
{
Serial.print(jetzt); Serial.print('\t'); Serial.print(vorhin); Serial.print('\t');
vorhin += INTERVALL;
Serial.println(vorhin);
}
}
Für mich tun sich mehrere Themen auf, "was ist der Unterschied" ist hiermit schon beantwortet:
Hier kann ich nicht zustimmen:
Bei kurzen Intervallen fällt es nicht auf, doch die Zeit zwischen Reset und INTERVALL bedarf einer speziellen Betrachtung.
Später nach Reset ist jetzt - vorhin >= INTERVALL wahr, wenn die Bedingung zum Blinken erfüllt ist. Die LED wird also sofort umgeschaltet.
In der Zeit zwischen Reset und INTERVALL ist die Bedingung aber nicht erfüllt, weshalb die LED erst nach der Zeit INTERVALL umschaltet.
Gegenmaßnahme ist, jetzt in die Vergangenheit zu verlegen. Mittels static uint32_t vorhin = -INTERVALL; von einer vorzeichenlosen Variablen etwas abzuziehen ist meine Lösung.
Die auch völlig legitim und richtig ist.
Gruß Tommy
Wenn ich das mal ein wenig abstrahiere, dann gibt es 2 Varianten, das Intervall abzuhandeln. Einmal den Aufholtimer und den verschleppenden.
Es gibt 2 mögliche Aktionszeitpunkte. Einmal vor dem Intervall und einmal danach
Somit sind es 4 mögliche Timer Varianten.
Das waren in etwa meine Gedanken, als ich meine(n) Timer entworfen habe.
Sie scheinen auch hier zuzutreffen.
Nach langem prüfen, habe ich mich dazu entschlossen den verschleppenden zu wählen. Zudem die Aktion nach dem Intervall.
z.B. der CombieTimer ist per default, auf stehend/inaktiv, als abgelaufen konfiguriert.
Damit lassen sich die wichtigsten Anwendungen abdecken.
In den meisten Fällen, ist es nicht schlimm, wenn es etwas verschleppt.
Auch der Fall, dass die Aktion bei Intervall Start stattfinden soll, geht damit.
Das ist etwas, was mich stört.
Nicht , dass es falsch wäre, in der Form, dass es Probleme macht, aber "emotional" werde ich damit nicht fertig. Für mich haben sich millis, in jeder Form, an die Kausalität zu halten.
Keine Zeit Sprünge rückwärts.
Wie gesagt, keine technische, sondern eine emotionale Hürde für mich, das zuzulassen, oder dem zuzustimmen.
Eins meiner Beispiele
Die Task blink() führt die Aktion vor dem Intervall durch
Task showLoops() nach dem Intervall
#include <TaskMacro.h>
/**
* Auf Tastendruck wird 5 mal geblinckt
*/
const byte taster = 4; // Taster zwischen Pin und GND
const byte led = 13; // Led zwischen Pin und GND
const unsigned long interval = 500; // ms
const byte zyklen = 5; // Anzahl Blinker
bool blinkAnforderung = false; // Merker für Blink Anforderung
Task blink()
{
static byte i = 0; // Wiederholungszaehler
taskBegin();
while(1)
{
taskWaitFor(blinkAnforderung);
for(i=0;i<zyklen;i++)
{
digitalWrite(led, HIGH); // leuchte an
taskPause(interval);
digitalWrite(led, LOW); // leuchte aus
taskPause(interval);
}
blinkAnforderung = false ; // Anforderung konsumieren
}
taskEnd();
}
Task tastenAuswertung()
{
taskBegin();
while(1)
{
taskWaitFor(!digitalRead(taster));
blinkAnforderung = true;
}
taskEnd();
}
Task showLoops()
{
static unsigned long loops = 0;
loops++;
taskBegin();
for(;;)
{
taskPause(1000);
Serial.print("Loops pro Sekunde: ");
Serial.println(loops);
loops = 0;
}
taskEnd();
}
void setup()
{
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(taster,INPUT_PULLUP);
}
void loop()
{
blink();
tastenAuswertung();
showLoops();
}
Vergleichbares geht auch mit den Datenflussorienten CombieTimer.
Auch das INTERVAL Makro hat diese Erweiterung bekommen, sofort mit der Aktion zu starten, in dem man ihm eine Startzeit mitgibt.
INTERVAL(500) macht nach 500ms die erste Aktion, danach alle 500ms
INTERVAL(500,2000) macht nach 2s die erste Aktion, danach alle 500ms
INTERVAL(500,0) macht sofort die erste Aktion, danach alle 500ms
Alles ohne Zeit Sprung rückwärts.
Man kann also schon dem Zeitparadox aus dem Weg gehen.
Danke, dann bin ich ja nicht vollkommen auf dem Holzweg ![]()
In den meisten Fällen, ist es nicht schlimm, wenn es etwas verschleppt.
Auch der Fall, dass die Aktion bei Intervall Start stattfinden soll, geht damit.
Gut, für blinkende LEDs werde ich diese Variante beibehalten.
Das ist etwas, was mich stört.
Da stimme ich Dir zu!
digitalWrite(led, HIGH); // leuchte an taskPause(interval); digitalWrite(led, LOW); // leuchte aus taskPause(interval);
Das ist genau das, wonach Anfänger suchen. Nur kann ich die CombieTimer leider nicht erklären, weshalb ich sie vorsichtshalber nicht verwende.
Man kann also schon dem Zeitparadox aus dem Weg gehen.
Wer kann, der kann ![]()
Wer nicht kann, muß sich mit der Nichtlinearität der Zeit trösten. Aber das ist ein ganz anderes Thema und für blinkende LEDs glücklicherweise wenig relavant.
Danke an Alle, die mir ermöglicht haben, wieder etwas klarer in den Programmiernebel zu schauen!
@primehgn: Danke, daß Du mich hast machen lassen ![]()