Analog Input Problem

Ich empfehle dir die Verwendung von BlinkWithoutDelays anstatt der Delays.
Oder sieh dir die Library “Intervall” von combie an, die könnte dir auch helfen.

Aber dann setzt ich bei jedem Durchlauf der loop() Schleife meine Servo Variable wieder auf false

Das liegt an dir.

Mit einem loop Durchlauf der eine Millisekunde (oder viel weniger, oder auch evtl. mal ein bisschen mehr) dauert, und ein paar Zustandsvariablen (dazu sagen dann manche "Endlicher Automat") sieht dein Sketch natürlich ganz anders aus.
Daher mein Tip "BlinkwithoutDelay" verstehen und sich angewöhnen, so zu denken. Dann das Ganze neu aufbauen. Diese Denkweise hat den Vorteil, dass alles mögliche unabhängig und parallel ablaufen kann.
Weil unabhängig, kannst du das Ganze auch leichter erweitern und ändern. Zur Zeit ist dein Problem, dass ein delay zum Blinken den ganzen anderen Rest lahmlegt.

INTERVAL von Combie versteckt diese Denkweise. Der Sketch wird so übersichtlicher, aber wir wolllen ja kein Zauberkunststück bewundern, sondern verstehen wie es geht. :wink:

INTERVALL von Combie versteckt diese Denkweise. Der Sketch wird so übersichtlicher, aber wir wolllen ja kein Zauberkunststück bewundern, sondern verstehen wie es geht. :wink:

;D Das tut jetzt aber auch ein kleines bisschen weh. ;D

Aber natürlich hast du Recht.
Das Prinzip, wie man auf delay() verzichten kann, sollte man einmal verinnerlicht haben.
Und, wie man auf diese Art Nebenläufigkeiten erzeugt.

Dann kann man auch auf die INTERVAL, TaskMacros, oder andere Implementierungen zurückgreifen. Z.B. um den Code übersichtlicher zu gestalten.

Hallo,

erstmal vielen Dank für eure Rückmeldung.

Aber ich glaube wir missverstehen uns etwas :smiley:

Also wenn ich die Delay Weglasse funktioniert ja mein Ablauf mich hoch und runtergehen und gleichzeitigen blinken.

ALLERDINGS ist dieses Blinken mit delay dafür da, dass es erst ein paar mal blinkt bevor die Schranken runtergehen!

Das blinkwithoutdelay hab ich schon soweit verstanden, deswegen prüfe ich ja auch ob die Zeit für den nächsten Servoschritt bzw. LED blinken schon gekommen ist.

PS:
Dashier war einer meiner ersten Versuche, das öffnen und schließen funktioniert ja mit blinken.

#include <Servo.h>
const int SERVO_PIN = 9;
const int BUTTON_PIN = 8;
const int KNOPF = 53;
int RELAIS=0;
const int LED_PIN = 13;
Servo SRV_servo;
int SRV_pos;
boolean SRV_moveFoward;
long SRV_nextWakeUp;
int LED_value;
boolean LED_moveFoward;
long LED_nextWakeUp;

void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
pinMode(KNOPF, INPUT);
SRV_servo.attach(SERVO_PIN);
SRV_pos = 0;
SRV_moveFoward = true;
SRV_nextWakeUp = millis();
LED_value = 0;
LED_moveFoward = true;
LED_nextWakeUp = millis();
}


void loop() {
long currentTime = millis();
long nextWakeUpSRV = SRV_doStep(currentTime);
long nextWakeUpLED = LED_doStep(currentTime);
long nextMinWakeUp = (nextWakeUpSRV < nextWakeUpLED) ? nextWakeUpSRV : nextWakeUpLED;
//delay(nextMinWakeUp – currentTime);
  }

/* ** SERVO ** */

long SRV_doStep(long currentMillis) {
  if(currentMillis>SRV_nextWakeUp) {
    if(SRV_moveFoward) {
      SRV_pos +=1;
      if(SRV_pos>110) {
        SRV_moveFoward = false;
        SRV_pos = 110;
      }
    } 
    else {
       SRV_pos -=1;
       if(SRV_pos<0) {
        SRV_moveFoward = true; 
        SRV_pos = 0;
        
        /* ** Damit die LED ausbleibt ** */
        digitalWrite(13, LOW);
        delay(5000);
       }
    }


    SRV_servo.write(SRV_pos);
    SRV_nextWakeUp = currentMillis + 40;

  }
  return SRV_nextWakeUp;
}






/* ** LED ** */
long LED_doStep(long currentMillis) {
if(currentMillis > LED_nextWakeUp) {
   
if(LED_moveFoward) {
LED_value+=3;
if(LED_value>=700){

digitalWrite(13, HIGH);

LED_moveFoward = false;
}
} else {
LED_value-=3;
if(LED_value<=0) {

digitalWrite(13, LOW);

LED_moveFoward = true;
}
}
LED_nextWakeUp = currentMillis + 1;
}
return LED_nextWakeUp; 
}

So,
also ich hab jetzt nochmal mein do-while und die delay rausgenommen:

#include <Servo.h>
const int SERVO_PIN = 9;
const int LED_PIN = 13;
Servo SRV_servo;
int SRV_pos;
boolean SRV_moveFoward;
long SRV_nextWakeUp;
int LED_value;
boolean LED_an;
boolean LED_moveFoward;
long LED_nextWakeUp;

int eingangbruecke = A7;
int sensorWertbruecke = 0;
int eingangoben = A6;
int sensorWertoben = 0;
int zu = 0;
int richtung = 0;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  // init the compontent’s states
  SRV_servo.attach(SERVO_PIN);
  SRV_pos = 0;
  SRV_moveFoward = false;
  SRV_nextWakeUp = millis();
  LED_value = 0;
  LED_moveFoward = false;
  LED_nextWakeUp = millis();
  LED_an = false;
}

void loop() {

    long currentTime = millis();
    long nextWakeUpSRV = SRV_doStep(currentTime);
    long nextWakeUpLED = LED_doStep(currentTime);
    long nextMinWakeUp = (nextWakeUpSRV < nextWakeUpLED) ? nextWakeUpSRV : nextWakeUpLED;
    //delay(nextMinWakeUp – currentTime);

    sensorWertbruecke = analogRead(eingangbruecke);

    if (sensorWertbruecke < 400 && richtung == 0) {

      zu = 1;
      richtung = 2;
    }
    if (sensorWertoben < 500 && richtung == 2) {
      zu = 0;
      richtung = 0;
      delay(1000);
    }



    sensorWertoben = analogRead(eingangoben);

    if (sensorWertoben < 500 && richtung == 0) {
      zu = 1;
      richtung = 1;
    }
    if (sensorWertbruecke < 400 && richtung == 1) {
      zu = 0;
      richtung = 0;
      delay(1000);
    }


    if (zu == 0) {
      LED_an = false;
      SRV_moveFoward = false;
    }
    if (zu == 1) {
      LED_an = true;
      SRV_moveFoward = true;
    }
}

/* ** LED ** */
long LED_doStep(long currentMillis) {
  if (currentMillis > LED_nextWakeUp) {
    if (LED_moveFoward && LED_an) {
      LED_value += 3;
      if (LED_value >= 700) {
        digitalWrite(13, HIGH);

        LED_moveFoward = false;
      }
    }
    else {
      LED_value -= 3;
      if (LED_value <= 0) {

        digitalWrite(13, LOW);
        LED_moveFoward = true;
      }
    }
    LED_nextWakeUp = currentMillis + 1;
  }
  return LED_nextWakeUp;
}

/* ** SERVO ** */

long SRV_doStep(long currentMillis) {
  if (currentMillis > SRV_nextWakeUp) {
    /* ** Schranken runter , Servo hoch ** */
    if (SRV_moveFoward ) {
      SRV_pos += 1;
      if (SRV_pos > 110) {
        SRV_moveFoward = false;
        SRV_pos = 110;
      }
    }

    /* ** Schranken hoch , Servo runter ** */
    else {
      SRV_pos -= 1;
      if (SRV_pos < 0) {
        SRV_moveFoward = true;
        SRV_pos = 0;

        /* ** Damit die LED ausbleibt ** */
        digitalWrite(13, LOW);
        delay(5000);
      }
    }


    SRV_servo.write(SRV_pos);
    SRV_nextWakeUp = currentMillis + 40;

  }
  return SRV_nextWakeUp;
}

Deswegen dauert es dennoch recht lange eh der LDR einen Schatten erfasst, hier wird meiner MEinung nach zu selten abgetastet. Geht das irgendwie noch schneller abzufragen?

deswegen prüfe ich ja auch ob die Zeit für den nächsten Servoschritt bzw. LED blinken schon gekommen ist.

Du solltest BlinkWithoutDelay noch mal lesen.
Denn sowas wie SRV_nextWakeUp = currentMillis + 40; verbietet sich.

Ich würde dir 3 endliche Automaten vorschlagen:

Eins:
Ein Automat, welcher einfach nur blinkt.

Zwei:
Ein Automat, welcher die Schranke fährt.

Drei:
Ein Automat, welcher deinen Schienensensor(oder was auch immer für Eingaben) auswertet.

Die Kommunikation zwischen den Automaten kann über globale Flags abgehandelt werden. Oder über Benachrichtigungen.

Hallo,
ich habe da aber leider keinen blassen Schimmer wie ich solche endliche Automaten erstelle geschweige denn verbinde.
Meine zwei Sensoren sind Lichtwiderstände.

Gruß
SachsenBahner

       /* ** Damit die LED ausbleibt ** */

digitalWrite(13, LOW);
       delay(5000);

Der Kommentar ist falsch und müsste heissen: "Damit eine ganze Zeit lang überhaupt nichts mehr passieren kann"

:wink:

Selbst wenn das gewollt sein sollte, könnte man es auch anders machen. Aber als BlinkWithoutDelay - Versteher weisst du das ja selbst.


Du solltest BlinkWithoutDelay noch mal lesen.
Denn sowas wie SRV_nextWakeUp = currentMillis + 40; verbietet sich.

Das gibt aber erst nach 49 Tagen ein winziges Problem...


Endliche Automaten sind Zustandsvariable an denen du erkennst, wo du gerade bist. (Beim BlinkWithoutDelay eben die Zeit seit dem letzten an/aus) ansonsten etwa ein Merker, ob die Schranke schon zugefahren wurde oder noch nicht, usw. Der Sinn ist, jedesmal nichts oder fast nichts zu machen.
Dann können alle anderen "Automaten" praktisch gleichzeitig und unabhängig laufen und prüfen, ob sich ein neuer Zustand ergeben hat.

michael_x:
Selbst wenn das gewollt sein sollte, könnte man es auch anders machen. Aber als BlinkWithoutDelay - Versteher weisst du das ja selbst.


Das gibt aber erst nach 49 Tagen ein winziges Problem...


Endliche Automaten sind Zustandsvariable an denen du erkennst, wo du gerade bist. (Beim BlinkWithoutDelay eben die Zeit seit dem letzten an/aus) ansonsten etwa ein Merker, ob die Schranke schon zugefahren wurde oder noch nicht, usw. Der Sinn ist, jedesmal nichts oder fast nichts zu machen.
Dann können alle anderen "Automaten" praktisch gleichzeitig und unabhängig laufen und prüfen, ob sich ein neuer Zustand ergeben hat.

Okay danke für die Erklärung.

michael_x:
Selbst wenn das gewollt sein sollte, könnte man es auch anders machen. Aber als BlinkWithoutDelay - Versteher weisst du das ja selbst.

Das ist absicht, da der Zug (meist um die 50 cm) nach dem Überfahren des Photowiderstands die Schranken öffnen aber auch gleich wieder schließen würde, da das Ende des Zuges lange noch nicht über den LDR weg ist. Somit verhindere ich also, dass die nächsten fünf Sekunden nach dem öffnen der LDR nicht abgefragt wird :smiley:

michael_x:
Das gibt aber erst nach 49 Tagen ein winziges Problem...

Also ich glaube kaum, dass mein Opa 49 Tage am Stück Modellbahn fährt. :smiley: :smiley: Wäre zwar cool, aber macht der Organismus nicht mit xD

Gruß und Danke
SachsenBahner

Ist das Dein erstes Projekt, das du so mehr oder weniger zusammen kopiert hast oder hast du die Beispiele aus der IDE durchgemacht und einigermaßen verstanden?

Hallo,

ich bin schon seit ca. ein einhalb Jahren dabei (beim Arduino, davor eher Raspi). Habe bisher aber nur RGB Controller, eben so LED / Poti / Taster Basics und ein Midi Controller mit Poti und Taster gemacht.

Zusammenkopiert ist es nicht, ich denke schon mit dem Kopf xD

Gruß
SachsenBahner

michael_x:
Das gibt aber erst nach 49 Tagen ein winziges Problem...

Das Problem ist, dass wenn erstmal das falsche Verfahren geübt wird, dann gehts nur schwer wieder aus dem Kopf.

Überläufe, und ihre Abhandlung....
Ein Dauerbrenner.

SachsenBahner:
Zusammenkopiert ist es nicht, ich denke schon mit dem Kopf xD

Ich hätte da was für Deinen Kopf: Anleitung: Endlicher Automat mit millis()

Mit der Fußgängerampel kannst Du probieren. Das blaue Blinklicht funktioniert praktisch vollkommen unabhängig von der Ampel. So könntest Du Schranken bewegen und gleichzeitig Blinken.

Ich fange gerne mit enum an, mache mir damit die Schritte klar. Das wird dann noch ein paar Mal geändert, macht ja nichts.

Ich finde switch/case für endliche Automaten gut, geht aber auch anders. Wie es mit OOP funktioniert, hat RudiDL5 sehr schön gezeigt.

Mein Tipp: Vergiß vorläufig, daß delay() existiert.

Mein Tipp: Vergiß vorläufig, daß delay() existiert.

Ich würde noch einen Schritt weiter gehen!

Die moderne Psychologie kennt einige Verfahren zur Selbstsuggestion. So kann man es einrichten, dass man einen Würgereiz bekommt sobald einem ein delay() unter die Augen kommt.

:o Ja gut, ich habe jetzt etwas übertrieben... :o

SachsenBahner:
ich bin schon seit ca. ein einhalb Jahren dabei (beim Arduino, davor eher Raspi). Habe bisher aber nur RGB Controller, eben so LED / Poti / Taster Basics und ein Midi Controller mit Poti und Taster gemacht.

Wenn man den Kenntnisstand des Fragestellers kennt, kann man gezieltere Tips geben. Weil bei 18 Posts geht man in aller Regel von Newbie aus :wink:

Da mir langweilig war…

Und auch noch ein Beispiel für meine TaskMacros fehlte, habe ich damit mal eine massiv nebenläufige “Schranke” gebaut.

Aus dem Original Programm habe ich nicht alles verstanden.
Mein Programm wird also noch nicht perfekt sein.

Die Sensoren werden jetzt auf meinem Uno ca. 4000 mal pro Sekunde abgefragt.

So kann es dann aussehen:

#include <Servo.h>
#include <TaskMacro.h>

const byte SERVO_PIN      = 9;
const byte LED_PIN        = 13;
const byte eingangbruecke = A1;
const byte eingangoben    = A2;



Servo servo;

// Kommunikationsflags
bool schranke   = true;  // True == auf, False == zu
bool blinken    = false; // True == ein, False == aus
byte durchfahrt = 0;     // gefilterter Sensorwert




void schrankenabhandlung()
{
  static int servopos; // 0 == auf, 110 == zu
  taskBegin();
  
  // initialisierung 
  blinken   = false;
  servopos  = 0;
  servo.write(servopos);
  
  while(1)
  {
    taskWaitFor(!schranke);
    Serial.println("Schranke schliesst"); 
    blinken   = true; // blinken starten
    taskPause(2000);  // autos durchfahren lassen
    for(servopos=0;servopos<110;servopos++)
    {
      servo.write(servopos);
      taskPause(40);
    }
    Serial.println("Schranke unten");
    taskWaitFor(schranke);
    Serial.println("Schranke oeffnet");
    for(servopos=110;servopos>0;servopos--)
    {
      servo.write(servopos);
      taskPause(40);
    }
    blinken = false;  // blinken ende
    Serial.println("Schranke ist offen");
  }
  taskEnd();
}


void steuerung()
{
  static byte sensormaske = 0;
  
  taskBegin();

  // initialisierung
  schranke  = true;

  while(1)
  {
    taskWaitFor(durchfahrt);  // warten bis erster Sensor belegt
    sensormaske = durchfahrt; // sensor merken
    schranke = false; // fahre schranke zu
    taskWaitFor(durchfahrt & ~sensormaske); //warten bis zweiter Sensor belegt
    taskWaitFor(!durchfahrt);  // warten bis kein Sensor mehr belegt
    schranke = true;  // fahre schranke auf
  }
  taskEnd();
}



void sensoreingangoben()
{
  static unsigned long sensorBelegtMerker = 0;
  taskBegin();
  while(1)
  {
    taskWaitFor(400 > analogRead(eingangoben));// Zug fährt in Sensor ein
    durchfahrt |= B010; // Nachricht für Schranke setzen
    sensorBelegtMerker = millis();
    Serial.println("Obensensor belegt"); 

    taskStepName(WarteAufZugEnde);
    taskSwitch(); // den anderen Abläufen Zeit geben
    if(400 > analogRead(eingangoben))
    {
      sensorBelegtMerker = millis();
      taskJumpTo(WarteAufZugEnde);
    }
    if((millis() - sensorBelegtMerker) < 3000) // 3 Sekunden nach letztem Wagon
       taskJumpTo(WarteAufZugEnde);

    durchfahrt &= ~B010; // Zug ist ganz durch Sensor durch
    Serial.println("Obensensor frei");   
  }
  taskEnd();
}

void sensorbruecke()
{
  static unsigned long sensorBelegtMerker = 0;
  taskBegin();
  while(1)
  {
    taskWaitFor(400 > analogRead(eingangbruecke));// Zug fährt in Sensor ein
    durchfahrt |= B001; // Nachricht für Schranke setzen
    sensorBelegtMerker = millis();
    Serial.println("Brueckensensor belegt");

    taskStepName(WarteAufZugEnde);
    taskSwitch(); // den anderen Abläufen Zeit geben
    if(400 > analogRead(eingangbruecke))
    {
      sensorBelegtMerker = millis();
      taskJumpTo(WarteAufZugEnde);
    }
    if((millis() - sensorBelegtMerker) < 3000) // 3 Sekunden nach letztem Wagon
       taskJumpTo(WarteAufZugEnde);

    durchfahrt &= ~B001; // Zug ist ganz durch Sensor durch
    Serial.println("Brueckensensor frei");   
  }
  taskEnd();
}

void blinker() 
{
  static bool leuchtet = false;
  digitalWrite(LED_PIN,leuchtet);
  
  taskBegin();
  while(1)
  {
    taskWaitFor(blinken); // Blinkanforderung prüfen
    leuchtet = true;
    taskPause(200);
    leuchtet = false;
    taskPause(200);
  }
  taskEnd();
}

void showLoops()
{
  static unsigned long loops = 0;
  loops++;
  
  taskBegin();
  for(;;)
  {
    taskPause(1000);
    Serial.print("Loops pro Sekunde: ");
    Serial.println(loops);
    loops = 0;
  }
  taskEnd();
}

void setup()
{
  Serial.begin(9600);
  pinMode(LED_PIN,OUTPUT);
  servo.attach(SERVO_PIN); 
}

void loop()
{
  // Reihenfolge der Aufrufe ist egal
    blinker();
    sensorbruecke();
    sensoreingangoben();
    showLoops();
    steuerung();
    schrankenabhandlung();
}

Verbesserungen:
Die Sensorabfrage kostet am meisten Zeit. Könnte man seltener machen.
Die Sensorabfrage ist duplizierter Code. Das geht auch besser.

combie:
Da mir langweilig war....

Wäre doch schön, Dir wäre häufiger langweilig, wenn da so schöne Sachen bei rauskommen :wink:

Die while(1) sind für mich schwer verdaulich und ich bin sehr gespannt, ob ein Programmierneuling damit leichter zurechtkommt als mit den millis(). Das kann ich echt nicht einschätzen. Eine interessante Alternative ist es auf jeden Fall!

Mal abwarten, was der SachenBahner dazu meint :slight_smile:

agmue:
Die while(1) sind für mich schwer verdaulich

Sieht halt auf den ersten Blick verboten aus, weil man unwillkürlich an EndlosSchleife denkt und an "verboten".
Vielleicht kann man die ja noch "undefinen" und unter einem anderem Namen benutzen. So ein bisschen Kosmetik fürs Volk :wink:

Wäre doch schön, Dir wäre häufiger langweilig, wenn da so schöne Sachen bei rauskommen :wink:

Danke für die Blumen!

Ja, das mit den Endlosschleifen sieht verboten aus.
Ist auch eigentlich das recht exakte Gegenteil meiner Predigten hier im Forum.

Aber anderseits ist es auch übliche Praxis auf Maschinen mit einem OS, welches Multitasking unterstützt. Geradezu unvermeidbar. Zumindest, für mich ist das Bild nicht ungewohnt.

Wie allerdings ein Beginner damit klar kommt, kann ich kaum abschätzen.