Drehscheibe Modellbahn mit RF24

Woran liegt das, das die While Schleife ausgefhrt wird, obwohl der Hal gar nicht betätigt wird?

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int messungPin1 = HIGH;
int messungPin1Alt = HIGH;
byte encoderWert = 0; // -1 ( eins weniger als 0 ) == 255
const byte hal = 3;
const byte encoderPinA = 10;            // Phase A vom Drehencoder
const byte encoderPinB = 11;             // Phase B vom Drehencoder
const byte tasterEnter = 12;                   // Pin an dem der Encoder Taster angeschlossen ist
int wertSpeichern = 0;                  // gespeicherter Encoderwert
int encoderGedrueckt = 0;              // Statusspeicher ob Encodertaster betätigt wurde
int encoderTaster = HIGH;             // Taster im Encoder
int gleisAlt = 0;                     // Scheibe Position alt
int gleisNeu = 0;                     // Position welche die Scheibe anfahren soll
bool enter = false;                   // Bestätigung das der Encoder gedrückt wurde
int schritte = 0;                     // Schritte die deer Motor (Hallsensor betätigt) zurücklegen muss
unsigned long encoderDruckzeit;       // Zeit wann der Encodertaster betätigt wurde
unsigned long entprellZeit = 200;     // Zeit die nach der betätigung eines Tasters gewartet wird

void setup() {
  pinMode(encoderPinA, INPUT);
  pinMode(encoderPinB, INPUT);
  pinMode(tasterEnter, INPUT);
  pinMode(hal, INPUT);
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Encoder");
  lcd.setCursor(0, 1);
  lcd.print("Test");
  delay (2000);
  lcd.clear();
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Wert");
  lcd.setCursor(0, 1);
  lcd.print(encoderWert);
}

void loop() {
  messungPin1 = digitalRead(encoderPinA);
  if ((messungPin1 == LOW) && (messungPin1Alt == HIGH)) {
    if (digitalRead(encoderPinB) == HIGH) {
      if (encoderWert < 24) encoderWert++ ;
    } else {
      if (encoderWert > 1) encoderWert-- ;
    }
    lcd.begin(16, 2);
    lcd.setCursor(0, 0);
    lcd.print("Wert");
    lcd.setCursor(0, 1);
    lcd.print(encoderWert);
  }
  {  //<-- WTF macht diese Klammer???
    encoderTaster = digitalRead(tasterEnter);
    if (encoderTaster == LOW)
    {
      encoderDruckzeit = millis();
      encoderGedrueckt = 1;
    }
    if ((millis() - encoderDruckzeit > entprellZeit) && encoderGedrueckt == 1) {
      wertSpeichern = encoderWert;
      Serial.println(wertSpeichern);
      encoderGedrueckt = 0;
      enter = true;
    }
    if (enter == true) {
      gleisNeu = wertSpeichern;
      schritte = gleisNeu - gleisAlt;
      Serial.print ("benoetigte Schritte  ");
      Serial.println(schritte);
      Serial.println(gleisNeu);
      Serial.println(gleisAlt);
      Serial.println(enter);
    }
    if ((gleisNeu != gleisAlt) && (enter == true)) {
      while (schritte != 0) {
        if (digitalRead (hal) == LOW); {
          schritte--;
          Serial.println("Schritte");
          Serial.println(schritte);
          delay(2000); //ein Hall-Sensor prellt nicht und hier machst Du ganze 2 Sekunden NICHTS - mir ist bewusst, was Du hier willst
          enter = false;
          gleisAlt = wertSpeichern;
        }
      }
    }
  } // hier WTF-Klammer Nummer 2
  messungPin1Alt = messungPin1;
}  //DAS war Mal Zeile 128, jetzt 91 8-)

MfG

PS: Ggf., weil schritte ungleich Null ist?
PS²: Ggf. hilft Die hier die serielle Ausgabe weiter - wenn hier die benötigten Schritte <0 sind, hast Du bei Deiner Abfrage ein neues Problem
PPS: STRG+T und entfernen von unnötigen Leerzeilen ... ich wiederhole mich

Hi,

siehe #19 , #21

du darfst das was wir schreiben nicht nur lesen, sondern auch verstehen :wink:

Hab es gerade gemacht. Strg + T kannte ich noch nicht.
Aber ich frage doch in der While Schleife den Hal ab? Steh irgendwie auf dem Schlauch

Ich hoffe so ist es besser:-)

Was für ein Problem meinst du. Wenn die Schritte 0 sind kann ich die nächste Position wählen und es werden die von der jetzigen Position bis zur neuen Position benötigten Schritte berechnet und ausgeführt.

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


int messungPin1 = HIGH;
int messungPin1Alt = HIGH;
byte encoderWert = 0; // -1 ( eins weniger als 0 ) == 255
const byte hal = 3;
const byte encoderPinA = 10;            // Phase A vom Drehencoder
const byte encoderPinB = 11;             // Phase B vom Drehencoder
const byte tasterEnter = 12;                   // Pin an dem der Encoder Taster angeschlossen ist
int wertSpeichern = 0;                  // gespeicherter Encoderwert
int encoderGedrueckt = 0;              // Statusspeicher ob Encodertaster betätigt wurde
int encoderTaster = HIGH;             // Taster im Encoder
int gleisAlt = 0;                     // Scheibe Position alt
int gleisNeu = 0;                     // Position welche die Scheibe anfahren soll
bool enter = false;                   // Bestätigung das der Encoder gedrückt wurde
int schritte = 0;                     // Schritte die deer Motor (Hallsensor betätigt) zurücklegen muss

unsigned long encoderDruckzeit;       // Zeit wann der Encodertaster betätigt wurde
unsigned long entprellZeit = 200;     // Zeit die nach der betätigung eines Tasters gewartet wird


void setup() {
  pinMode(encoderPinA, INPUT);
  pinMode(encoderPinB, INPUT);
  pinMode(tasterEnter, INPUT);
  pinMode(hal, INPUT);
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Encoder");
  lcd.setCursor(0, 1);
  lcd.print("Test");
  delay (2000);
  lcd.clear();
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Wert");
  lcd.setCursor(0, 1);
  lcd.print(encoderWert);
}

void loop() {
  messungPin1 = digitalRead(encoderPinA);
  if ((messungPin1 == LOW) && (messungPin1Alt == HIGH)) {
    if (digitalRead(encoderPinB) == HIGH) {
      if (encoderWert < 24) encoderWert++ ;
    } else {
      if (encoderWert > 1) encoderWert-- ;
    }
    lcd.begin(16, 2);
    lcd.setCursor(0, 0);
    lcd.print("Wert");
    lcd.setCursor(0, 1);
    lcd.print(encoderWert);
  }
     encoderTaster = digitalRead(tasterEnter);
    if (encoderTaster == LOW)
    {
      encoderDruckzeit = millis();
      encoderGedrueckt = 1;
    }
    if ((millis() - encoderDruckzeit > entprellZeit) && encoderGedrueckt == 1) {
      wertSpeichern = encoderWert;
      Serial.println(wertSpeichern);
      encoderGedrueckt = 0;
      enter = true;
    }
    if (enter == true) {
      gleisNeu = wertSpeichern;
      schritte = gleisNeu - gleisAlt;
      Serial.print ("benoetigte Schritte  ");
      Serial.println(schritte);
      //gleisAlt = wertSpeichern;
      Serial.println(gleisNeu);
      Serial.println(gleisAlt);
      Serial.println(enter);
    }
    if ((gleisNeu != gleisAlt) && (enter == true)) {
      while (schritte != 0) {
        if (digitalRead (hal) == LOW); {
          schritte--;
          Serial.println("Schritte");
          Serial.println(schritte);
          delay(2000);
          enter = false;
          gleisAlt = wertSpeichern;
        }
      }
    }
    //if ((schritte >12)&& (enter== true)) {
    // Serial.println("rechts");
    //enter = false;
   //  else {
  // Serial.println("links");
  //enter = false;
  //}
  //}
  messungPin1Alt = messungPin1;
}

Hi,

Keine Ahnung worauf du stehst ,

Die Abfrage des Hallsensors hat doch nichts mit dem While zu tun , richtig ist das die Abfrage des Hallsensors nur erfolgt wenn die while schleife erfüllt ist.

nochmals der Vorschlag zurück zu #19 u #21

was willst Du in der while schleife eigentlich machen , wenn der Sensor belegt ist runter zählen bis 0 , das jedesmal anzeigen und dazwischen 2s warten. ?

Heinz

Jedes mal einen Schritt runterzählen wenn der Sensor vom Magneten betätigt wird. Bis die Schritte 0 sind. Die 2 Sekunden habe ich nur eingebaut, damit ich im Seriellen Monitor was sehe. Weil ja sobald ich den encoder Taster betätige die While Schleife ausgeführt wird, obwohl der Hal gar nicht betätigt ist.

Hi

Die Sache ist viel einfacher - diese 2 Sekunden wartet Er, damit der Hall-Sensor eben nur 1x erkannt wird.
NUR: Das Runterzählen der Schritte ist 'suboptimal'.
Was, wenn von Gleis 19 auf Gleis 18 gefahren werden soll?
Schritte=-1 ... und der Sketch läuft einige Runden, bis Das auf Null kommt (int geht bis -16768 runter ... nur Mal so)

Eigentlich eine schöne Aufgabe - nur hat sich der To hier schon etwas verrannt.
Der Ansatz ist stimmig, die Abarbeitung bedarf einer Verbesserung.
Aktuell wäre Es besser, Du lässt den Motor laufen, bis Dein IST-Gleis dem SOLL-Gleis entspricht - geht nur bei einer Drehscheibe und sieht Da dann auch noch blöd aus, wenn 23 Gleise nach links gedreht wird, wo eine Drehung um 1 Gleis nach Rechts gereicht hätte.

ODER: Du merkst Dir den Abstand der Positionen, stellst die Drehrichtung ein, und wartest drauf, daß diese Schrittanzahl Null wird.

MfG

PS: MALE Dir auf, was Du erreichen willst, mit möglichst kleinen Zwischenschritten

PPS: Oha . DANN habe ich mich mit dem delay(2000); vertan - Du wirst aber nicht sonderlich glücklich ohne das delay, da die While-Schleife für einen Durchlauf nicht wirklich lange braucht - die Schritte sind ruck-zuck auf Null runter gezählt - sobald der Hall-Sensor auslöst.
Du wartest hier NICHT darauf, daß der Hall-Sensor wieder sperrt, zählst also die Erkennung Mehrfach!

Ich will mich halt Schrit für Schritt ran tasten. Es soll dann auch immer der kürzere Weg genommen werden. Es muss dann so zu sagen auch noch recht oder linksdrehen entschieden werden. Zum schluss möchte ich auch mal noch langsam anfahren und bremsen. Aber bis dahin....

PS. das mit dem Hall und der Zeit stimmt. Da habe ich noch gar nicht dran gedacht.
Mit den negativen und positiven Schritten hab ich auch noch keine Idee.

ODER: Du merkst Dir den Abstand der Positionen, stellst die Drehrichtung ein, und wartest drauf, daß diese Schrittanzahl Null wird.

genau so wollte ich es ja machen.

Hi

Dann ist aber die Start-Schrittzahl eher

schritte = abs(gleisNeu - gleisAlt);  //ABSOLUT, liefert negative Werte positiv zurück
if (gleisNeu<gleisAlt){
  richtung=links;
}else{
  richtung=rechts;
}

Damit kannst Du dann den Motor so lange drehen lassen (eben je nach 'richtung' links oder rechts rum), bis der HallSensor so oft 'gesehen' wurde, wie Schritte abzuwarten ist.

MfG

Danke dir. Funktioniert das auch wenn ich von Gleis 1 zu Gleis 23 Fahren will das sie dann links rum läuft?

Hallo,

Habt ihr ne Idee warum die for Schleife läuft obwohl der Hall nicht betätigt wird. Er ist über einen Pullup angeschlossen.

if ((gleisNeu != gleisAlt) && (enter == true)) {
    if (digitalRead (hal) == LOW); {
    for (schritte != 0; schritte >0; schritte-- ) {
    //if (digitalRead (hal) == LOW);{
    //schritte--;
    Serial.println("Schritte");
    Serial.println(schritte);
    delay(2000);}
    enter = false;
    gleisAlt = wertSpeichern;
}

Hi
Jupp :slight_smile:

if (digitalRead (hal) == LOW);

Die IF-Abfrage ist an dem ; zuende.
Die Klammerung hat dahinter keinen höheren Sinn mehr - der Code wird ausgeführt, weil Er eben hinter der IF steht.

Entferne das ; , dann greift die Klammer wieder, wenn die Bedingung wahr ist.

MfG

if ((gleisNeu != gleisAlt) && (enter == true)) {
    if (digitalRead (hal) == LOW) {
    for (schritte != 0; schritte >0; schritte-- ) {
    //if (digitalRead (hal) == LOW);{
    //schritte--;
    Serial.println("Schritte");
    Serial.println(schritte);
    delay(2000);}
    enter = false;
    gleisAlt = wertSpeichern;
}

hm... Funktionirt aber trotzdem nicht. Der code rast jetzt durch und wenn ich den Hall einmal betätige läuft die Schleife wieder automatisch. Aber sie soll jedesmal wenn der Hall betätigt wird jedesmal die Variable schritte um 1 runter zählen.

Hi

Du wartest, bis der ein neues Gleis gewählt wurde und Enter gedrückt wurde
Jetzt wartest Du darauf, daß der Hall-Sensor LOW zeigt
Jetzt Startest Du eine Schleife, Die alle 2 Sekunden einen Wert runter zählt.

Ich denke, der Sketch macht genau Das, was Du geschrieben hast.
Mit ziemlicher Sicherheit aber nicht Das, was Du willst.

Du willst:

  • den Hall-Sensor IMMER abfragen - direkt in der loop
  • den Motor starten, wenn eine Fahrt gestartet wird (und der Abstand !=0 ist)
  • den Motor stoppen, wenn der Abstand ==0 ist
  • die Schritte (um 1) herunterzählen, wenn der Hall-Sensor von HIGH nach LOW wechselt
    ... die loop() wird tausend Mal die Sekunde durchrannt und trotzdem wird nur dann auf etwas reagiert, wenn's dafür 'an der Zeit ist'.

Ob der Motor nach dem letzten Hall-Impuls noch weiterlaufen muß, bis die Gleise übereinander stehen - kA - wenn nicht, müsste man einen Schritt vorher mit der Bremsrampe beginnen.

Das lässt sich wunderbar in eine State-Maschine einbauen.
Dazu hat combie bereite eine Liste hier im Forum - solltest Du Dir ansehen.

MfG

[
Du willst:

  • den Hall-Sensor IMMER abfragen - direkt in der loop

Nein der Hall soll nur abgefragt werden, wenn die Bühne dreht und der Motor läuft

  • den Motor starten, wenn eine Fahrt gestartet wird (und der Abstand !=0 ist)

Ja genau

  • den Motor stoppen, wenn der Abstand ==0 ist

ja genau

  • die Schritte (um 1) herunterzählen, wenn der Hall-Sensor von HIGH nach LOW wechselt

Stimmt auch

Wenn die Schritte abgelaufen sind kann, kann man über den Drehencoder erst das nächste Zielgleis wählen.

... die loop() wird tausend Mal die Sekunde durchrannt und trotzdem wird nur dann auf etwas reagiert, wenn's dafür 'an der Zeit ist

Hi

Was stört Dich daran, daß der Hall-Sensor abgefragt wird, wenn die Bühne Sich nicht dreht?
Ohne Drehung wird auch keine Flanke kommen, Die man auswerten könnte - und ausgewertet wird eh nur, wenn der Motor drehen soll.

Motor = stop ;// Drehrichtung des Motor bei Start auf STOP (oder ggf. Referenz-Fahrt)
...
setup(){
//Motor-Pin auf OUT, Hall-Pin auf IN, ...
}
...
loop(){
  //... Encoder auswerten und 'Soll' hoch/runter zählen
  static boolean flanke=false;
  static boolean hallalt=false;
  boolean hallneu=digitalRead(hall_pin);
  if (hallalt==true && hallneu==false){
     flanke=true;
  }else{
     flanke=false;
  }
  hallalt=hallneu;
  Wenn (Motor!=stop && Flanke=true){
    schritt--;
  }
  Wenn (schritt==0 && Motor!=stop){
    Motor=stop;
  }
  Wenn (Enter=gedrückt && Soll != Ist && Motor==stop){
     byte linksrum=abs(Soll-Ist);
     byte rechtsrum=abs(Ist-Soll);
     Wenn (linksrum <= rechtsrum){
        schritte=linksrum;
     }else{
        schritte=rechtsrum;
     }
  }
  if (motor==stop && schritte!=0){
     if (schritte==linksrum){
        Motor=links;
     }else{
        Motor=rechts;
     }
  }
}

So in der Art würde ich's versuchen.

Das Zielgleis kann IMMER eingestellt werden.
Eine neue Fahrt kann nur gestartet werden, wenn die Bühne nicht dreht, dann wird das eingestellte Gleis als Ziel übernommen (bzw. die Schritte dahin berechnet und der Motor gestartet).
Während der Motor fährt, werden bei fallender Flanke jeweils ein Schritt abgezogen.
Bei Schritt auf Null wird der Motor angehalten.
Es wird jeweils in die Richtung der kürzeren Entfernung gestartet.
Man kann, sobald die Bühne läuft, problemlos ein neues Zielgleis anwählen, die Übernahme geht aber erst, wenn die vorherige Fahrt beendet wurde.

Man kann einige der Abfragen kombinieren - so ist Es nicht wirklich nötig, in mehreren auf einander folgenden IF-Abfragen 'Motor==stop' abzufragen - Das könnte man in einer IF erschlagen und in Deren Körper die anderen IFs verarbeiten.

Man kann den Motor auch in ein switch-case einsetzen und dort z.B. die Referenz-Fahrt abfrühstücken, bei stop die Fahrt starten, sofern Soll!=Ziel und Enter gedrückt sowie bei links/rechts prüfen, ob wir bereits am Ziel sind (= Motor stoppen) bzw. die Flanke des Hal-Sensor auswerten.
= State-Maschine

MfG

Das mit der Statemachine verstehe ich nicht. Wie soll mir das bei meinem Projekt helfen?

Oder besser gesagt womit fange ich da in meinem Projekt an?