Go Down

Topic: For Schleife geht nicht (Read 1 time) previous topic - next topic

ElEspanol

Programmiertechnisch setzt man keine Pausen, sondern macht eine Ablaufsteuerung. Oder mehrere, die sozusagen dadurch parallel laufen.

Trace841

Programmiertechnisch setzt man keine Pausen, sondern macht eine Ablaufsteuerung. Oder mehrere, die sozusagen dadurch parallel laufen.
Darum hatte ich Pause ja auch in "" gesetzt.

Das Problem ist ja, dass der Taster den Sound auslöst während das Programm weiterläuft und den Lichteffekt auslöst. Das geschieht ja so schnell, dass man nicht merkt, dass es eigentlich 2 Abläufe hintereinander sind.

Nun wollte ich, dass der Tastendruck einen Sound auslöst und der Lichteffekt ebenfalls einen Sound auslöst. Während ich beim Taster einfach nur den Soundbefehl hinzufügen musste, klappt das beim Lichteffekt leider nicht, weil sich das Programm dann selbst aufhängt.

Der Lichteffekt startet, das Programm läuft weiter, startet den Sound, läuft weiter und unterbricht den Sound um den folgenden Lichteffekt auszulösen.

Doc_Arduino

Hallo,

wie schon gesagt, ich sehe in großen Buchstaben eine Schrittkette vor mir. Stichtwort bleibt switch case. Entweder erfolgt der Schritt zum nächsten case mittels Zeitabfrage wie gezeigt. Oder ich könnte mir vorstellen beim Licht/Soundeffekt Ereignis gesteuert. Das heißt dein Licht/Soundeffekt gibt ein "bin fertig" zurück, daraufhin erfolgt dann der Sprung zum nächsten case.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Trace841

Hallo,

wie schon gesagt, ich sehe in großen Buchstaben eine Schrittkette vor mir. Stichtwort bleibt switch case. Entweder erfolgt der Schritt zum nächsten case mittels Zeitabfrage wie gezeigt. Oder ich könnte mir vorstellen beim Licht/Soundeffekt Ereignis gesteuert. Das heißt dein Licht/Soundeffekt gibt ein "bin fertig" zurück, daraufhin erfolgt dann der Sprung zum nächsten case.
Aber es muss doch eine Möglichkeit geben, die von mir gewünsche Funktion zu implementieren, ohne den Code mit einer Schrittkette neuschreiben zu müssen.

Bin auch einer Lösung bereits recht nahe. Der erste Sound wird getriggert, sobald ich den Taster lange drücke (Zeile 102-103). Allerdings muss ich ihn jetzt so lange gedrückt halten, wie im unsigned long turnOnDelay angegeben. Währenddessen spielt der Sound mehrmals ab (so lange wie ich den Taster gedrückt halte). Lasse ich den Taster dann los, startet der Lichteffekt mit zugehörigem Sound (Zeile 107-144). 

Eigentlich sollte das turnOnDelay (Zeile 105) dazu dienen, genug Zeit zu haben bis der Tastersound abgespielt wurde, damit danach der Lichteffekt mit Sound abspielt.

Jetzt ist es so, dass ich den Taster genau diese Zeit lang gedrückt halten und dann loslassen muss, damit das klappt.

Hier ist nochmal der Code:

Code: [Select]
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);


// ===================== Variables =============================================================//
// -------  Declaring Pins ----------------------------------------------//
static byte disruptorPin = 9;
static byte enginePin = 6;
static byte pushButtonPin = 12;
static byte torpPin[] = { 2, 3 };

// -------  User Inputs ------------------------------------------------//
static unsigned long torpUpTime = 1680;
static unsigned long torpFlashTime = 200;
static unsigned long torpDownTime = 500;
static long double torpIdleBrightness = 20;
static long double torpMaxBrightness = 255;
static unsigned long engineFadePeriod = 3000;
static unsigned long disruptorFiringTime = 2400;

// -------  For the Button Pushing -------------------------------------//
unsigned long debounce = 50;
unsigned long holdTime = 1000;

// -------  Bookeeping ------------------------------------------------//
unsigned long currentMillis;
boolean buttonValue = false;
boolean buttonLast = true;
boolean ignoreUp = false;
unsigned long buttonUpTime;
unsigned long buttonDownTime;
unsigned int torpedoPushes = 0;
unsigned int disruptorPushes = 0;
unsigned long torpedoTime;
unsigned long disruptorTime;
unsigned long torpedoMillis;
unsigned long disruptorMillis;
unsigned long disruptorFlashTime;
boolean disruptorState = 0;

unsigned long turnOnDelay = 2500;
// ==================== End Variables ========================================================= //


// ===================== Setup ================================================================ //
void setup(){
  pinMode(disruptorPin,OUTPUT);
  pinMode(enginePin,OUTPUT);
  pinMode(pushButtonPin,INPUT_PULLUP);     // Enables internal pull-up resistor
  pinMode(torpPin[0],OUTPUT);
  pinMode(torpPin[1],OUTPUT);
 
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    while(true);
  }
  myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms
  myDFPlayer.volume(5);  //Set volume value (0~30).
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
 
}


// ===================== End Setup ============================================================ //



// ===================== Main Loop ============================================================ //
void loop() {
 unsigned long currentMillis = millis();         // get current time
 
 // ---------- Push Buttoon Code --------------------------------------------------------//

  buttonValue = digitalRead(pushButtonPin);
 
    // Record Time of Push
  if (buttonValue == false && buttonLast == true && (millis() - buttonUpTime) > debounce){
    buttonDownTime = millis();
    }
 
  // Record Time of Release
  if (buttonValue == true && buttonLast == false && (millis() - buttonDownTime) > debounce){
        buttonUpTime = millis();
        if (ignoreUp == false){
      disruptorTime = millis(); // If released early, fire disruptor!
      disruptorPushes++;
      myDFPlayer.playMp3Folder(2);
      }
      else{
       ignoreUp = false;
      }
   }

  // If push time is longer than threshold, fire torpedo!
  if (buttonValue == false && (millis() - buttonDownTime) > long(holdTime)){
    myDFPlayer.playMp3Folder(5);
   
    if ((millis() - buttonDownTime) >= turnOnDelay) {
             
    buttonDownTime = millis();
    torpedoTime = millis();
    torpedoPushes++;
    ignoreUp = true;
    myDFPlayer.playMp3Folder(1);

     }
   }
 
  // Record the button state for comparison in the next cycle
  buttonLast = buttonValue;   
 // -------------------------------------------------------------------------------------//
 
 
 
 // ---------- Torpedo Firing ----------------------------------------------------------//
 // Ramp Up Red LED, Flash White LED, then a Ramp Down of Red LED
  // Ramp Up

 
  if ((currentMillis-torpedoTime) < torpUpTime && torpedoPushes > 0){
    analogWrite(torpPin[1],torpIdleBrightness+(torpMaxBrightness-torpIdleBrightness)/torpUpTime*(currentMillis-torpedoTime));
    digitalWrite(torpPin[0], LOW);
   
   
  } 
  // Flash
  else if (((currentMillis-torpedoTime) > torpUpTime) && ((currentMillis-torpedoTime) < (torpUpTime+torpFlashTime)) && torpedoPushes > 0){
    analogWrite(torpPin[1], 0);
    digitalWrite(torpPin[0], HIGH);
   
  }
  // Ramp Down
  else if (((currentMillis-torpedoTime) > (torpUpTime+torpFlashTime)) && ((currentMillis-torpedoTime) < (torpUpTime+torpFlashTime+torpDownTime)) && torpedoPushes > 0){
    analogWrite(torpPin[1],torpMaxBrightness+(torpIdleBrightness-torpMaxBrightness)/torpDownTime*((currentMillis-torpedoTime)-(torpUpTime+torpFlashTime)));
    digitalWrite(torpPin[0], LOW);
   
  } 
  // Idle
  else{
    analogWrite(torpPin[1], torpIdleBrightness);
    digitalWrite(torpPin[0], LOW);
   
  }

 
 // ---------- Engine Fading ----------------------------------------------------------- //
  // Slow Up and Down Fade with Shorter Pusations
  int fadeValue = int(127.0+127.0/2.0*(1+(0.75*sin(2*PI*currentMillis/engineFadePeriod)+0.25*cos(14*PI*currentMillis/engineFadePeriod))));
  analogWrite(enginePin,fadeValue);

 
 // ---------- Disruptor Firing -------------------------------------------------------- //
  // Get Random On or Off Time Using getRandom() Function Below
  disruptorFlashTime = fmod(getRandom(), 4000UL) + 60UL;
  if (((currentMillis - disruptorTime) < disruptorFiringTime) && (disruptorPushes > 0)){
    if(currentMillis - disruptorMillis > disruptorFlashTime) {
      disruptorMillis = currentMillis; 
      digitalWrite(disruptorPin, disruptorState = !disruptorState);
      }
   }
   else{
     analogWrite(disruptorPin,5);
 
    }
 // ------------------------------------------------------------------------------------ //


}
// ===================== End Main Loop ======================================================== //




// ===================== Pseduo-Random Generator ============================================== //
// Found This Online. I Take No Credit for It.
unsigned long m_w = 1;
unsigned long m_z = 2;

unsigned long getRandom()
{
    m_z = 36969L * (m_z & 65535L) + (m_z >> 16);
    m_w = 18000L * (m_w & 65535L) + (m_w >> 16);
    return (m_z << 16) + m_w;  /* 32-bit result */
}
// ===================== End Pseduo-Random Generator ========================================== //

Doc_Arduino

Hallo,

ehrlich gesagt blicke ich nicht mehr durch. Ich dachte es ging um den Abschnitt "Torpedo Firing".

Wegen Zeile 102 usw.
Du musst dir merken das die Taste gedrückt wurde, wenn gedrückt wurde und Zeit vorbei, dann nächste Aktion starten. Ob du das mit if machst oder switch case ist am Ende ziemlich egal. Mit switch case sieht man besser das es eine Schrittkette ist die nacheinander bestimmte Aktionen startet und man kann mit lesebaren Namen arbeiten. enum und switch case gibt ein ziemlich gutes Paar ab.

Schaust du dir mein switch case Bsp. an, siehst du das ein "bin gedrückt Merker" hier nicht notwendig ist, weil direkt danach schon der nächste Zustand aktiv ist bzw. der Taster startet die Aktion überhaupt erst. Ich finde das ziemlich einfach und man kann es beliebig ausbauen. Eigentlich ideal für dein Vorhaben.

Wenn erst nach dem kompletten abspielen des Sounds die nächste Aktion starten soll, dann benötigst du wie schon gesagt einen Rückgabewert "bin fertig" oder wenn die Funktion keinen Rückgabewert hat, musste die Abspieldauer vom Sound abwarten.

Mein Tipp.
Mache mit dem Problemteil einen separaten Sketch, schreibe alles in Funktionen, dann kannste das leicht einbinden wenn es funktioniert. Nutze lokale Variablen. Desweiteren kannst du über Strukturen (struct) nachdenken um mehr Übersicht reinzubekommen. Variablen die zusammengehören zusammenfassen. Die ein oder andere globale Variable kannste bestimmt lokal machen. Hilft alles wirtschaften.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Trace841

Ja, um den Abschnitt "Torpedo Firing" ging es ja auch zuerst. Hatte ja dann geschrieben, dass ich erstmal etwas andere ausprobieren wollte, von dem ich dachte, es wäre einfacher.

Mein Problem ist einfach, dass andere Sketche meist anders aufgebaut sind, bestimmte millis Abfragen oder Zustandsänderungen sind anders und könne nicht einfach so übertragen werden.

Bei meinem letzten Code beispielsweise habe ich ein sehr einfachen Teil aus "Button-press with delayed action" genommen und wie du siehst, hat es nicht geklappt. Eizeln für sich, wie du vorgeschlagen hattest, kein Problem.....eingefügt in meinem Sketch...Problem.

Das liegt eben daran, dass bei dem Beispiele einfach nur eine LED blinken lassen. Bei mir hängt aber mehr dran als nur eine LED bzw. passieren beim Tastendruck mehr Dinge, die voneinander abhängig sind, als bei einem einfachen Blinkprogramm.

Es ist für mich äußerst Schwierig nachzuvollziehen, was sich alles ändern muss, bzw. welche Variablen wo zu deklarieren sind, damit der ursprüngliche Sketch normal weiterfunktioniert und der neue Teil diesen nur ergänzt.

Hast du dir meinen letzten Sketch mal angeguckt? Hatte ja geschrieben, dass ich der Lösung recht nahe bin und jetzt nur noch ein Zeitproblem zwischen dem Drücken der Taste, dem Abspielen des ersten Soundeffekts, des Zweiten und des Lichteffekts habe.

Es muss also auch auf diese einfache Art gehen, ohne jetzt die Funktionen durch Switch Case zu ersetzen. Auch ein "bin fertig" Rückgabewert war ja bisher nicht notwendig. Die Sounddatei ist ja auf die Dauer des LED-Effekts abgestimmt.

SwitchCase habe ich mir jetzt einiges durchgelesen und klingt einleuchtend aber dazu müsste ich ja den ganzen Sketch umschreiben, statt nur etwas zu ergänzen.

Bisher ist es ja so, dass nach dem Drücken des Tasters für x-Sekunden sofort der Sound startet und ohne Verzögerung der Lichteffekt. Das funktioniert ja auch prima.

Jetzt wollte ich "nur":  Taster für x-Sekunden gedrückt halten -> erster Sound, nach 2 Sekunden Verzögerung startet der zweite Sound und der Lichteffekt (Zeile 107-144).






Doc_Arduino

Hallo,

ich dachte Anfangs du möchtest programmieren lernen. Ich lese aber immer nur ich möchte Funktionalität x einbauen ohne y zu ändern. Wie soll das gehen? Der Thread ist voller Informationen und Lösungsansätze. Nichts davon interessiert dich. Schade.

Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Trace841

Hallo,

ich dachte Anfangs du möchtest programmieren lernen. Ich lese aber immer nur ich möchte Funktionalität x einbauen ohne y zu ändern. Wie soll das gehen? Der Thread ist voller Informationen und Lösungsansätze. Nichts davon interessiert dich. Schade.


Ich hab doch jetzt bereits einen veränderten Code gezeigt, den ich erstellt habe, nachdem ich mir diverse Vorschläge durchgelesen habe. Wie könnte ich das geschafft haben, wenn mich das alles nicht interessieren würde?

Wenn ich irgendwo Urlaub mache, möchte ich mich ein wenig verständigen können aber nicht gleich die ganze Sprache lernen.

Und ja, richtig, ich möchte y nicht ändern, denn y funktioniert doch einwandfrei. Also warum dort etwas ändern?

Leider bestehen die meisten Lösungsansätze daraus den Code neuzuschreiben oder anders zu gestalten. Auch hier sehe ich nicht den Sinn darin einen Code neuzugestalten, der doch an sich funktioniert. Oder übersehe ich da was?

Nochmal zum Verständnis. Der Anfangscode funktioniert reibungslos. Nur wollte ich diesen erweitern und stoße dabei auf Probleme.

Doc_Arduino

Hallo,

nochmal zum Verständnis. Du hast folgende Situation.

Du hast einen Sketch der "scheinbar" funktioniert. Er funktioniert jedoch noch nicht wie endgültig gewünscht. Demzufolge musst du am Sketch etwas ändern, was nicht nur eine neue Zeile einfügen bedeutet.

Wenn du wüßtest was ich schon alles umbauen mußte, teilweise widerwillig, aber ich mußte. Manchmal kommt man über Umwege wieder zu einfacheren Code, jedoch ist der neue einfachere Code immer noch anders wie der alte Code. Wenn der alte Code das machen würde was man sich wünscht, tja dann müßte man ihn nicht umbauen. Logisch oder?

Bei meiner aktuellen "Lib Codiererei" habe ich das Gefühl das ich ständig nur umbaue. Ich könnte mich auf meiner funktionierenden Version ausruhen. Tue ich aber nicht, weil es hier und da noch Optimierungspotential gibt. Mit Rückschlägen muss man dabei rechnen.

Mehr kann ich dir im Moment nicht sagen.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Serenifly

Und ja, richtig, ich möchte y nicht ändern, denn y funktioniert doch einwandfrei. Also warum dort etwas ändern?

Leider bestehen die meisten Lösungsansätze daraus den Code neuzuschreiben oder anders zu gestalten. Auch hier sehe ich nicht den Sinn darin einen Code neuzugestalten, der doch an sich funktioniert. Oder übersehe ich da was?
Das ist beim Programmieren aber häufig so. Auch im professionellen Bereich. Selbst kleine Änderungen sind dann unter Umständen viel Arbeit. Manche Firmen verbringen Monate damit nur Code neuzuschreiben der schonmal funktioniert hat. Idealerweise schreibt man von Anfang an so das alles leicht änderbar und erweiterbar ist, aber das ist auch leichter gesagt als getan. Und irgendwann später merkt man dann doch vielleicht dass es nicht so gut geht wie gedacht.

ElEspanol

und hier kommt noch dazu, dass der Code nicht von Dir ist, und somit keiner weiss, was sich der Programmierer seinerzeit gedacht hat, es gerade si und nicht anders zu machen.

combie

Ich sehe das ein klein wenig anders!
Stimme aber grundsätzlich zu.


Bei größeren Projekten ist die erste Version sowieso für die Tonne bestimmt.
Sie dient nur als Prototype...
Die zweite Variante ist dann schon meist recht brauchbar.

Oft folgt daraufhin noch ein dritter kompletter Neubau, welcher dann sämtliche "dirty Hacks" eliminiert.

Ich sehe das als den einzigen wahren Weg, das neu gelernte und die beim Bau der Prototypen gemachten Erfahrungen einzuflechten.






Der Pessimist sieht die Wolke vor der Sonne.
Der Optimist sieht die Sonne hinter der Wolke.

Mantra: Die Sonne scheint immer!

Trace841

Vielen Dank für die Erklärungen, mir ist jetzt etwas einleuchtender, warum man bereits funktionierende Bereiche neuschreiben muss.

Der Anfangscode funktioniert nicht nur scheinbar, sondern vollständig und auch zufriedenstellend. Was ich wollte, ist eine (oder 2) Funktionen hinzufügen. Eben statt den Effekt nur einmal ablaufen zu lassen, 3 mal und eine Sounddatei abspielen zu lassen, sobald ein Taster gedrückt wurde.

Vermutlich habe ich mir das einfacher vorgesellt als es tatsächlich ist. Denn beim Einfügen der Sounddateien musste ich tatsächlich nur per Copy/Paste ein paar Zeilen einfügen.

Ich sehe auch die Schwierigkeit darin, dass die Lichteffekte mit vielen Variablenvergleichen an die Tastenbestimmung gekoppelt ist, welche wiederum aus Variablenvergleichen besteht.

Diese ganzen Variablenvergleiche dann in andere Funktionen einzubauen ist für mich bisher geistig nicht machbar. Dafür reichen meine Grundkenntnisse nicht aus.

Beispiele mit swichtcase oder auch andere Beispiele beinhalten oft nur eine einfache Variable, welche dann als switch dient (Potiwert, einfacher Tastendruck usw.) oder mit einfachen Tasten. Das ist auch recht gut zu verstehen. Aber eben nur, so lange es sich um eine Variable handelt. Nicht um Abhängigkeiten. Oder es sind Beispiele, die schon wieder so komplex sind, dass man diese nicht so leicht aufs eigene Projekt ummünzen kann.

Der von mir gewünschte zusätzliche Effekt wäre mit Sicherheit einfacher umzusetzen, wenn der Anfangscode bereits anders geschrieben wäre. Da habt ihr alle natürlich recht.

Trotzdem finde ich es sehr ernüchternd, dass ich mich jetzt doch wesentlich intensiver mit Arduino auseinander setzen muss, wo ich doch "nur" einfach Blink- und Soundeffekte für den Modellbau haben wollte. Aber da muss ich dann jetzt wohl durch.

ElEspanol

Trotzdem finde ich es sehr ernüchternd, dass ich mich jetzt doch wesentlich intensiver mit Arduino auseinander setzen muss, wo ich doch "nur" einfach Blink- und Soundeffekte für den Modellbau haben wollte. Aber da muss ich dann jetzt wohl durch.
Gute Einsicht. Und das wird dir mit jedem Teilerfolg mehr Spaß machen.

Trace841

Gute Einsicht. Und das wird dir mit jedem Teilerfolg mehr Spaß machen.
Gute Einsicht. Und das wird dir mit jedem Teilerfolg mehr Spaß machen.
Stimmt. Denn egal wie klein, der erste Schritt ist immer der schwerste von allen.



Hab aber eben noch mal etwas ausprobiert und habe nun den gewünschen Effekt. Allerdings mit Delay, welches ich natürlich vermeiden möchte.

Aber ich weiß nicht genau, wie ich die millis schreiben muss, um kein Delay nutzen zu müssen,

Millis für den zeitlichen Ablauf einer blinkenden LED zu schreiben kann ich aber da hier eben so viele Variablen sind, die auch alle millis nutzen, komme ich nicht weiter.

Hier nochmal der Teilcode:

Code: [Select]
  if (buttonValue == false && (millis() - buttonDownTime) > long(holdTime)){
    myDFPlayer.playMp3Folder(5);
   
delay (1500);
             
    buttonDownTime = millis();
    torpedoTime = millis();
    torpedoPushes++;
    ignoreUp = true;
    myDFPlayer.playMp3Folder(1);

     }
   
 
 



Dadurch habe ich erreicht, dass beim Drücken des Tasters ein Sound abgespielt wird (MP3(5)), dann 1500millis gewartet wird und dann der Code weiterläuft, so dass der nächste Sound (MP3(1)) sowie der entsprechende Lichteffekt abspielt.

Wie gesagt, funktioniert. Aber ohne Delay, sondern mit millis wäre es ja korrekt. Und wenn schon, dann möchte ich es von Anfang an richtig machen.

Go Up