Schleife nach definierter Zeit wiederholen

Hallo,

ich würde gerne eine mitzählende Schleife bauen, die erst nach einer bestimmten Zeit wieder von vorne losläuft, ohne delay zu nutzen, oder die Länge der Schleife im Schleifenkopf definiert zu haben.

Bisher sieht es so aus:

for (schleifenzaehler=0;;schleifenzaehler++)              
  {
      schleifenzeit = millis();                                                     // Erfassung der aktuellen Schleifenzeit
  }

if (millis()>schleifenzeit+1000)
  {
    break;
 }

Leider beginnt die Schleife momentan direkt wieder von vorne auch wenn die if-Bedingung (noch) nicht erfüllt wurde.

Der Hintergund ist der, dass ich innerhalb dieser Schleife mehrere sich auf die schleifenzeit beziehende Programmteile integrieren möchte, ohne mich durch das Verwenden von delay() selbst auszubremsen.

Gruß Chris

Probier

while (millis()<schleifenzeit+1000) {}

oder so... :wink:

Hallo,

wenn ich es so mache..

while (millis()<schleifenzeit+1000)    
  {
      schleifenzeit = millis();                      // Erfassung der aktuellen Schleifenzeit
      schleifenzaehler++;
 }

..wird die Schleife doch aber trotzdem viel schneller als einmal pro Sekunde durchlaufen.

Gruß Chris

Ich bin immer noch nicht sicher, was genau Du haben willst.
Hast Du uns mal ein Beispiel?

Würde das helfen?

while (millis()<schleifenzeit+1000) {
  schleifenzeit = millis();
}
schleifenzaehler++;

Ich verstehe es auch nicht

????
Du möchtest etwas im sekundentakt machen solange bis eine bestimmte Zeit bzw zähler abgelaufen ist
????

Ok,

ich werde versuchen es zu präzisieren. Vielleicht besteht meinerseits ja ein grundlegender Denkfehler.

Was ich erreichen möchte:

Ich benötige eine einsekündige Schleife, deren Durchläufe mitgezählt werden und in deren Schleifenkörper sich mehrere Anweisungen befinden können, die sich zeitlich auf die Startzeit der Schleife beziehen.

Z.B.

if(millis()>schleifenzeit+500)                                                 // Automatisches ausschalten der Lampen nach einer bestimmten Zeit vom Schleifenstart an gerechnet
{
digitalWrite(LED_B,LOW);
}

Mein Problem ist nun, dass die o.a. "Varianten" dazu führen, dass die Schleife wesentlich schneller als einmal pro Sekunde durchlaufen wird und der Wert schleifenzeit sehr schnell steigt.

Würde ich einfach z.B. an das Ende der Schleife ein delay(1000) setzen, könnte ich ja keine Buttonabfragen o.ä. mehr realisieren.

Hoffe, man versteht nun mein Problem.

Gruß Chris

so?

void loop(){
  if(millis()>schleifenzeit+1000) 
    {
      mach was im sekundentakt

    schleifenzeit=millies();
    schleifenzähler++;
    }

  mach was so oft wie geht
  buttonabfragen
  usw
}

Ja.

Danke, das ist sehr gut.

Nun hätte aber das Problem, dass sich alles was unter..

mach was so oft wie geht
  buttonabfragen
  usw

..steht, sich mit dem kompletten Restcode loopen würde.

Mein Ziel war es jedoch diese Informationen in eine kompakte Schleife zu packen.

Gruß Chris

Ok, Du willst also mehrere Sachen von der Startzeit abhängig ablaufen lassen, und das Ganze jede Sekunde wiederholen, richtig?

Wie wäre es denn damit:

boolean x1, x2, x3; // Definiere drei Merker, ob ich die jeweilige Operation in der Sekunde schon mal gemacht hab
int lastStart = 1000; // Merker, wann die Schleife das letzte Mal durch lief
void loop() { // Diese Funktion wird staendig wiederholend ausgefuehrt
  int start = millis() % 1000; // Modulo, Restwert einer Ganzzahlteilung, "start" faengt damit jede Sekunde wieder bei "0" an
  if (lastStart>start) { // Wenn der letzte Durchlauf spaeter in der (vorherigen) Sekunde war als wir jetzt sind
    x1=false; // Dann die Merker wieder "scharf schalten", damit die Operationen diese Sekunde laufen koennen
    x2=false;
    x3=false;
  }
  lastStart = start; // Hier merken wir uns den aktuellen Zeitpunkt in dieser Sekunde, damit wir das naechste Mal, wenn die "if"-Abfrage kommt, wissen, ob eine neue Sekunde angefangen hat oder nicht

  if (start>=10 && x1==false) { // Wenn der Anfang der aktuellen Sekunde mindestens 10 Millisekunden her ist und wir diese Operation noch nicht ausgefuehrt haben: Ausfuehren!
    Serial.println(millis()); // Die eigentliche Operation, ist nur ein Beispiel
    x1 = true; // Merken, dass wir diese Operation in dieser Sekunde schon mal gemacht haben
  }
  if (start>=100 && x2==false) {
    Serial.println(millis());
    x2 = true;
  }
  if (start>=500 && x3==false) {
    Serial.println(millis());
    x3 = true;
  }
}

Müsste dann ungefähr das ausspucken:

10
100
500
1010
1100
1500
2010
2100
2500
...

So?

Danke!

Dieser Code ist für mich Anfänger noch zu komplex um ihn direkt zu verstehen.

Werds aber dank meiner Bücher hoffentlich bald verstehen.

Würde mich dann an dieser Stelle wieder melden.

Gruß Chris

Hab noch ein paar mehr Kommentare eingebaut, vielleicht wirds damit klarer...

Klar, mach nur. :slight_smile:

Ok- habs denke ich verstanden, wie es gemeint ist.

Du hast mir eine Art aufgezeigt um z.B. LED-Zustände abhängig von der Startzeit und abhängig davon, ob der LED-Zustand bereits geändert wurde zu schalten.

Hat mich auf jeden Fall weitergebracht, auch wenn ich mein Problem anhand dieses Ansatzes nicht gelöst bekomme.

Ich habe aber mittlerweile eine Vermutung, was mein Problem sein könnte.

Ich muss hierfür leider etwas ausholen.

Gelernt habe ich, dass innerhalb eines Codes nach den Zeilen für die Libraryintegration und der Definition von Variablen das..

void setup(){
}

..und der..

void loop(){
}

..folgen.

Im Setup lege ich Ein- und Ausgänge fest usw.

Nun meine ich, meinen kompletten restlichen Code in void loop(){} legen zu müssen und befürchte aufgrund der Tatsache, dass sich meine "Wunschschleife" nicht innerhalb einer "geschlossenen" Schleife zu realisieren scheint, Probleme bekommen zu können, den restlichen Code getrennt von den bisher in diesem Thread aufgezeigten Möglichkeiten ausführen zu können.

Sorry, ein langer Satz.

Wer ihn verstanden hat (hoffentlich gibt es diesen Personenkreis), kann mir evtl. folgende Frage beantworten:

Ist diese Denkweise richtig, oder gibt es alternative Möglichkeiten um eine Schleife "sauber" vom Rest des Programmcodes zu "isolieren"?

Gruß Chris

Wieder bin ich nicht 100%ig sicher, aber mein Ansatz sollte da eigentlich ztotzdem helfen, da er ja nur dann eine Operation ausführt, wenn die bestimmte Zeit erreicht ist.

Ansonsten saust er die ganze Zeit durch loop(), und Du kannst problemlos ständig sämtliche anderen Anbfragen machen, nach denen Dir ist. :wink:

Hallo,

hab mein Problem jetzt mal aufgemalt. Der komplette Inhalt des Blatts stellt den void loop() dar.

Was ich nicht möchte ist, dass der eingekringelte Teil des Codes im Loop läuft, während die rechteckige Schleife (um die es mir geht) im Loop läuft.

Gruß Chris

Könntest Du uns schildern, was Du ganz am Ende in Händen zu halten hoffst?

Was soll das werden?

wollte gerade auch posten, was joghurt fragt: es ist glaub ich einfacher, wenn du uns sagst was du machen willst und wir sagen dir dann wie man es am besten macht. Ist glaub ich sinnvoller, als wenn du uns sagst wie du glaubst, dass man es machen sollte, ohne dass wir wissen was du erreichen willst.

ehrlich gesagt glaube ich, dass du probleme siehst, die nicht existieren.

Sehr gerne.

Es geht um eine Art Reaktionsspiel mit einer immer kürzer werdenden Hauptschleife.
Während dieser Hauptschleife sollen zufällig Lampen aufleuchten, denen Knöpfe zugeordnet sind.
Der entsprechende Knopf muss dann jeweils gedrückt werden, bevor die Schleife erneut startet.
Schafft man dies nicht, sollen Parameter wie Ergebnisausgabe usw. erfolgen.

Und genau um die Isolation dieser Schleife geht es mir.

Schließlich möchte ich das Ergebnis nicht schon während dem eigentlichen Spiel (also während der Hauptschleife) angezeigt bekommen.

Gruß Chris

edit: hab grad noch mehr probleme mit meinem ansatz entdeckt. muss das mal ausprobieren. ich lass es trotzdem mal stehen, aber... wie gesagt - glaub gerade, dass ich da ein paar denk-fehler drinnen hab,

Also, in pseydocode:

boolean success = true; //haelt fest ob die runde bestanden wurde oder nicht
int interval = 5; // um die geschwindigkeit mit der des spiel schneller wird modifizieren zu koennen
int loopCounter = 0; //zaehlt, wie viele runden schon gespielt wurden
int time = 1000; //legt fest, wie lange die erste runde ist
int start; // variable in der die momentane zeit gespeichert wird

void loop{
if (success) {   //wenn die letzte runde bestanden wurde, wird die schleife ausgefuehrt
     start = millis(); //registriert, wann die runde begonnen wurde
     while (millis - start < time - loopCounter * interval) { //legt fest wie lange die runde dauert - haengt davon ab, wieviele runden es schon gab
          success = false; //am anfang ist die runde noch nicht bestanden
          light random LEDs; //irgend ein code, der halt nur eine bestimmte zeit lang ausgefuehrt wird
          if (correct button pushed){ //wenn der spieler richtig reagiert...
               sucess = true; //... hat er die runde bestanden und die naechste runde kann beginnen
          }
     }
else { // hat er die runde nicht begonnen, zeige das ergaebnis an
     print result
     }
loopcounter++; 
}

sry - ist schrecklich zu lesen - kopiers vielleicht in die arduino ide, damit es besser lesbar ist.

kanns grad nicht testen, da ich noch in der uni bin, aber ich glaub ich kapier jetyt dein problem: habe vage in erinnerung, dass sich while() mit der loop schleife manchmal merkwuerdig benimmt. sprich es koennte sein, dass loopcounter schneller ansteigt als gedacht :-/

muss dass zu hause mal anschaun - bin auch nicht so der profi.

hoffe ich hab dir trotzdem bisschen geholfen.

lg

p.

Ah! XD

Ok.

Bin die Sache somit also scheinbar wirklich falsch angegangen, indem ich glaubte die Hauptschleife "für sich" laufen lassen zu können. Ja, sie läuft so auch für sich, jedoch anders, als ich gedacht hätte, dass es möglich sei.

So passt das dann aber auch.

Danke. Auch Dir nochmal, Yoghurt.. speziell für Deine Geduld!

Gruß Chris

Chris72622:
Danke. Auch Dir nochmal, Yoghurt.. speziell für Deine Geduld!

Kein Problem. :wink:

Wie wäre es denn mit sowas:

// - Einstellungen --------------------------------------
// Anzahl der Knoepfe und Lampen
#define BUTTONCOUNT 3
// Knopf/Lampe - Angeschlossen an Pin
#define BUTTON1 2
#define BUTTON2 3
#define BUTTON3 4
#define LIGHT1  5
#define LIGHT2  6
#define LIGHT3  7
// Initiale Rundendauer in Millisekunden
#define LOOPDURATIONSTART 1000
// Faktor, um den die Runden pro Durchlauf kuerzer werden
#define LOOPFACTOR 0.9

// - Definitionen --------------------------------------
byte buttons[] = {BUTTON1, BUTTON2, BUTTON3};
byte lights[] = {LIGHT1, LIGHT2, LIGHT3};
int loopDuration = LOOPDURATIONSTART; // Rundendauer

// - Initialisierung --------------------------------------
void setup() {
	// Alle Pins fuer Knoepfe und Lampen richtig einstellen
	for (byte t=0; t<BUTTONCOUNT; t++) {
		pinMode(buttons[t], INPUT); // Knoepfe-Pins auf Eingabe stellen
		pinMode(lights[t], OUTPUT); // Licht-Pins auf Ausgabe stellen, sind dann standardmaessig aus
		digitalWrite(lights[t], LOW); // Alle Lampen einschalten, nur so zum Testen... ;)
	}
	delay(3000); // Bissl warten, dann gehts los.
}

// - Hauptroutine --------------------------------------
void loop() {
	for (byte t=0; t<BUTTONCOUNT; t++)
		digitalWrite(lights[t], LOW); // Alle Lampen ausschalten

	delay(loopDuration); // Rundenzeit warten, bevor es los geht, damit man ein Gefuehl fuer die Rundenzeit bekommt, koennte natuerlich auch per random() veraendert werden oder so.

	byte whichOne = random(BUTTONCOUNT); // Sucht sich einen der Knoepfe/Lampen fuer diese Runde zufaellig aus
	digitalWrite(whichOne, HIGH); // Diese Lampe einschalten

	long start = millis();
	while (start+loopDuration > millis()) { // Jetzt hat er die Rundenzeit lange Zeit...
		for (byte t=0; t<BUTTONCOUNT; t++) { // ...auf einen der Knoepfe zu druecken.
			if (digitalRead(buttons[t])==HIGH) {
				if (t == whichOne) { // Ist es der Richtige: Gut, naechste Runde!
					loopDuration *= LOOPFACTOR; // Naechste Runde ist kuerzer!
					return; // loop() abbrechen, wird dann wieder von vorne durchlaufen
				} else {
					break; // Ist es der Falsche: while-Schleife abbrechen, verloren.
				}
			}
		}
	}

	// Verloren! Alle Lampen an, warten, dann alles zurueckstellen und wieder anfangen.
	for (byte t=0; t<BUTTONCOUNT; t++)
		digitalWrite(lights[t], HIGH);
	delay(3000);
	loopDuration = LOOPDURATIONSTART;
}
// - Ende --------------------------------------

Das ist jetzt nur mal schnell im Text-Editor zusammengeschrieben, ich hab hier keine Entwicklunsumgebung zum Testen, daher ohne Gewähr! :blush: