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.
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.
void loop(){
if(millis()>schleifenzeit+1000)
{
mach was im sekundentakt
schleifenzeit=millies();
schleifenzähler++;
}
mach was so oft wie geht
buttonabfragen
usw
}
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;
}
}
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"?
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.
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.
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.
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.
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!
Chris72622:
Danke. Auch Dir nochmal, Yoghurt.. speziell für Deine Geduld!
Kein Problem.
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!