Mehrere millis()

Hallo liebe community.

Habe gerade wieder ein Problem an dem ich seit Tagen sitze. Ich hoffe ihr könnt mir helfen.
Also folgendes:
Ich habe eine Schaltung wo ich 4 timer mit jeweils 4 Schaltern einstellen kann und 10 Taster die dann meine Beleuchtung einschalten.
Ich betätige die Taster unterschiedlich. Also wenn ich mit dem Schalter 3 min. Vorwähle dann möchte ich Taster 1 drücken und die Zeit läuft ab und währenddessen drücke ich Taster 5 und taster 10 und die sollen auch 3 min. Laufen.
Mein Problem liegt jetzt darin das ich die Funktion millis verwende. Aber das funktioniert nicht so richtig. Denn ich kann zwar einen Taster anwählen aber ich kann nur ein Taster nach dem anderen drücken. Es sollte aber gleichzeitig geschehen.
Deshalb meine Frage an euch:Wie kann ich mehrere Millis einsetzen.

Danke im voraus.

lacki1103:
Deshalb meine Frage an euch:Wie kann ich mehrere Millis einsetzen.

So wie du einen "millis()" setzt. Nur jeder mit eigenen Namen.

Jeder Zeitstrang benötigt sein eigenes lastMillis und sein Intervall oder Deine Beschreibung ist unvollständig.

Gruß Tommy

Wie kann ich mehrere Millis einsetzen.

Hintereinander, und immer nur eines nach dem anderen.

lacki1103:
Mein Problem liegt jetzt darin das ich die Funktion millis verwende. Aber das funktioniert nicht so richtig. Denn ich kann zwar einen Taster anwählen aber ich kann nur ein Taster nach dem anderen drücken. Es sollte aber gleichzeitig geschehen.
Deshalb meine Frage an euch:Wie kann ich mehrere Millis einsetzen.

Du kannst millis() so oft verwenden wie Du es brauchst.
Es gibt kein Limit.
Du musst nur zu jedem Ereignis einen Merker anlegen, diesen setzen und schliesslich auch benutzen

Ohne Code wird das aber nichts.
Zeig doch mal, was Du hast.

Hi

Du hast nur eine Armbanduhr - trotzdem kannst Du verschiedene Dinge gleichzeitig machen

  • Wasser kochen für den Tee - dauert 3 Minuten
  • die Pizza in den Ofen schieben - dauert 20 Minuten
  • das Badewasser einlaufen lassen - 10 Minuten

Alles mit nur EINER Uhr - genau Das ist millis() - diese eine Uhr!
Du musst Dir nur merken, wann Du mit den Tätigkeiten angefangen hast - und eben nicht neben der Pizza stehen bleiben und auf das Ende der 20 Minuten dort warten!

Du schaust immer wieder auf die Uhr und prüfst 'sind jetzt die 3 Minuten für den Tee um?', 'die 20 Minuten für die Pizza?', 'Badewasser schon fertig?'.
Wenn hier die Zeit jeweils nicht um ist - machst Du NICHTS - also auch nicht warten!!

Ich denke, Du nutzt zwar aktuell millis(), aber eben in einer WHILE-Schleife - Was nicht viel anders ist, als delay();

Zeige, was Du hast - dann können wir Dir ggf. helfen.

Auch ist mir nicht wirklich bewusst, was welcher Knopf nun tun soll ... Das bedarf einer besseren Erklärung.

MfG

Ok. Ich würd den Code gerne teilen aber ich weiß nicht wie?

Steht doch alles hier: How to use this forum - please read.
Oder: Setze den bitte in Code-Tags.

Verwende dazu die Schaltfläche </> oben links im Editorfenster.
Das kannst du auch nachträglich machen.
Dazu den Sketch markieren und die Schaltfläche klicken, oder [code] davor und [/code] dahinter ohne *.

Damit wird dieser für alle besser lesbar.

... wollte ich auch gerade verlinken ... ist Das nicht der erste Thread, Den man sich in einem Forum so antut?

postmaster-ino:
... wollte ich auch gerade verlinken ... ist Das nicht der erste Thread, Den man sich in einem Forum so antut?

Ja, wer lesen kann......

ist ja gut und schön die anleitung aber ich sehe diese Pfeile bei mir nicht.

lacki1103:
Deshalb meine Frage an euch:Wie kann ich mehrere Millis einsetzen.

IMO ist Deine Aufgabenstellung ein Paradebeispiel für etwas, für das man „endlichen Automaten“ und Klassen einsetzen/kombinieren kann.

Benutze Klassen, mit denen Du Deine Timer-Funktionen umsetzt. Jedes Exemplar der Klasse speichert dabei eigene Start-/End-/Dauer-Zeiten bzw -Zeitpunkte. Diese Exemplare/Objekte werden in jedem loop()-Durchgang „aufgefordert“, ihren Job zu erledigen - Zeiten ermitteln/abfragen/ausrechnen und Pins schalten.

Das wäre zumindest mein erster Ansatz.

Gruß

Gregor

bool Zeit1 = true;
bool TR1 = true;
bool TR2 = true;
bool TR3 = true;
long ZeitVariable = 0L;
long ZeitVariable1 = 0L;

void setup() {
  pinMode(35, INPUT);
  pinMode(21, OUTPUT);
  pinMode(25, INPUT);
  pinMode(26, INPUT);
  pinMode(27, INPUT);
  pinMode(1, OUTPUT);
  pinMode(39, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(28, INPUT);
  pinMode(29, INPUT);
  pinMode(30, INPUT);
  pinMode(31, INPUT);
  pinMode(32, INPUT);
  pinMode(33, INPUT);
  pinMode(34, INPUT);
  pinMode(36, INPUT);
  pinMode(37, INPUT);
  pinMode(38, INPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(17, OUTPUT);
  pinMode(18, OUTPUT);
  pinMode(19, OUTPUT);
  pinMode(20, OUTPUT);
  pinMode(22, OUTPUT);
  pinMode(23, OUTPUT);
  pinMode(24, OUTPUT);
  pinMode(40, OUTPUT);
  pinMode(41, OUTPUT);
  pinMode(42, OUTPUT);
  pinMode(43, OUTPUT);
  pinMode(44, OUTPUT);
  pinMode(45, OUTPUT);
  pinMode(46, OUTPUT);
  pinMode(47, OUTPUT);
  pinMode(48, OUTPUT);
  pinMode(49, OUTPUT);
}

void loop() {
  if (digitalRead(35)) {
    digitalWrite( 21 , HIGH );
    Zeit1 = true;
  }
  else {
    digitalWrite( 21 , LOW );
    Zeit1 = false;
  }
  if (digitalRead(25)) {
    TR1 = true;
  }
  else {
    TR1 = false;
  }
  if (digitalRead(26)) {
    TR2 = true;
  }
  else {
    TR2 = false;
  }
  if (digitalRead(27)) {
    TR3 = true;
  }
  else {
    TR3 = false;
  }
  if (( Zeit1 && TR1 )) {
    ZeitVariable = millis();
    while (ZeitVariable + 10000L >= millis()) {
      digitalWrite( 1 , HIGH );
      digitalWrite( 39 , HIGH );
    }
    digitalWrite( 1 , LOW );
    digitalWrite( 39 , LOW );
    digitalWrite( 11 , HIGH );
    delay( 1000 );
    digitalWrite( 11 , LOW );
  }

  if ((Zeit1 && TR2)) {
    ZeitVariable1 =  millis();
    while (ZeitVariable1 + 10000L >= millis()) {
      digitalWrite( 2, HIGH);
      digitalWrite(40, HIGH);
    }
    digitalWrite(2, LOW);
    digitalWrite(40, LOW);
    digitalWrite(12, HIGH);
    delay( 1000 );
    digitalWrite(12, LOW);
  }
  if ((Zeit1 && TR3)) {
    ZeitVariable1 =  millis();
    while (ZeitVariable1 + 10000L >= millis()) {
      digitalWrite( 3, HIGH);
      digitalWrite(41, HIGH);
    }
    digitalWrite(3, LOW);
    digitalWrite(41, LOW);
    digitalWrite(13, HIGH);
    delay( 1000 );
    digitalWrite(13, LOW);
  }
}

Evtl. könnte Dir dieses Tutorial von Rentner helfen.

Gruß Tommy

1 Like

Guten Morgen,

hier mal ein Tip, wie Du das setup() gestalten könntest. Trägt vielleicht zur Lesbarkeit bei :wink:

void setup() {
  for (int i=1;i<24;i++){
  pinMode(i, OUTPUT);
  }
  for (int i=39;i<49;i++){
  pinMode(i, OUTPUT);
  }
  for (int i=25;i<38;i++){
  pinMode(i, INPUT);
  }
}

Damit man dir besser helfen kann, und Du deinen eigenen Sketch auch in ein paar Wochen noch verstehst solltest Du ein paar grundsätzliche Dinge beherzigen:

  • Kommentiere deinen Sketch. Schreibe also dazu, was Du dir bei den einzelnen Codeblöcken gedacht hast, und wozu sie da sind. Nur so können wir prüfen, ob der Code auch das tut, was Du beabsichtigt hast.
  • Gebe den Pinnummern am Amfang des Sketches sprechende Namen, und verwende dann im Code nur noch diese Namen. Nur so kann man dann auch erkenne was da passiert - welche Pins z.B. die Schalter und welche die Taster sind - und wozu die jeweiligen Ausgangspins genutzt werden.
  • Mach dich mal über Arrays schlau. Bei so vielen Pins, die alle ähnliches bewirken ist das eine sehr effiziente Methode und erleichtert die Übersicht im Sketch ungemein.

Ausserdem solltest Du dir unbedingt die 'Nachtwächtererklärung' mal anschauen. So wie Du die millis einsetzt, ist das auch nichts anderes als ein einfaches delay() - mit allen entsprechenden Problemen.

Dann kannst Du dir auch mal die MobaTools und die darin enthaltenen Klassen MoToTimer und MoToButtons anschauen. Damit kannst Du deine Anforderungen rel. leicht umsetzen. Es ist auch ein Beispiel dabei, in dem 2 Leds über jeweils einen Taster unabhängig voneinander für eine bestimmte Zeit angeschaltet werden. Das ist ja so ungefähr das, was Du auch vorhast.

Hi

Vermeide, Variablen durchzunummerieren!
TR1, TR2, TR3, Zeit1,...
Variablen (also veränderliche Platzhalter) werden normal komplett klein geschrieben.
Dinge, Die sich NIE ändern, als const (konstant) deklarieren.

ZeitVariable1 =  millis();
    while (ZeitVariable1 + 10000L >= millis()) {
      digitalWrite( 3, HIGH);
      digitalWrite(41, HIGH);
    }

Das fällt Dir nach 49,x Tagen auf die Füße (oder einem Vielfachem davon).
Zeitabfragen IMMER
aktuelle_zeit-start_zeit>=wartezeit (oder <, wenn man 'während Dessen' was tun will).
Wenn in Deinem Beispiel millis() weniger als 1000 vor dem Überlauf steht, ist Deine Startvariable + 1000 eine ganz kleine Zahl (<1000), und millis() mit 4 Milliarden doch etwas größer - diese Abfrage ist somit, obwohl die Wartezeit gar nicht vorbei ist, direkt gültig (oder bei während Dessen nie ... für die nächsten 49,x Tage).

Bei mir kommt dafür sehr oft der name 'lastmillis' zum Einsatz - kann auch in jeder Funktion lokal erstellt werden - mit einem static davor bleibt die Variable erhalten, ist nur in dieser Funktion sichtbar.
Alle anderen Funktionen, Die auch so arbeiten, haben Ihre eigene 'lastmillis'-Version, Alle unabhängig voneinander.
Du musst NUR darauf achten, daß Du lastmillis nicht auch global benutzt (funktioniert auch, aber Du kannst Dir schwer findbare Fehler einbauen).
Wenn NUR lokal, wird das Beschreiben von lastmillis einen Error hervorrufen, wenn Diese nicht zuvor lokal erstellt wurde - wenn's davon eine globale Variante gibt, schreibst Du darin rum - und irgendwo wird dann mit der falschen Zeit gerechnet!

MfG

Hallo,
mir ist da nicht ganz klar was Du eigentlich vorhast. Warum gibst du den Ein und Ausgängen keine vernüfige Namen.

Ich hab das jetzt so verstanden.
Du hast drei Taster für die Vorwahl von Zeiten. Die Anderen Taster sind für die Auswahl der Ausgänge.
Wenn Du einen der Taster zusammen mit einer der Vorwahlen drückst soll der zugehörige Ausgang für die hinterlegte Zeit eingeschaltet werden.

Erstelle ein Programm Ablauf , gerne auch in Textform, damit Du das gliedern kannst und mögliche logische Fehler erkennst. Wann willst Du die Zeit starten, wenn du erkennst das Du gerade zwei Taster gedrückt hast, sicher mit der Flanke dazu ?
Versuch doch erst mal das mit den drei Tastern für die Vorwahlen und einem Taster für eine Ausgang hin zu bekommen. Wenn das klappt kannst Du darüber nachdenken die Taster und Ausgänge durch ein Array zu ersetzen. Wenn Dir das zu komplizier ist such nach einer Lib mit Timer Funktionen. MicroBahner hat Dir ja bereits seine emfohlen.

Heinz

Das mit dem Kommentieren macht extrem Sinn:

void setup() {
  for (int i=1;i<24;i++){  // Zähle die Variable "i" bei 1 beginnend hoch bis 23 
  pinMode(i, OUTPUT);      // setze den IO-PIN mit Nummer "i" auf Ausgang
  }
  for (int i=39;i<49;i++){ // Zähle die Variable "i" bei 39 beginnend hoch bis 48
  pinMode(i, OUTPUT);
  }
  for (int i=25;i<38;i++){ // zähle die Variable "i" bei 25 beginnend hoch bis 37
  pinMode(i, INPUT);
  }
}

Meine Vermutung: Ein newbee mit 15 posts hat keine Ahnung was beim Programmieren mit dem Begriff "Klasse" gemeint ist.

Um das ganze besser zu verstehen frage ich nach:
4 Timer mit 4 Schaltern einstellen. Heißt das 4x4 Schalter oder nur 1 x 4 Schalter?
Sind das einfache Ein/Ausschalter oder haben die Schalter mehrere Schaltstellungen?

Das Grundprinzip eines nicht blockierenden Timers ist wie Nudeln kochen mit regelmäßig auf die Uhr schauen.
Nudeln ins kochende Wasser geben und sich die Uhrzeit (zum Beispiel 20:12) Uhr aufschreiben. Die Kochzeit beträgt 15 Minuten.
Man kann also bis dahin ein paar andere Dinge tun:
die Nudelverpackung in den Müll werfen
ein paar verschmutze Tassen in die Spülmaschine stellen usw.
oder auch am Notebook ein bisschen am Programm weiterschreiben
Du schaust ca alle 2 Minuten mal auf die Uhr ob schon 15 Minuten vergangen sind
Die Uhr zeigt dann an 20:14 Uhr
man berechnet: aktuelleZeit - StartZeit = 2 Das Rechenergebnis liefert 2 die If-Bedingung lautet

if aktuelleZeit - StartZeit > 15 {
TopfVomHerdNehmen
}

Das heißt erst wenn 15 Minuten vergangen sind dann wird er Topf vom Herd genommen.
Die Hauptschleife loop() kommt in jeder Sekunde zigtausendmal an dieser if-bedingung vorbei
aber erst wenn die Bedingung erfüllt ist dann wird ein entsprechender Befehl ausgeführt.

Es ist kein reines abwarten bis die Zeit um ist sondern ein regelmäßig und ganz oft stattfindendes überprüfen ob
eine bestimmte Zeitspanne schon vorbei ist.
Dieses Grundprinzip kann man jetzt auch vier mal anwenden

if aktuelleZeit - StartZeit1 > WarteZeit1 {
MachWas1()
}

if aktuelleZeit - StartZeit2 > WarteZeit2 {
MachWas2()
}

if aktuelleZeit - StartZeit3 > WarteZeit3 {
MachWas3()
}

if aktuelleZeit - StartZeit4 > WarteZeit4 {
MachWas4()
}

Da jetzt alle if-bedingungen eigene Variablen haben können die alle zu unterschiedlichen Zeiten
starten und unterschiedliche lange Wartezeiten haben

Da du vermutlich nicht jeweils nach "WarteZeit" ein/im ausschalten im SInne von blinken möchtest,
Sondern Timer läuft für z.B. 3 Minuten. Dann wird er für 3 Stunden gar nicht benutzt.

Braucht man noch zusätzlich eine boolsche Variable TimerGestartet1 bis TimerGestartet4

if Timer1_gestartet 
  { 
    if aktuelleZeit  - StartZeit1 > WarteZeit1 
    {
      MachWas1()
      Timer1_gestartet = false;
    }  
  }

if Timer2_gestartet 
  { 
    if aktuelleZeit  - StartZeit2 > WarteZeit2 
    {
      MachWas2()
      Timer2_gestartet = false;
    }  
  }

if Timer3_gestartet 
  { 
    if aktuelleZeit  - StartZeit3 > WarteZeit3 
    {
      MachWas3()
      Timer3_gestartet = false;
    }  
  }

if Timer4_gestartet 
  { 
    if aktuelleZeit  - StartZeit4 > WarteZeit4 
    {
      MachWas4();
      Timer4_gestartet = false;
    }  
  }

Wenn die Zeit um ist = die Bedingung if aktuelleZeit - StartZeit4 > WarteZeit4 ist erfüllt
wird Timer_gestartet4 auf false gesetzt

Mit der Aktion mit der ein Timer gestartet wird setzt man

StartZeit1 = millis();
Timer_gestartet1 = true;

So das war jetzt schon relativ ausführlich. Jetzt musst du mal eine Rückmeldung geben ob das so schon verständlich ist
viele Grüße
Stefan

1 Like

Das mit dem Kommentieren macht extrem Sinn:

  for (int i=1;i<24;i++){  // Zähle die Variable "i" bei 1 beginnend hoch bis 23

Das ist ein gutes Beispiel für einen unnötigen Kommentar.
Dokumentiert höchstens, dass dies das erste Mal war, wo der Verfasser eine for-Schleife programmiert hat.
Sinnvoller wäre evtl ein Kommentar, was die Pins 1 .. 23 gemeinsam haben. Oder sonst etwas, das nicht aus der Anweisung selbst ersichtlich ist.