Drehscheibe Modellbahn mit RF24

Hallo alle zusammen,

ich spiele gerade mal ein wenig mit dem Drehencoder. Ziel ist es mir Werte von 0-23 auf dem Display anzeigen zu lassen. Das funktioniert auch schon ganz gut. Nur habe ich ein Problem:

Wenn ich den Arduino starte und dann am Encoder drehe, geht dieser Wert zuerst nur bis 15. Wenn ich einmal die 15 erreicht habe dann geht er komischerweise bis Wert 23. Drehe ich ihn dann wieder auf 0 zurück, springt er nach Wert 0 wieder auf Wert 15 und nicht auf Wert 23.

Habt ihr ne Idee woran das liegen könnte?

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int messungPin1 = LOW;
int messungPin1Alt = LOW;
int encoderWertA = 0;
byte encoderWert = 0;

 void setup() { 
 pinMode(10, INPUT);
 pinMode(11, 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();
 
 } 

 void loop() {
 messungPin1 = digitalRead(10);
 if ((messungPin1 == HIGH) && (messungPin1Alt == LOW)) {
 if (digitalRead(11) == HIGH) {
 encoderWertA = (encoderWert++)%24;
 } else {
 encoderWertA =(encoderWert--)%24;
 }
 Serial.println (encoderWertA);
 lcd.begin(16, 2);
 lcd.setCursor(0, 0);
 lcd.print("Wert");
 lcd.setCursor(0, 1);
 lcd.print(encoderWertA);
 
 }
 messungPin1Alt = messungPin1;
 }

Hi

Du lässt zwar encoderWertA auf 23 begrenzen, aber Deine eigentliche Zähl-Variable encoderWert zählt 25 ... 26 ... 27 ...
Oder 1 ... 0 ... -1 ... -2 ...

MfG

Edit
Der RF24 kam erst bei Post 120 dazu - Link:#120.
Dort klappt die Drehbühne anscheinend bereits, wie hier zu Beginn angedacht.

Hi,

Danke für den Hinweis, aber wie könnte ich das ändern?

byte encoderWert = 0xff; // -1 ( eins weniger als 0 ) == 255
int encoderWertA = encoderWert %24; // 255 % 24 =15

encoderWertA braucht man nicht:

if (digitalRead(11) == HIGH) {
 if (encoderWert < 23) encoderWert++ ;
} else {
 if (encoderWert > 0) encoderWert-- ;
}

mit Begrenzung auf 0 .. 23

Hi

Acki1985:
Danke für den Hinweis, aber wie könnte ich das ändern?

Indem Du den begrenzten encoderWertA auf Deinen encoderWert kopierst.

encoderWert=encoderWertA;

Sollte 'tun'.

MfG

andere Fallstricke:

Hast Du Pullup/Pulldown Widerstände an den Pins 10 und 11?
Vieleicht solltest Du ein delay(10); nach if ((messungPin1 == HIGH) && (messungPin1Alt == LOW)) {" einfügen um den Kontakt zu entprellen.

Grüße Uwe

Hi,

es sind Pullup Wiederstände eingebaut. Das es am Prellen liegt kann ich mir eigentlich nicht vorstellen. Es geht ja nur beim ersten mal drehen bis Wert 15 und dann von 0 bis 23.

postmaster-ino:
HiIndem Du den begrenzten encoderWertA auf Deinen encoderWert kopierst.

encoderWert=encoderWertA;

Sollte 'tun'.

MfG

Wenn ich das mache erhalte ich immer Wert 0.

Acki1985:
Wenn ich das mache erhalte ich immer Wert 0.

Hallo,

die Lösung von Michael in #3 hast Du gesehen , die wäre auch mein Vorschlag gewesen.

Heinz

Hi

Acki1985:
Wenn ich das mache erhalte ich immer Wert 0.

Kommt drauf an, WO Du Das machst.
Aber kein Problem, in Salami-Taktik bin ich lernfähig.
Dein Problem: Dein Tempo

MfG

Wenn ich das so wie in #3 mache, ist der Startwert 255. Diesen muss ich dann auf 0 runter regeln. Danach geht der Wert von 0 bis 23 und von 23 bis 0.

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int messungPin1 = LOW;
int messungPin1Alt = LOW;
byte encoderWert = 0xff; // -1 ( eins weniger als 0 ) == 255
int encoderWertA = encoderWert %24;  // 255 % 24 =15


 void setup() { 
 pinMode(10, INPUT);
 pinMode(11, 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();
 
 } 

 void loop() {
 messungPin1 = digitalRead(10);
 if ((messungPin1 == HIGH) && (messungPin1Alt == LOW)) {
 if (digitalRead(11) == HIGH) {
 if (encoderWert < 23) encoderWert++ ;
} else {
 if (encoderWert > 0) encoderWert-- ;

  }
 Serial.println (encoderWertA);
 lcd.begin(16, 2);
 lcd.setCursor(0, 0);
 lcd.print("Wert");
 lcd.setCursor(0, 1);
 lcd.print(encoderWert);
 
 }
 
 messungPin1Alt = messungPin1;
 }

Hab es rausbekommen. Liegt an dem Variablentyp Byte. Der kann ja nur psitive Zahlen. Wenn ich da eine negative Zahl eingebe, ist der Startwert = 255. Gebe ich da 0 ein Startet er bei 1. Muss dann aber auch null runteregeln bevor ich den Wertebereich 0 bis 23 nutzen kann.

Hat da noch wer ne Idee?

Hab es hinbekommen :slight_smile:

#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
int encoderWertA = encoderWert %24;  // 255 % 24 =15
int 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

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(10, INPUT);
 pinMode(11, INPUT);
 pinMode(12, 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(10);
 if ((messungPin1 == LOW) && (messungPin1Alt == HIGH)) {
 if (digitalRead(11) == HIGH) {
 if (encoderWert < 23) encoderWert++ ;
} else {
 if (encoderWert > 0) encoderWert-- ;

  }
 
 lcd.begin(16, 2);
 lcd.setCursor(0, 0);
 lcd.print("Wert");
 lcd.setCursor(0, 1);
 lcd.print(encoderWert);
 
 }

 {
  encoderTaster = digitalRead(12);
  if (encoderTaster == LOW)
  {
    encoderDruckzeit = millis();
    encoderGedrueckt = 1;
  }

  if ((millis() - encoderDruckzeit > entprellZeit) && encoderGedrueckt ==1) {
    
    
    wertSpeichern = encoderWert;
    Serial.println(wertSpeichern);
    encoderGedrueckt=0;
  }


  
 }
 
 messungPin1Alt = messungPin1;

 
  }

Es kommt darauf an was man will.

if (digitalRead(11) == HIGH) {
 if (encoderWert < 23) encoderWert++ ;
} else {
 if (encoderWert > 0) encoderWert-- ;
}

bringt Dir Werte zwischen 0 und 23

wenn man nach der 23 die null kommen soll dann muß man es anders machen
Grüße Uwe

Hi

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Hier wäre Es übersichtlicher, wenn man den
                                     //Zahlen sprechende Namen geben würde, um ein
                                     //Anpassen an andere Pins einfacher zu gestallten
int messungPin1 = HIGH;
int messungPin1Alt = HIGH;
byte encoderWert = 0; // -1 ( eins weniger als 0 ) == 255
//int encoderWertA = encoderWert % 24; // 255 % 24 =15  //Wird im Sketch nicht benutzt - wohl nicht angemeckert, da eine Zuweisung stattfindet
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
byte encoderGedrueckt = 0;              // Statusspeicher ob Encodertaster betätigt wurde
byte encoderTaster = HIGH;             // Taster im Encoder
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);
  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 < 23) encoderWert++ ;
    } else {
      if (encoderWert > 0) 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;
    }
  }  // <-- ???
  messungPin1Alt = messungPin1;
}

Compiliert ohne Wqarnungen.
Ich habe mir gestattet, die Pins außerhalb einzustellen und im Code die 'magic numbers' durch sprechende Namen zu ersetzen.
Da sich die Pinzuweisungen wohl während der Laufzeit nicht mehr ändern, sind Diese als const deklariert - der Compiler kann Diese somit fest im Code verbauen - wenn Er mag.
Entfernen unnötiger Leerzeilen und ein STRG+T brachten bessere Lesbarkeit.
Woher hast Du die Klammerung innerhalb loop()? Von mir mit // <-- ?? gekennzeichnet?
Diese Klammerung sollte - überhaupt Nichts - bewirken (lasse mich Da gerne korrigieren)

MfG

Gesundes neues Jahr wünsche ich allen :slight_smile:

Ich danke dir Postmaster.

Ich bin schon ein Schritt weiter. Ich möchte mit dem Encoder Positionen einstellen können die ein Motor zurücklegen (Stepps) muss. Das mit der Berechnung funktioniert schon ganz gut. Nur wie mache ich das, das die Schritte mit einem Hallsensor mittels Magnet am Zahnrad.vergleicht und wenn die Schritte zurückgelegt wurden der Motor abschaltet?

#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 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);
 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;
  enter = false;
}

//if ((schritte >12)&& (enter== true)) {
 // Serial.println("rechts");
  //enter = false;
}
//  else {
   // Serial.println("links"); 
    //enter = false;
//}

//}

  
 
 
 messungPin1Alt = messungPin1;

 
  }

Hallo,

DC Motor , Schrittmotor , eine Richtung , zwei Richtungen, wie schnell dreht das Zahnrad, Welche Übersetztung mit Bezug auf die Motorwelle ? Willst du wirklich nur so viel Zähne fahren we Du mit den Werten des Encoders vorgibst ( 0-23)

Jetzt mal ganz grob

Bei einem Schrittmotor macht der Hallsensor keinen Sinn. Bei DC Motor must du halt die Impulse des Hallsensors beim fahren zählen, mit deinem Sollwert vergleichen und dann abschalten. Mit einem DC Motor kannst Du keine kleinen Winkelschritte fahren.
Mit nur einem Hallsensor am Zahnrad weist Du nicht wie die Richtung ist. Dann must Du Dir die aktuelle Position aus den gefahren Impulsen bilden und in einer Variablen abspeichern. Aus der Differenz zwischen neuem Sollwert und Istwert die Richtung bestimmen und abhängig davon den Istwert hoch oder runter zählen. Probleme bekommst Du damit beim starten nach Power on , da Du nicht weist wo du stehst. Ein " Refferenzfahren " währe dazu die Lösung.

Heinz

Hallo Heinz,

Ich danke dir. Also es wird ein DC Motor über Motortreiber angesteuert. Die Bühne wird über ein großes Zahnrad angetrieben. Dieses Zahnrad besitzt 3 Kerben wo bei erreichen ein Stift einrastet. Dieser Stift wird Bei Start zurückgesogen und gibt das Zahnrad frei. Nach ablauf der Schritte, soll der Stift wieder in die entsprechende Kerbe einrasten. Der Weg den die Bühne zurückgelegt hat, wird über den Hallsensor ermittelt. An jeder Kerbe ist ein Magnet angebracht. Jede Kerbe bedeudet einen Gleisabgang. Ich hoffe ich konnte es einigermasen verständlich erklären. Der Start ab Gleis 1 wird immer bei Poweron über eine Referenzfahrt festgelegt.

Hab mal ein wenig weiter gemacht. Nur leider scheint er die While Schleife nicht auszuführen.

#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 (hal == LOW);
    schritte--;
    Serial.println("Schritte");
    Serial.println(schritte);
    }
  }
    else {
      enter = false;
    }
    
  }
//if ((schritte >12)&& (enter== true)) {
 // Serial.println("rechts");
  //enter = false;
}
//  else {
   // Serial.println("links"); 
    //enter = false;
//}

//}

  
 
 
 messungPin1Alt = messungPin1;

 
  }

Habt ihr ne Idee?

while (schritte >0);  // ??

Die while-Schleife geht nur bis zum Semikolon
Wenn (schritte > 0) hängt der Sketch hier für immer

So ganz habe ich die Sketch-Logik aber nicht verstanden ...