Analog Input Problem

Hallo,

ich habe folgenden Code um Schranken vom Bahnübergang zu heben und zu senken und nebenbei noch eine LED blinken zu lassen:

#include <Servo.h>
const int SERVO_PIN = 9;
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_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 = true;
  SRV_nextWakeUp = millis();
  LED_value = 0;
  LED_moveFoward = true;
  LED_nextWakeUp = millis();
}

void loop() {
  LED_an = false;
  LED_moveFoward = true;
  SRV_moveFoward = false;
  do {
    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) {
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);

      zu = 1;
      richtung = 2;
    }
    if (sensorWertoben < 500 && richtung == 2) {
      zu = 0;
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      richtung = 0;
      delay(1000);
    }



    sensorWertoben = analogRead(eingangoben);

    if (sensorWertoben < 500 && richtung == 0) {
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      zu = 1;
      richtung = 1;
    }
    if (sensorWertbruecke < 400 && richtung == 1) {
      zu = 0;
      richtung = 0;
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
      delay(1000);
    }


    if (zu == 0) {
      LED_an = false;
      SRV_moveFoward = false;
    }
    if (zu == 1) {
      LED_an = true;
      SRV_moveFoward = true;
    }
  } while (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;
}

Folgende Probleme:

  • Es blinkt nur circa jedes 10. Mal weiter während sich die Schranken schließen, sonst hört die LED auf zu blinken.
  • Es dauert bis zu 5 Sekunden ehe die LDR vom Arduino erfasst werden.

Wie kann man das ändern?

Aktuell läuft es auf einem Arduino Mega, soll aber auf einen Attiny 45 geflasht werden.

Vielen Dank,
SachsenBahner

Wie kann man das ändern?

Das Prinzip von BlinkWithoutDelay verstehen lernen.

Delays raus do {} while Schleifen raus.

( Du hast schon eine Schleife, die heisst loop(). Mehr brauchst du nicht )


Ich sehe kein Analog Input Problem. Den Titel kannst du gerne anpassen ;)

Wie kann man das ändern?

Du möchtest gerne einen/mehrere endliche Automaten bauen.

Hallo,

michael_x: Delays raus

die sind dafür da, dass der Bahnübergang erst blinkt bevor die Schranken schließen.

michael_x: do {} while Schleifen raus.

Aber dann setzt ich bei jedem Durchlauf der loop() Schleife meine Servo Variable wieder auf false und dadruch zittert der Servo nur hin und her.

combie: Du möchtest gerne einen/mehrere endliche Automaten bauen.

Kann sein, ich verstehe hier aber gerade den Zusammenhang nicht :D

Gruß SachsenBahner

Ich kann den michael_x nur unterstützen! Weg mit den Delays(), die stehen dir nur im Weg rum. Weg mit den Schleifen. Loop() sollte reichen.

Kann sein, ich verstehe hier aber gerade den Zusammenhang nicht

Mach die Schleifen und Delay weg, dann kommt das schon. Zwangsläufig.

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. ;)

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

;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"

;)

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 :D

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. :D :D 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 ;)