Frage zur Motorsteuerung

Hallo zusammen,

ich beschäftige mich jetzt seit ca. 1 Woche intensiv mit dem Thema Arduino und wie Programmiere ich etwas.
Leider ist mein Arduino Mega noch nicht angekommen aber ich hoffe das sich das noch bis Ende dieser Woche ausgeht.
Jedenfalls hab ich schon fleissig meinen ersten Sketch geschrieben. Habe gerade versucht mich in das Thema "wie führe ich 2 Aktionen gleichzeitig aus" einzuarbeiten.
In meinem Sketch habe ich es mit der Funktion millis() versucht. ich bin mir aber nicht sicher ob das so wie ich das da reingeschrieben habe funktionieren kann.

Ich möchte wenn Taster1 gedrückt wird 2 Motoren (Motor1 und Motor2) gleichzeitig anlaufen lassen. Der eine soll 5sek laufen, der andere 3sek.
Wenn Taster2 gedrückt wird sollen sie wieder laufen aber beide mit nur 3sek Laufzeit.

Kann das so wie ich das geschrieben habe funktionieren?
Ich bin mir unsicher ob ich die millis() Befehle an den richtigen Stellen eingefügt habe und ob das gemeinsam mit dem Taster so funktioniert.
Zumindest der Arduino Programmer gibt keine Fehlermeldung ab.

Vielen Dank für eure Hilfe
MfG Patrick

const int Motor1=2;
const int Motor1RichtungA=22;
const int Motor1RichtungB=23;
const int Motor2=3;
const int Motor2RichtungA=24;
const int Motor2RichtungB=25;
const int Taster1=46;
const int Taster2=47;
int TasterStatus1=0;
int TasterStatus2=0;
long previousMillis1 = 0;              //für den Anfang definieren, dass PreviousMillis1 noch nicht vorhanden ist
long previousMillis2 = 0;

void setup()
{
 pinMode(Motor1,OUTPUT);
 pinMode(Motor2,OUTPUT);
 pinMode(Motor1RichtungA,OUTPUT);
 pinMode(Motor1RichtungB,OUTPUT);
 pinMode(Motor2RichtungA,OUTPUT);
 pinMode(Motor2RichtungB,OUTPUT);
 pinMode(Taster1,INPUT);
 pinMode(Taster2,INPUT);

 digitalWrite(Motor1,LOW);
 digitalWrite(Motor2,LOW);
}



void loop()
{
  TasterStatus1 = digitalRead(Taster1);			//Auslesen ob Taster1 High ist
  if (TasterStatus1 == HIGH) {				//wenn Taster gedrückt ist, dann
  long dauer1 = 5000;					//Motor1 soll 5sek laufen
  unsigned long currentMillis1 = millis();		//Merke aktuelle Zeitdauer = currentMillis1
  if(currentMillis1 - previousMillis1 < dauer1)  	//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 5sek dann Motoren laufen lassen
  digitalWrite(Motor1RichtungA,LOW); 			//Drehrichtung von Motor1	
  digitalWrite(Motor1RichtungB,HIGH);			//Drehrichtung von Motor1
  analogWrite(Motor1,200);  				//Motor laufen lassen mit dem Wert 200 (also nicht volle Drehzahl)

  long dauer2 = 3000;					//Motor2 soll gleichzeitig mit Motor 1 Starten aber nur 3sek laufen
  unsigned long currentMillis2 = millis();		//Merke aktuelle Zeitdauer = currentMillis2
  if(currentMillis2 - previousMillis2 < dauer2)		//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 3sek dann Motoren laufen lassen
  digitalWrite(Motor2RichtungA,LOW); 			//Drehrichtung von Motor2
  digitalWrite(Motor2RichtungB,HIGH);			//Drehrichtung von Motor2
  analogWrite(Motor2,200);  				//Motor laufen lassen mit dem Wert 200 (also nicht volle Drehzahl)
  previousMillis1 = currentMillis1;			//Zeitdauer die vergangen ist seit Motor1 läuft merken
  previousMillis2 = currentMillis2;			//Zeitdauer die vergangen ist seit Motor2 läuft merken
  }
  else {						//Wenn die Zeitdauer vergangen ist den jeweiligen Motor stoppen
  analogWrite(Motor1,LOW);				
  analogWrite(Motor2,LOW);
  }

  
  TasterStatus2 = digitalRead(Taster2);			//Selbes Spiel nochmal allerdings wenn Taster2 gedrückt wird und mit anderen Laufzeiten der Motoren
  if (TasterStatus2 == HIGH) {
  long dauer1 = 3000;
  unsigned long currentMillis1 = millis();
  if(currentMillis1 - previousMillis1 < dauer1)
  digitalWrite(Motor1RichtungA,HIGH); 
  digitalWrite(Motor1RichtungB,LOW);
  analogWrite(Motor1,255);
    
  long dauer2 = 3000;
  unsigned long currentMillis2 = millis();
  if(currentMillis2 - previousMillis2 < dauer2)
  digitalWrite(Motor2RichtungA,HIGH); 
  digitalWrite(Motor2RichtungB,LOW);
  analogWrite(Motor2,255);
  previousMillis1 = currentMillis1;
  previousMillis2 = currentMillis2;  
  }
  else {
  analogWrite(Motor1,LOW);
  analogWrite(Motor2,LOW);
  }

}

Das wird nicht wie erwartet funktionieren, fürchte ich. Zum einen hast du ein paar if-Anweisungen, wo die auszuführenden Codezeilen nicht in geschweiften Klammern stehen. Und wenn ich das auf die Schnelle richtig sehe, musst du für die Abarbeitung die Taste gedrückt halten. Ausweg: Nach dem Tastendruck ein Flag setzen und nach Abarbeitung dieses wieder auf 0 setzen.

musst du für die Abarbeitung die Taste gedrückt halten

das hab ich auch schon befürchtet.

was bedeutet ein Flag setzten? :~

und was ich noch befürchte ist, dass wenn ich Taste1 gedrückt habe und dann während die Motoren noch im Programm1 laufen auch Taste2 drücke, dann werden die Programme gleichzeitig/parallel anlaufen. Es soll aber immer nur ein Programm möglich sein, da diese ja die selben Motoren benutzen. Kann man da irgendwie nach drücken von Taste1 die Taste 2 solange sperren bis das Programm zu Taste1 fertig ist?

MfG Patrick

Hab noch ein paar Klammern gesetzt :cold_sweat:
so besser?

const int Motor1=2;
const int Motor1RichtungA=22;
const int Motor1RichtungB=23;
const int Motor2=3;
const int Motor2RichtungA=24;
const int Motor2RichtungB=25;
const int Taster1=46;
const int Taster2=47;
int TasterStatus1=0;
int TasterStatus2=0;
long previousMillis1 = 0;              //für den Anfang definieren, dass PreviousMillis1 noch nicht vorhanden ist
long previousMillis2 = 0;

void setup()
{
 pinMode(Motor1,OUTPUT);
 pinMode(Motor2,OUTPUT);
 pinMode(Motor1RichtungA,OUTPUT);
 pinMode(Motor1RichtungB,OUTPUT);
 pinMode(Motor2RichtungA,OUTPUT);
 pinMode(Motor2RichtungB,OUTPUT);
 pinMode(Taster1,INPUT);
 pinMode(Taster2,INPUT);

 digitalWrite(Motor1,LOW);
 digitalWrite(Motor2,LOW);
}



void loop()
{
  TasterStatus1 = digitalRead(Taster1);			//Auslesen ob Taster1 High ist
  if (TasterStatus1 == HIGH) {				//wenn Taster gedrückt ist, dann
  long dauer1 = 5000;					//Motor1 soll 5sek laufen
  unsigned long currentMillis1 = millis();		//Merke aktuelle Zeitdauer = currentMillis1
  if(currentMillis1 - previousMillis1 < dauer1){  	//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 5sek dann Motoren laufen lassen
  digitalWrite(Motor1RichtungA,LOW); 			//Drehrichtung von Motor1	
  digitalWrite(Motor1RichtungB,HIGH);			//Drehrichtung von Motor1
  analogWrite(Motor1,200);  				//Motor laufen lassen mit dem Wert 200 (also nicht volle Drehzahl)
  }
  long dauer2 = 3000;					//Motor2 soll gleichzeitig mit Motor 1 Starten aber nur 3sek laufen
  unsigned long currentMillis2 = millis();		//Merke aktuelle Zeitdauer = currentMillis2
  if(currentMillis2 - previousMillis2 < dauer2){	//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 3sek dann Motoren laufen lassen
  digitalWrite(Motor2RichtungA,LOW); 			//Drehrichtung von Motor2
  digitalWrite(Motor2RichtungB,HIGH);			//Drehrichtung von Motor2
  analogWrite(Motor2,200);
  }  							//Motor laufen lassen mit dem Wert 200 (also nicht volle Drehzahl)
  previousMillis1 = currentMillis1;			//Zeitdauer die vergangen ist seit Motor1 läuft merken
  previousMillis2 = currentMillis2;			//Zeitdauer die vergangen ist seit Motor2 läuft merken
  }
  else {						//Wenn die Zeitdauer vergangen ist den jeweiligen Motor stoppen
  analogWrite(Motor1,LOW);				
  analogWrite(Motor2,LOW);
  }

  
  TasterStatus2 = digitalRead(Taster2);			//Selbes Spiel nochmal allerdings wenn Taster2 gedrückt wird und mit anderen Laufzeiten der Motoren
  if (TasterStatus2 == HIGH) {
  long dauer1 = 3000;
  unsigned long currentMillis1 = millis();
  if(currentMillis1 - previousMillis1 < dauer1){
  digitalWrite(Motor1RichtungA,HIGH); 
  digitalWrite(Motor1RichtungB,LOW);
  analogWrite(Motor1,255);
  }
  long dauer2 = 3000;
  unsigned long currentMillis2 = millis();
  if(currentMillis2 - previousMillis2 < dauer2){
  digitalWrite(Motor2RichtungA,HIGH); 
  digitalWrite(Motor2RichtungB,LOW);
  analogWrite(Motor2,255);
  }
  previousMillis1 = currentMillis1;
  previousMillis2 = currentMillis2;  
  }
  else {
  analogWrite(Motor1,LOW);
  analogWrite(Motor2,LOW);
  }

}

Ein Flag setzen bedeutet einfach sich was in einer Variablen merken.

z.B. so:

  TasterStatus1 = digitalRead(Taster1);			//Auslesen ob Taster1 High ist
  if (TasterStatus1 == HIGH && !Aktion2) {		//wenn Taster gedrückt wurde und keine Aktion2 läuft,
    Aktion1 = true;					// dann in Aktion1 merken.
  }
  
  if (Aktion1) {				        //wenn Taster gedrückt wurde, dann
    long dauer1 = 5000;					//Motor1 soll 5sek laufen
    unsigned long currentMillis1 = millis();		//Merke aktuelle Zeitdauer = currentMillis1
    if(currentMillis1 - previousMillis1 < dauer1){  	//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 5sek dann Motoren laufen lassen
      ...  // Motor ansteuern
    }
    Aktion1 = false;
  }

Die Variablen Aktion1 und Aktion2 mußt du im Kopf als boolean deklarieren.
Ich würde auch andere Variablen z.B. dauer1 etc im Kopf deklarieren, und zwar als
"const unsigned long dauer1 = 5000;"
dann hast du alle Zeiten, die du evtl ändern möchtest an einer Stelle und mußt nicht suchen.

:cold_sweat: :cold_sweat: :cold_sweat:

also das wird langsam ein ganz klein wenig kompliziert.
ich hoffe man kann den code jetzt noch nachvollziehen??
das wär jetzt mal mein versuch, nachdem ich mich mal über flag und einen taster als schalter definieren schlau gemacht habe.
Aber je mehr code ich schreibe desto unsicherer werde ich irgendwie.
Was sagt ihr zu meinem ist-Stand?

const int Motor1=2;
const int Motor1RichtungA=22;
const int Motor1RichtungB=23;
const int Motor2=3;
const int Motor2RichtungA=24;
const int Motor2RichtungB=25;
const int Taster1=46;
const int Taster2=47;
int TasterStatus1=0;
int TasterStatus2=0;
long previousMillis1 = 0;		//für den Anfang definieren, dass PreviousMillis1 noch nicht vorhanden ist
long previousMillis2 = 0;
int state = HIGH;			//um den Taster in einen Schalter umzuwandeln
int previous = LOW;
long time=0;
long debounce=200;			//Taster entprellen

void setup()
{
 pinMode(Motor1,OUTPUT);
 pinMode(Motor2,OUTPUT);
 pinMode(Motor1RichtungA,OUTPUT);
 pinMode(Motor1RichtungB,OUTPUT);
 pinMode(Motor2RichtungA,OUTPUT);
 pinMode(Motor2RichtungB,OUTPUT);
 pinMode(Taster1,INPUT);
 pinMode(Taster2,INPUT);

 digitalWrite(Motor1,LOW);
 digitalWrite(Motor2,LOW);
}



void loop()
{
  TasterStatus1 = digitalRead(Taster1);						//Auslesen ob Taster1 High ist
  if (TasterStatus1==HIGH && previous==LOW && millis()-time>debounce) {		//wenn Taster gedrückt ist, dann
    if (state==HIGH){
      long dauer1 = 5000;							//Motor1 soll 5sek laufen
      unsigned long currentMillis1 = millis();					//Merke aktuelle Zeitdauer = currentMillis1
        if(currentMillis1 - previousMillis1 < dauer1){  		//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 5sek dann Motoren laufen lassen
          digitalWrite(Motor1RichtungA,LOW); 				//Drehrichtung von Motor1	
          digitalWrite(Motor1RichtungB,HIGH);				//Drehrichtung von Motor1
          analogWrite(Motor1,200);  					//Motor laufen lassen mit dem Wert 200 (also nicht volle Drehzahl)
          }
      long dauer2 = 3000;						//Motor2 soll gleichzeitig mit Motor 1 Starten aber nur 3sek laufen
      unsigned long currentMillis2 = millis();				//Merke aktuelle Zeitdauer = currentMillis2
        if(currentMillis2 - previousMillis2 < dauer2){			//Wenn Aktuelle Zeitdauer - vergangene Zeitdauer < 3sek dann Motoren laufen lassen
          digitalWrite(Motor2RichtungA,LOW); 				//Drehrichtung von Motor2
          digitalWrite(Motor2RichtungB,HIGH);				//Drehrichtung von Motor2
          analogWrite(Motor2,200);
          }  								//Motor laufen lassen mit dem Wert 200 (also nicht volle Drehzahl)
    previousMillis1 = currentMillis1;					//Zeitdauer die vergangen ist seit Motor1 läuft merken
    previousMillis2 = currentMillis2;					//Zeitdauer die vergangen ist seit Motor2 läuft merken
    }
    else {								//Wenn die Zeitdauer vergangen ist den jeweiligen Motor stoppen
    analogWrite(Motor1,LOW);				
    analogWrite(Motor2,LOW);
    }
  time = millis();
  previous = TasterStatus1;
  }

  
  TasterStatus2 = digitalRead(Taster2);						//Selbes Spiel nochmal allerdings wenn Taster2 gedrückt wird und mit anderen Laufzeiten der Motoren
  if (TasterStatus2==HIGH && previous==LOW && millis()-time>debounce) {
    if (state==HIGH){
      long dauer1 = 3000;
      unsigned long currentMillis1 = millis();
        if(currentMillis1 - previousMillis1 < dauer1){
          digitalWrite(Motor1RichtungA,HIGH); 
          digitalWrite(Motor1RichtungB,LOW);
          analogWrite(Motor1,255);
          }
      long dauer2 = 3000;
      unsigned long currentMillis2 = millis();
        if(currentMillis2 - previousMillis2 < dauer2){
          digitalWrite(Motor2RichtungA,HIGH); 
          digitalWrite(Motor2RichtungB,LOW);
          analogWrite(Motor2,255);
          }
    previousMillis1 = currentMillis1;
    previousMillis2 = currentMillis2;  
    }
    else {
    analogWrite(Motor1,LOW);
    analogWrite(Motor2,LOW);
    }
  time = millis();
  previous = TasterStatus2;
  }
}

du brauchst noch ein paar Semikolons;

int state = HIGH;		//um den Taster in einen Schalter umzuwandeln
...
if (state==HIGH)

versteh ich nicht, wo wird state jemals verändert ?

Debounce wüde ich durch ein kleines delay realisieren, das vereinfacht die Logik sehr.

  1. wenn Taster== HIGH und gerade gestartet.
    2.if ( TasterStatus == LOW && previous==HIGH) { delay(debounce);  previous=LOW; } // 20 msec sollten reichen
    time ( müsste eigentlich unsigned long sein ) brauchst du dann nicht, aber für jeden Taster natürlich ein eigenes "previous".

Was passiert bzw. soll passieren, wenn die Motoren noch laufen und du den einen oder anderen ( oder beide ) Taster betätigst ???
Was passiert bzw. soll passieren, wenn du einen Taster permanent gedrückt hältst ???

    previousMillis1 = currentMillis1;
    previousMillis2 = currentMillis2;

Die sind immer gleich, wofür brauchst du 2 ?
previousMillis bleibt erst stehen, wenn der Taster losgelassen wurde, d.h. erst dann fängt die Zeit an zu zählen ...

Ich würde den Code anders aufteilen.

in jeder Loop zuerst die Taster lesen:

  if (digitalRead(Taster1) && !Aktion2) {		//wenn Taster1 gedrückt wurde und keine Aktion2 läuft,
    Aktion1 = true;					// dann  Aktion1 setzen.
  }
  if (digitalRead(Taster2) && !Aktion1) {		//wenn Taster2 gedrückt wurde und keine Aktion1 läuft,
    Aktion2 = true;					// dann  Aktion2 setzen.
  }

Dann hast du beide Taster abgefragt. Entprellen brauchst du nicht, weil beim ersten erkennen von HIGH wird bereits die Aktion gesetzt, die ausgeführt werden soll. Und mit der verundung "&& !Aktionx" erreichst du, dass ein Tastendruck erst wieder ausgewertet wird, wenn die andere Aktion abgelaufen ist.

Und dann führst du deine Aktionen aus:

  if (Aktion1) {				       
    if(millis() - StartMillis < dauer1){  	       
      ...  // Motor ansteuern
    }else {    
      ...  // Motor abstellen
      Aktion1 = false;  // Wenn Zeit abgelaufen, Aktion1 beenden.
    }
  }

Das gleiche natürlich nochmal mit Aktion2. Ich habe es jetzt stark verkürzt dargestellt, aber das ist besser um erstmal eine Struktur reinzukriegen.

Am besten setzt du dich eh erstmal hin und schreibst dir mit Pseudocode eine Struktur auf.
Eben mit Pseudobefehlen wie "Motoran", "Motoraus", if (Zeitabgelaufen) etc. Du kannst dich dabei durchaus an dem orientieren was du machen müßtest, wenn du das von hand machen solltest.
(Solche Pseudobefehle wie "Motoran" kann man dann später auch gut in Funktionen umwandeln!)

Es ist aber generell schwierig, vor allem als Anfänger, einen Code "trocken" zu schreiben.
Code schreiben ist das eine.
Herausfinden warum er nicht funktioniert (und er wird nicht auf Anhieb funktionieren!) das Andere.

Zum debuggen (also sehen, was der Controller wirklich macht, bietet es sich an über Serial.print() entsprechende Statusmeldungen auf dem Monitor auszugeben.

Also zum Beispiel, um mein oben angegebenes Beispiel zur Tasterabfrage zu kontrollieren:

  if (digitalRead(Taster1) && !Aktion2) {		//wenn Taster1 gedrückt wurde und keine Aktion2 läuft,
    Aktion1 = true;					// dann  Aktion1 setzen.
    Serial.println("  Taster 1 gedrueckt.")
  }
  if (digitalRead(Taster2) && !Aktion1) {		//wenn Taster2 gedrückt wurde und keine Aktion1 läuft,
    Aktion2 = true;					// dann  Aktion2 setzen.
    Serial.println("  Taster 2 gedrueckt.")
  }

:fearful:
also diese ganzen Komentare muss ich mir mal in Ruhe zu Gemüte führen! Das wird ganz schön viel. Ich hoffe da hab ich mich nicht übernommen! 8)

Was passiert bzw. soll passieren, wenn die Motoren noch laufen und du den einen oder anderen ( oder beide ) Taster betätigst ???
Was passiert bzw. soll passieren, wenn du einen Taster permanent gedrückt hältst ??

Wenn ein Taster gedrückt wurde sollen sofort alle anderen Taster deaktiviert werden damit eben nicht 2 Motorenprogramme gleichzeitig laufen können. Aber das Problem hab ich erstmal ignoriert weil sonst kenn ich mich gar nicht mehr aus.
Ich würde mich schon freuen wenn mein Programm erst mal so funktioniert und dann überleg ich wegen dem Taster deaktivieren.

Permanent drücken soll eigentlich nicht vorkommen bzw. soll keine Auswirkung auf das Programm haben. Einmal gedrückt soll das zugehörige Programm ablaufen. Egal ob nochmal gedrückt wird oder permanent oder ... Erst wenn das Programm zu ende ist soll man wieder durch drücken auf einen neuen Taster oder den selben Taster wieder ein Programm starten können.

previousMillis1 = currentMillis1;
previousMillis2 = currentMillis2;
Die sind immer gleich, wofür brauchst du 2 ?

Ich dachte ich brauche Nr1 für den ersten Motor und Nr2 für den zweiten Motor. Aber bei genauerem überlegen wird wohl wirklich einmal ohne die Zahlen genügen. 8)

if (state==HIGH)
versteh ich nicht, wo wird state jemals verändert ?

Stimmt das kann ich anscheinen auch löschen.
Hatte ich aus dem Beispiel "aus einem Taster einen Schalter machen" das ich gefunden habe. Da hatte es aber eine andere Bedeutung und ist für mich gar nicht relevant.

So viele Codezeilen :roll_eyes:

MfG Patrick

ALSO,
wenn der Sketch jetzt stimmt, dann fress ich nen Besen!
Zumindest ist mir jetzt das Schreiben relativ leicht von der Hand gegangen und ich finds super nachvollziehbar. :grin:

const int Motor1=2;
const int Motor1RichtungA=22;
const int Motor1RichtungB=23;
const int Motor2=3;
const int Motor2RichtungA=24;
const int Motor2RichtungB=25;
const int Taster1=46;
const int Taster2=47;
int TasterStatus1=0;
int TasterStatus2=0;
long time=0;

void setup()
{
 pinMode(Motor1,OUTPUT);
 pinMode(Motor2,OUTPUT);
 pinMode(Motor1RichtungA,OUTPUT);
 pinMode(Motor1RichtungB,OUTPUT);
 pinMode(Motor2RichtungA,OUTPUT);
 pinMode(Motor2RichtungB,OUTPUT);
 pinMode(Taster1,INPUT);
 pinMode(Taster2,INPUT);

 digitalWrite(Motor1,LOW);
 digitalWrite(Motor2,LOW);
}


void Motorprogramm1()				//Motor1 soll 5sek laufen, Motor2 soll parallel 3sek laufen
{
  long dauer1 = 5000;
  if(time<dauer1){				//im ersten Durchlauf ist time=0 dann wird time immer nach Durchlauf des Programms auf aktuelle Zeit gesetzt
    						//wenn die Durchlaufzeit kleiner ist als 5sek dann Motor1 weiterlaufen lassen
    digitalWrite(Motor1RichtungA,LOW); 						
    digitalWrite(Motor1RichtungB,HIGH);				
    analogWrite(Motor1,200);
  }  		  
  long dauer2 = 3000;				//selbes Prinzip wie bei Motor1
  if(time<dauer2){
    digitalWrite(Motor2RichtungA,LOW); 					
    digitalWrite(Motor2RichtungB,HIGH);				
    analogWrite(Motor2,200);
  }
  time = millis(); 
}


void Motorprogramm2()				//selbes Prinzip wie Motorprogramm1		
{
  long dauer1 = 3000;
  if(time<dauer1){
    digitalWrite(Motor1RichtungA,LOW); 					
    digitalWrite(Motor1RichtungB,HIGH);				
    analogWrite(Motor1,200);
  }  		  
  long dauer2 = 3000;
  if(time<dauer2){
    digitalWrite(Motor2RichtungA,LOW); 					
    digitalWrite(Motor2RichtungB,HIGH);				
    analogWrite(Motor2,200);
  }
  time = millis(); 
}


void loop()
{
  TasterStatus1 = digitalRead(Taster1);			//Auslesen ob Taster1 High ist
  if (TasterStatus1 && !Motorprogramm2){		//Wenn der Taster High und kein anderes Programm aktiv, dann Programm1 ausführen
  Motorprogramm1;
  }
}

Hab ich das richtig verstanden, dass ich eigentlich bei einer "if" Bedingung gar kein "else" brauche wenn ich als "else" gar nichts machen will? In meinem Fall ist "else" ja Motor aus und dieses Motor aus hab ich oben mit digitalWrite(Motorx,LOW); ja schon definiert!?

So viele Codezeilen :roll_eyes:

Solange du sie noch zwischen [ code ] Tags kriegst, geht's doch :wink:

Damit es übersichtlicher wird, bietet es sich an, Funktionen zu schreiben, die

  1. die loop übersichtlicher halten können
  2. evtl mehrfach mit Parametern aufgerufen werden können, wenn ähnliches mehrfach gemacht werden soll.
    ( Programm1 und 2 unterscheiden sich nur durch die Laufzeiten der 2 Motoren, richtig ? )
  3. sogar in separaten Dateien "versteckt" werden können, wenn das hilft.

Aus Günthers Beispiel könntest du eine Funktion machen

boolean MotorProgramm(boolean active, unsigned int dauer)
{
   // liefert active zurück ( evtl. auf false gesetzt, wenn dauer abgelaufen ist )
   // speichert die Startzeit lokal. Kann daher gleichzeitig nur 1 Mal aktiv sein !!!
   if (active) 
   {
      static unsigned long StartMillis;
      if (StartMillis == 0) StartMillis = millis();  // Start merken

      if(millis() - StartMillis < dauer){  	       
      ...  // Motor ansteuern
      }  else {    
      ...  // Motor abstellen
      active = false; 
      StartMillis = 0;  // für den nächsten Start
      }  
   }
 return active;
}

und sie für jeden Taster verwenden. loop ist dann nur

void loop() {
   static boolean Aktion1;
   static boolean Aktion2;
   if (digitalRead(Taster1) && !Aktion2) {	//wenn Taster1 gedrückt wurde und keine Aktion2 läuft,
      Aktion1 = true;				// dann  Aktion1 setzen.
   }
   if (digitalRead(Taster2) && !Aktion1) {	//wenn Taster2 gedrückt wurde und keine Aktion1 läuft,
     Aktion2 = true;				// dann  Aktion2 setzen.
   }
   Aktion1 = Motorprogramm(Aktion1, 3000); // setzt Aktion1 auf false, wenn fertig 
   Aktion2 = Motorprogramm(Aktion2, 5000); // setzt Aktion2 auf false, wenn fertig
}

Das ist jetzt nur als Beispiel für 1 Motor, und geht davon aus, dass ein Taster nicht das andere Programm unterbricht.
Variable sind bei mir absichtlich nicht global, wenn nicht nötig. static reicht fast immer.

Motorprogramm.ino als separate Datei zu anzulegen, lohnt erstmal nicht, finde ich. Kannst du aber machen, wenns dadurch übersichtlicher wird.

P.S. Dein Programm hat das Problem, dass du immer wieder time= millis(); setzt.
Du willst aber nur die Startzeit, bzw. die Differenz zwischen millis() und der Startzeit.

Wird schon besser!
Sogar schon mit Funktionen! Sehr gut!

Funktionieren würde es noch nicht....

Aber wenn ich ein Programm schreiben muß auch immer wieder testen...

also, was mir auffiel:
"if(time<dauer1)" das funktioniert so nicht.
Du mußt, wie in deinen vorangegangenen Beispielen, die die Startzeit merken (z.B. beim Drücken des Tasters) und dann immer die Differenz zwischen Startzeit und time mit Dauer vergleichen. Also:
"if(time-Startzeit > dauer)"

Und dann kannst du nicht eine Funktion wie eine boolsche Variable behandeln:
" if (TasterStatus1 && !Motorprogramm2)" funktioniert nicht.
Du mußt schon, wie in meinem Beispiel eine eigene Statusvariable (Flag) erzeugen ("boolean Aktion1 = false;") die du bei Tastendruck setzt, und unten, abhängig von der Statusvariablen die Motorfunktion aufrufen. (und nach ablauf wieder rücksetzen).

Nochwas, aber das ist nur Kosmetik:
Deine beiden Funktionen machen ja das gleiche.
Du kannst auch nur eine Funktion deklarieren, der du die Dauern übergibst:

void Motorprogramm(long Dauer1, long Dauer2){

und dann so aufrufen:

Motorprogramm(5000,3000); // Programm1
void Motorprogramm(3000,3000)  // Programm2

Und dann kannst du nicht eine Funktion wie eine boolsche Variable behandeln:
" if (TasterStatus1 && !Motorprogramm2)" funktioniert nicht.

if (TasterStatus1 && !Motorprogramm2() ) könnte aber funktionieren.

Funktionen die nichts zurückliefern und nur Seiteneffekte produzieren, sollten eher die Ausnahme sein,
wenn ich das mal überspitzen darf :wink:

michael_x:

Und dann kannst du nicht eine Funktion wie eine boolsche Variable behandeln:
" if (TasterStatus1 && !Motorprogramm2)" funktioniert nicht.

if (TasterStatus1 && !Motorprogramm2() ) könnte aber funktionieren.

Funktioniert nicht.
Zu einen von der Syntax: nur wenn du die Funktion als boolean deklarierst, akzeptiert das der Compiler, zum anderen funktionell: Die Funktion würde an dieser Stelle ausgeführt werden, was aber nicht gewünscht ist.

Edit: Spannende Sache.
Michael, du hat in deinem Zitat natürlich die Klammern nach der Funktion nachgezogen.
Dann meckert der Compiler. Wenn man die Klammern weglässt, also

 if (TasterStatus1 && !Motorprogramm2)

Dann wird das compiliert!

Testsketch:

void test(){}

void setup(){
  Serial.begin(57600);
  if (test) Serial.println("true");
  else Serial.println("false");  
}
void loop(){}

Das läuft, obwohl "test" als Variable nirgends deklariert ist. :fearful:
(gibt übrigens true zurück.)

@ papla: auch wenn der Compiler nicht meckert: Funktionen müssen immer mit Klammern aufgerufen werden.
also: loop(), millis() und auch Motorprogramm1()

Der Funktionsname ohne Klammern wird eventuell als Adresse der Funktion interpretiert. Diese ist ungleich 0 und damit "true". 100%ig sicher bin ich mir da aber nicht.

Aber so werden Funktionszeiger zugewiesen:

void(*funcPtr)(void);    //Funktionszeiger deklarieren
funcPtr = func;     //Funktion zuweisen. Gleichwertig mit &func
funcPtr();    //Funktion über Zeiger aufrufen. Diesmal mit Klammern

Serial.println(test, HEX) sollte dir die Adresse der Funktion anzeigen

Serenifly:
Der Funktionsname ohne Klammern wird eventuell als Adresse der Funktion interpretiert. Dieser ist ungleich 0 und damit "true". 100%ig sicher bin ich mir da aber nicht.

Danke für die Erläuterung, das macht Sinn.
Es ging aber hier garnicht um einen Funktionspointer, sondern nur um die Frage, warum ein Schreibfehler keinen Compilererror auslöst.

Aber nun: back to Topic

Eben. Es löst wahrscheinlich keinen Fehler aus, weil das Teil der korrekten Syntax ist um Funktionszeiger zu verwenden und der Compiler das nicht unterscheiden kann. Und um das zu erklären muss man kurz mal die drei Zeilen für Funktionszeiger hinschreiben. Da sieht man den Unterschied zwischen "test" und "test()".

Einen wunderschönen Guten Morgen zusammen!
Ein neuer Tag ein neuer Versuch! :blush:

Hab mal versucht die letzten Anmerkungen von euch einzuarbeiten:
Dazu hab ich ein paar Anmerkungen in den Sketch hineingeschrieben.
Ich hoffe ich hab das mit den StartMillis jetzt verstanden!? Aber bei der Berechnung der abgelaufenen Zeit hab ich noch ein Verständnisproblem mit dem > bzw. < Zeichen.
In meiner loop stimmt auch irgendwas nicht, und ich komm irgendwie nicht drauf warum!?!? :0

Vielleicht noch kurz zur Erklärung:
Wenn der Sketch dann so funktioniert wie ich das möchte, dann möchte ich noch diverse Zusammenfassungen machen wie hier bereits vorgeschlagen wurde. So, dass dann Laufzeiten und Drehrichtungen einfacher zu ändern sind.
Zuvor möchte ich noch ca. 7 Motoren mit 10Tastern einfügen die in verschiedensten Kombinationen laufen sollen.
Ich glaube wenn ich jetzt schon zu viel zusammenfasse dann kenn ich mich nachher nicht mehr aus.

MfG Patrick

const int Motor1=2;
const int Motor1RichtungA=22;
const int Motor1RichtungB=23;
const int Motor2=3;
const int Motor2RichtungA=24;
const int Motor2RichtungB=25;
const int Taster1=46;
const int Taster2=47;
int TasterStatus1=0;
int TasterStatus2=0;
long time=0;

void setup()
{
 pinMode(Motor1,OUTPUT);
 pinMode(Motor2,OUTPUT);
 pinMode(Motor1RichtungA,OUTPUT);
 pinMode(Motor1RichtungB,OUTPUT);
 pinMode(Motor2RichtungA,OUTPUT);
 pinMode(Motor2RichtungB,OUTPUT);
 pinMode(Taster1,INPUT);
 pinMode(Taster2,INPUT);

 digitalWrite(Motor1,LOW);
 digitalWrite(Motor2,LOW);
}


void Motorprogramm1()				
{
  long dauer1 = 5000;
  static unsigned long StartMillis = millis();	//Startmillis werden gemerkt und nicht mehr verändert
  if(time-StartMillis<dauer1){			//Ich verwende hier immer ein "kleiner" Zeichen, ihr verwendet immer ein "größer" Zeichen. Das hab ich noch nicht ganz verstanden!
    digitalWrite(Motor1RichtungA,LOW); 						
    digitalWrite(Motor1RichtungB,HIGH);				
    analogWrite(Motor1,200);
  }  		  
  long dauer2 = 3000;				
  if(time-StartMillis<dauer2){			//macht es Sinn hier nochmal zB StartMillis2 für die Laufzeit des zweiten Motors zu deklarieren?
    digitalWrite(Motor2RichtungA,LOW); 					
    digitalWrite(Motor2RichtungB,HIGH);				
    analogWrite(Motor2,200);
  time = millis(); 
  }
  else {
    digitalWrite(Motor1,LOW);
    digitalWrite(Motor2,LOW);
    StartMillis = 0;				//ist dieser Befehl notwendig? beim nächsten Start per Tastendruck werden ja die Startmillis wieer auf den Wert millis() gesetzt!?
  }
}


void Motorprogramm2()				
{
  long dauer1 = 3000;
  static unsigned long StartMillis = millis();
  if(time-StartMillis<dauer1){
    digitalWrite(Motor1RichtungA,LOW); 					
    digitalWrite(Motor1RichtungB,HIGH);				
    analogWrite(Motor1,200);
  }  		  
  long dauer2 = 3000;
  if(time-StartMillis<dauer2){
    digitalWrite(Motor2RichtungA,LOW); 					
    digitalWrite(Motor2RichtungB,HIGH);				
    analogWrite(Motor2,200);
  time = millis();
  } 
  else {
    digitalWrite(Motor1,LOW);
    digitalWrite(Motor2,LOW);
    StartMillis = 0;
  }
}


void loop()
{
  TasterStatus1 = digitalRead(Taster1);			
  if (TasterStatus1 && !Motorprogramm2){		
  Motorprogramm1 = true;			//Hier stimmt was nicht. Ich bekomme die Fehlermeldung assignment of function 'void Motorprogramm1()'
  if (Motorprogramm1) {
  Motorprogramm1;
}

Das solltest du nochmal nachlesen:

Das läuft, obwohl "test" als Variable nirgends deklariert ist. smiley-eek-blue
(gibt übrigens true zurück.)

test ist als Funktionsname definiert, und ist die Adresse der Funktion.

  • immer Motorprogramm1() verwenden.
  • wenn du das Ergebnis von Motorprogramm in einem if verwenden willst, muss Motorprogramm auch einen Wert zurückliefern:
[b]boolean[/b] Test( ) { 
  static boolean t; 
  t = !t;
  [b]return t;[/b]
}

Ich verwende hier immer ein "kleiner" Zeichen, ihr verwendet immer ein "größer" Zeichen. Das hab ich noch nicht ganz verstanden!

Ich seh es nicht:

      if(millis() - StartMillis < dauer){  	       

...  // Motor ansteuern
      }  else {   
      ...  // Motor abstellen
      active = false;


ist dieser Befehl notwendig? beim nächsten Start per Tastendruck werden ja die Startmillis wieer auf den Wert millis() gesetzt!?

Nein!
static Variable behalten den zuletzt gesetzten Wert bis zum Reset.
Motorprogramm wird immer wieder neu aufgerufen, um Start und Ende zu erkennen ( und fast immer gar nichts zu machen)
Irgendwie musst du mitkriegen, dass 1) ein neuer Auftrag da ist und 2) der schon angefangen wurde


macht es Sinn hier nochmal zB StartMillis2 für die Laufzeit des zweiten Motors zu deklarieren?
Wenn sie unterschiedliche Startzeiten haben: ja, also zur Zeit: nein.
StartMillis ist zur Zeit der Start des jeweiligen Programms. Relativ dazu wird bestimmt, wann welcher Motor wieder ausgeschaltet wird und wann das ganze Programm fertig ist.


Zuvor möchte ich noch ca. 7 Motoren mit 10Tastern einfügen die in verschiedensten Kombinationen laufen sollen.

Erstmal eins, dann helfen wir noch gerne bei "aus 1 mach 2", aber dann ist deine Fleissarbeit angesagt ...

Hm, also für mich sind meine Sketches immer logisch! :grin:
Ich glaub ich brauch gar keinen passenden Sketch sondern einen Computer der so denkt wie ich! 8)

Quote
Ich verwende hier immer ein "kleiner" Zeichen, ihr verwendet immer ein "größer" Zeichen. Das hab ich noch nicht ganz verstanden!
Ich seh es nicht:

Da hab ich wohl vor lauter Bäumen, ähm Zeichen was verwechselt.

Quote
Zuvor möchte ich noch ca. 7 Motoren mit 10Tastern einfügen die in verschiedensten Kombinationen laufen sollen.
Erstmal eins, dann helfen wir noch gerne bei "aus 1 mach 2", aber dann ist deine Fleissarbeit angesagt ...

War nicht so gemeint. Sondern wie du sagst, dass ich das Programm erstmal im kleinen zum laufen bringen will und dann ausbauen.
Hab ich nur angemerkt, weil schon der Vorschlag kam, weil alle Motoren das gleiche machen bis auf die Laufzeit, viel mehr zusammenzufassen.
Wollt nur sagen, dass sich das noch ändert. :blush:

Hab unter "else" definiert, wenn das Motorprogramm nicht ausgeführt wird, dann ist es "false" bzw. "0"
und im loop, dass bei Tastendruck überprüft wird ob ein anderes Programm läuft, wenn nicht dann ist Motorprogramm1 "true" bzw "1" und wird ausgeführt.

Oder sagen wir so: Ich GLAUBE, dass ich das definiert habe. :.

Mit meinem Befehl StartMillis = 0; bin ich mir noch ein klein wenig unsicher!

MfG Patrick

const int Motor1=2;
const int Motor1RichtungA=22;
const int Motor1RichtungB=23;
const int Motor2=3;
const int Motor2RichtungA=24;
const int Motor2RichtungB=25;
const int Taster1=46;
const int Taster2=47;
int TasterStatus1=0;
int TasterStatus2=0;
long time=0;

void setup()
{
 pinMode(Motor1,OUTPUT);
 pinMode(Motor2,OUTPUT);
 pinMode(Motor1RichtungA,OUTPUT);
 pinMode(Motor1RichtungB,OUTPUT);
 pinMode(Motor2RichtungA,OUTPUT);
 pinMode(Motor2RichtungB,OUTPUT);
 pinMode(Taster1,INPUT);
 pinMode(Taster2,INPUT);

 digitalWrite(Motor1,LOW);
 digitalWrite(Motor2,LOW);
}


void Motorprogramm1()				
{
  long dauer1 = 5000;
  static unsigned long StartMillis = millis();	//Startmillis werden gemerkt und nicht mehr verändert
  if(time-StartMillis<dauer1){			
    digitalWrite(Motor1RichtungA,LOW); 						
    digitalWrite(Motor1RichtungB,HIGH);				
    analogWrite(Motor1,200);
  }  		  
  long dauer2 = 3000;				
  if(time-StartMillis<dauer2){			
    digitalWrite(Motor2RichtungA,LOW); 					
    digitalWrite(Motor2RichtungB,HIGH);				
    analogWrite(Motor2,200);
  time = millis(); 
  }
  else {
    digitalWrite(Motor1,LOW);
    digitalWrite(Motor2,LOW);
    static boolean Motorprogramm1;
    Motorprogramm1 = false;			//Hier wird definiert wenn das Programm nicht ausgeführt wird, dann ist es "0" bzw. "false"		
    StartMillis = 0;				//Werden hiermit die StartMillis für den nächsten Programmaufruf wirklich auf 0 gesetzt obwohl oben "static" steht?
  }
}


void Motorprogramm2()				
{
  long dauer1 = 3000;
  static unsigned long StartMillis = millis();
  if(time-StartMillis<dauer1){
    digitalWrite(Motor1RichtungA,LOW); 					
    digitalWrite(Motor1RichtungB,HIGH);				
    analogWrite(Motor1,200);
  }  		  
  long dauer2 = 3000;
  if(time-StartMillis<dauer2){
    digitalWrite(Motor2RichtungA,LOW); 					
    digitalWrite(Motor2RichtungB,HIGH);				
    analogWrite(Motor2,200);
  time = millis();
  } 
  else {
    digitalWrite(Motor1,LOW);
    digitalWrite(Motor2,LOW);
    static boolean Motorprogramm2;
    Motorprogramm2 = false;
    StartMillis = 0;
  }
}


void loop()
{
  static boolean Motorprogramm1;
  static boolean Motorprogramm2;
  TasterStatus1 = digitalRead(Taster1);		//Taster auslesen		
  if (TasterStatus1 && !Motorprogramm2){	//Wenn Taster "HIGH" und Motorprogramm2 läuft nicht dann	
  Motorprogramm1 = true;			//ist Motorprogramm1 richtig und darf ausgeführt werden
  }
}