Seriell Daten empfangen und eine Led nach einer bestimmten Zeit ausschalten

Hallo,

ich habe folgendes Problem. Ein Arduino sendet seriell Positionen an einen Nano. Dieser soll einen Stepper an diese Position verfahren und eine Led für 2s leuchten lassen. Wird innerhalb dieser 2s eine neue Position empfangen soll diese angefahren werden und die 2s “von neu” gestartet werden.

Ich habe bisher folgenden Sketch:

#include <CheapStepper.h>
#include <SoftwareSerial.h>
#define ledPin1 3
#define ledPin2 4


CheapStepper LichtStepper(8,9,10,11);
SoftwareSerial nanoSerial (6,7);    // Rx, Tx verkehrtherum am UNO anschließen (Rx auf Tx und Tx auf Rx)

int aktPosition=0;
unsigned long previousMillis = 0;
const long interval = 1000;

void setup() {
  
  Serial.begin(9600);
  LichtStepper.setRpm(7);
  
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  

//############### ENDSCHALTER ANFAHREN LICHTSTEPPER #################  

  for (int i=0; i<360; i++) //Lidar an Anschlag verfahren LichtStepper
  {
      int end_one=5;
      pinMode(end_one, INPUT_PULLUP);
      if(digitalRead(end_one)==HIGH) {LichtStepper.moveDegreesCCW (1);}
      else {break;}    
  }

  LichtStepper.moveDegreesCW(23); //20 Grad nach vorne verfahren und Mitte = 0 Punkt
  LichtStepper.setRpm(15);
  nanoSerial.begin(9600);
}

//################### LOOP ###########################

void loop() {

  while (nanoSerial.available() <= 0);
   
      byte incomingByte= nanoSerial.read();
      Serial.print("Empfangen:  ");
      Serial.println(incomingByte, DEC);

   if (incomingByte==231)
   {
      for(int i=0; i<10; i++)
      {
        digitalWrite(ledPin1,HIGH);
        digitalWrite(ledPin2, HIGH); 
        delay(20);
        digitalWrite(ledPin1,LOW);
        digitalWrite(ledPin2, LOW);
        delay(20);
      }
   }

   else
   { 
      if ((incomingByte-aktPosition)>0)
      { 
          digitalWrite(ledPin1,HIGH);
          digitalWrite(ledPin2, HIGH);
          LichtStepper.moveDegreesCW (incomingByte-aktPosition);
          aktPosition= incomingByte;
          previousMillis=millis();
          //delay(200);
      }

      else if ((incomingByte-aktPosition) == 0)
      {
          digitalWrite(ledPin1,HIGH);
          digitalWrite(ledPin2, HIGH);
          previousMillis=millis();
         //delay(200);
      }

      else
      {
          digitalWrite(ledPin1,HIGH);
          digitalWrite(ledPin2, HIGH);
          LichtStepper.moveDegreesCCW (abs(incomingByte-aktPosition));
          aktPosition= incomingByte;
          previousMillis=millis();
          //delay(200);
      }

    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW); 

    unsigned long currentMillis = millis();
   
    if (currentMillis - previousMillis >= interval)
      {
        digitalWrite(ledPin1,LOW);
        digitalWrite(ledPin2, LOW);
      }
    
    Serial.print(currentMillis);
    Serial.print("  ---   ");
    Serial.println(previousMillis);
    
   }
}

Der Fehler liegt hierbei ja bei der While-Schleife/Bedingung. Der Arduino wartet dort so lange bis diese Bedingung Wahr wird und erst dann wird der Rest durchlaufen.

Wie kann ich es abändern, dass keine Daten verloren gehen, die Seriell gesendet werden und gleichzeit nach 2s die Leds wieder ausgeschaltet werden? Dabei ist es nicht schlimm, wenn die Leds mal nach 1,9 oder 2,1s ausgehen.

Ich habe es schon mit

if (nanoSerial.available() <= 0);

probiert allerdings werden dann keine Daten Empfangen. Ich nehme an das liegt daran, wenn Daten gesendet werden das Programm sich nicht gerade bei der If-Bedingung befindet?

Danke für Eure Hilfe!

Gruß

Du darfst nirgends warten. Das hast auch völlig unnötig. Du hast in loop() schon eine Schleife. Da kann man ständig die Schnittstelle abfragen. Und wenn nichts da ist macht man einfach nichts und loop() läuft durch

Kontrolliere die verstrichene Zeit mit millis().
Speichere die Startzeit und kontrolliere ob die Startzeit plus intervall vorbei ist um die LED abzuschalten.
Kommt ein neues Ereignis vor den 2 Sekunden Speicherst Du die Startzeit einfach neu ab.

Grüße Uwe

uwefed:
Kontrolliere die verstrichene Zeit mit millis().
Speichere die Startzeit und kontrolliere ob die Startzeit plus intervall vorbei ist um die LED abzuschalten.
Kommt ein neues Ereignis vor den 2 Sekunden Speicherst Du die Startzeit einfach neu ab.

So ist auch meine Idee gewesen, sobald eine neue Position empfangen werde setzte ich die “previousMillis” auf die verstrichene Zeit zu diesem Zeitpunkt und dann kontrolliere ich wann millis()-previousMillis größer als der Intervall ist.

Das Problem liegt bei dem “while (nanoSerial.available() <= 0);”. Hier wartet er bis dies Wahr ist oder?
Und so wird millis()-previousMillis immer nur dann überprüft, wenn ein neuer Wert empfangen wurde.

Ich gebe mir am Ende ja beide Werte zur Kontrolle aus:

Serial.print(currentMillis);
    Serial.print("  ---   ");
    Serial.println(previousMillis);

Hier haben previousMillis und currentMillis den gleichen Wert, da dieser Teil des Programms nur dann durchlaufen wird, wenn ein etwas Seriell empfangen wurde.

Ja, die Zeile ist ja auch Unsinn. Warum willst Du warten, wenn nichts kommt? Das blockiert Deinen Sketch.
Nimm doch lieber

if (Serial.available() {
  // mach was
}

Gruß Tommy

Manchmal steht man echt auf dem Schlauch…

Habe das jetzt so gelöst, indem ich die Überprüfung einfach in die while Schleife eingefügt habe. Da das Programm eh nicht oft Daten empfängt und sich meistens in der while-loop befindet macht es auch Sinn es dort rein zu schreiben.

Vielen Dank für Eure Hilfe! :slight_smile:

Hier das komplette Programm falls es jmd intressiert:

#include <CheapStepper.h>
#include <SoftwareSerial.h>
#define ledPin1 3
#define ledPin2 4


CheapStepper LichtStepper(8,9,10,11);
SoftwareSerial nanoSerial (6,7);    // Rx, Tx verkehrtherum am UNO anschließen (Rx auf Tx und Tx auf Rx)

int aktPosition=0;
unsigned long previousMillis = 0, currentMillis=0;
const long interval = 2000;
boolean stat=true;

void setup() {
  
  Serial.begin(9600);
  LichtStepper.setRpm(7);
  
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  

//############### ENDSCHALTER ANFAHREN LICHTSTEPPER #################  

  for (int i=0; i<360; i++) //Lidar an Anschlag verfahren LichtStepper
  {
      int end_one=5;
      pinMode(end_one, INPUT_PULLUP);
      if(digitalRead(end_one)==HIGH) {LichtStepper.moveDegreesCCW (1);}
      else {break;}    
  }

  LichtStepper.moveDegreesCW(23); //20 Grad nach vorne verfahren und Mitte = 0 Punkt
  LichtStepper.setRpm(15);
  nanoSerial.begin(9600);
}

//################### LOOP ###########################

void loop() {

  while (nanoSerial.available() <= 0)
  {
    currentMillis = millis();
   
    if (currentMillis - previousMillis >= interval)
      {
        if (stat==false)
        {
            digitalWrite(ledPin1,LOW);
            digitalWrite(ledPin2, LOW);
            stat=true;
        }
      }
  }
    
      byte incomingByte= nanoSerial.read();
      Serial.print("Empfangen:  ");
      Serial.println(incomingByte, DEC);

   if (incomingByte==231)
   {
      for(int i=0; i<10; i++)
      {
        digitalWrite(ledPin1,HIGH);
        digitalWrite(ledPin2, HIGH); 
        delay(20);
        digitalWrite(ledPin1,LOW);
        digitalWrite(ledPin2, LOW);
        delay(20);
      }
   }

   else
   { 
      if ((incomingByte-aktPosition)>0)
      { 
          digitalWrite(ledPin1,HIGH);
          digitalWrite(ledPin2, HIGH);
          LichtStepper.moveDegreesCW (incomingByte-aktPosition);
          aktPosition= incomingByte;
          previousMillis=millis();
          stat=false;
      }

      else if ((incomingByte-aktPosition) == 0)
      {
          digitalWrite(ledPin1,HIGH);
          digitalWrite(ledPin2, HIGH);
          previousMillis=millis();
          stat=false;
      }

      else
      {
          digitalWrite(ledPin1,HIGH);
          digitalWrite(ledPin2, HIGH);
          LichtStepper.moveDegreesCCW (abs(incomingByte-aktPosition));
          aktPosition= incomingByte;
          previousMillis=millis();
          stat=false;
      }

    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);    
   }
}

Du brauchst keine while-Schleifen! Das ist ein grundlegend falscher Ansatz. loop() ist deine Schleife

Das mag so jetzt gehen weil do sonst nichts anderes macht. Aber in vielen Programmen will man mehrere Dinge quasi-gleichzeitig erledigen.