Hi,
habe mal eben mit meinen Encodern rumgetestet:
Specifications:
Rotary Shaft Length: Approx. 12mm
Shaft Full Length: Approx. 20mm
Shaft Diameter: Approx. 6mm
Size (L x W): Approx. 15 x 11mm
Position: 20
Pulse: 20
Output: 2-bit gray code
Closed Circuit Resistance: 3 ohms maximums
Max. Rating: 10 mA @ 5 VDC
Operating Temperature Range: -30 to 70 degrees celsius
Storage Temperature Range: -40 to 85 degrees celsius
Rotational Life: 30000 cycles minimum
Switch Life: 20000 cycles minimum
Hier zunächst mein TestCode:
/******Encoder*************/
int AAread=0;
int BBread=0;
byte modus=0;
byte A=3;
byte B=2;
byte modusa=0;
byte buttonA=4;
int d;
boolean once=false;
/************SETUP*****************/
void setup()
{
Serial.begin(115200);
/************ENCODER*************/
pinMode(buttonA, INPUT);
pinMode(A,INPUT);
pinMode(B,INPUT);
digitalWrite(buttonA, HIGH);
digitalWrite(A,HIGH);
digitalWrite(B,HIGH);
attachInterrupt(0,encoder,CHANGE);
attachInterrupt(1,encoder,CHANGE);
}
/***************HAUPTSCHLEIFE******************/
void loop()
{
if (modusa==0) {
if (once==false) {
once=true;
}
Serial.println("Modus 0 / Secs: ");
Serial.println(millis());
delay(1000);
}
if (modusa==1) {
if (once==false) {
once=true;
}
Serial.println("Modus 1 / Secs: ");
Serial.println(millis());
delay(1000);
}
if (modusa==2) {
if (once==false) {
once=true;
}
Serial.println("Modus 2 / Secs: ");
Serial.println(millis());
delay(1000);
}
if (modusa==3) {
if (once==false) {
once=true;
}
Serial.println("Modus 3 / Secs: ");
Serial.println(millis());
delay(1000);
}
}
/****WECHSEL MANUELL AUTOMATISCH*****/
void Button(){
byte read1=digitalRead(buttonA);
if (read1==HIGH && once==true) {
++modusa;
once=false;
}
if (modusa==3) modusa=0;
}
/********Encoder Steuerung blau [1] und [2] und Mondlicht [4]*****/
void encoder() {
AAread=digitalRead(A);
BBread=digitalRead(B);
/*--Linksdrehen--*/
if (AAread==LOW && BBread==LOW ||AAread==HIGH&& BBread==HIGH){
d=d-1;
Serial.print("Linksdrehen: ");
Serial.println(d,DEC);
}
/*--Rechtsdrehen--*/
if (AAread==HIGH && BBread==LOW||AAread==LOW && BBread==HIGH) {
d=d+1;
Serial.print("Rechtsdrehen: ");
Serial.println(d, DEC);
}
}
2 Fehler, bislang die Ursache trotz diverser Tests nicht gefunden:
Click auf Button schaltet nicht den Modus weiter. Habe ich irgendwie falsch entprellt (boolean once)?
Die interrupts 0 und 1 liegen auf A und B, also nur drehen. Wenn ich jetzt drehe passiert auch was, aber irgendwie wird immer mit einem Raster ein rechtsdrehen und ein linksdrehen ausgelöst. Siehe Screenshot. Was hab ich da falsch programmiert?
Eigentlich ist der Code mehr oder weniger von einem funktionierenden Code, aber ein neuer Encoder.
Angeschlossen ist folgend:
auf der 3-PIN Seite:
A und B an die Interrupts, C an GND
auf der 2-PIN Seite:
einer an Digital-In, einer an GND
Hoffe mir kann jemand helfen. Ich hatte meine alten Panasonic Encoder bereits am laufen, eigentlich mit fast dem selben Code. Daher bin ich grad verwirrt....
Gruß
EDIT an Mod:
kann leider mein 66kb Anhang nicht anhängen:
The upload folder is full. Please try a smaller file and/or contact an administrator.
Der Graycode ist ein absoluter Coder der bei jedem Weiterzählen nur ein Bit ändert und nicht mehrere wie der Binärcode wenn er zB von 7 auf 8 wechselt (B0111 auf B1000) Gray-Code – Wikipedia
Es ist kein incrementeller Code wie eine 2 Phasiges Signal einer Lochscheibe.
Aus der Beschreibung des Encoders werde ich nicht schlau. Einerseits hat er 2 Bit Graycode; somit eine Auflösung von 4 und andererseits 20 Pulse pro Umdrehung.
Hast Du den Herstellercode oder ein Datenblatt?
Grüße Uwe
das mit dem Graycode habe ich jetzt so verstanden - aber in wie fern ist das der Grund für die Verwirrung ("aber irgendwie wird immer mit einem Raster ein rechtsdrehen und ein linksdrehen ausgelöst")?
Es ging ja mal mit einem anderem Encoder. Also vermute ich jetzt, dass ich was am Code falsch habe?
Leider habe ich kein Datenblatt gefunden, die Dinger sind von Ebay, ich habe den Verkäufer mal angeschrieben.
Du musst ein "Datentable" hinterlegen und die beiden Eingänge vergleichen in welche Richtung gedreht hast. Der ander Code ist für einen Incrementalgeber bei dem sich die Signale anders verhalten.
Der 2 Bit Gray Code hat folgende Wahrheitstabelle:
A B
0 0
0 1
1 1
1 0
Daraus ist ersichtlich, daß keine Richtungsinformation bei einem H-L bzw L-H Übergang wie bei einem 90 Grad versetzten Phasensignal aus dem Zustand der Signale der beiden Leitungen erhalten werden können.
Es können aber auch nur 4 Positionen pro Umdrehung erkannt werden und darum verstehe ich die Information "pulse 20" in den Daten nicht.
Mit anderen Worten es ist der Falsche Encoder um auf diese Weise Richtungsinfo zu erhalten. Richtungsinfo erhälst Du wenn Du die Letzte Position mit der Aktuellen vergleichst und die Richtung errechnest.
Hallo currymuetze,
wenn es ein Graycode in dieser Form ist
PinA PinB
0 0 | Drehrichtung cw
0 1 |
1 1 |
1 0 V
dann schau dir mal meinen Code an (Anwendung in der Menüsteuerung von mehrzeiligen LCD Displays: Projektvorstellung: Menü für LCD Display mit Rotary Encoder Auswahl - Deutsch - Arduino Forum)
Die entscheidenden Teile nehme ich hier mal auf. Das Prinzip funktioniert mit nur einem Interrupt, der ausgelöst wird, wenn sich der Zustand von PinA ändert. In Abhängigkeit vom angenommenen Zustand PinA und dem Zustand von PinB wird die Drehrichtung bestimmt.
#define PINA 2
#define PINB 7
#define INTERRUPT 0 // that is, pin 2
volatile boolean turned; // rotary was turned
volatile boolean up; // true when turned cw
// Interrupt Service Routine for a change to encoder pin A
void isr ()
{
if (digitalRead (PINA))
up = digitalRead (PINB);
else
up = !digitalRead (PINB);
turned = true;
} // end of isr
void setup ()
{
digitalWrite (PINA, HIGH); // enable pull-ups
digitalWrite (PINB, HIGH);
digitalWrite (PUSHP, HIGH);
attachInterrupt (INTERRUPT, isr, CHANGE); // interrupt 0 is pin 2
}
void loop ()
{
if (turned)
{
if (up)
[i]<hier Unterprogramm für cw-Drehung aufrufen>[/i];
else
[i]<hier Unterprogramm für ccw-Drehung aufrufen>[/i];
turned = false;
}
}
Gruß
Reinhard
Nachtrag: gerade den Beitrag von Uwe gesehen. Mein Encoder hat auch 16 Rastpositionen pro Umdrehung. D.h. der Graycode wiederholt sich, in meinem Fall 4x / Umdrehung. Es geht ja auch nicht um eine absolute Position, sondern nur darum ob nach rechts oder links gedreht wird.
volvodani:
Du musst ein "Datentable" hinterlegen und die beiden Eingänge vergleichen in welche Richtung gedreht hast. Der ander Code ist für einen Incrementalgeber bei dem sich die Signale anders verhalten.
So sieht man seinen Code wieder
Hi,
jip genau - war mir nur nicht bvewusst, dass die Encoder so unterschiedlich sind Damals hab ich ja auch den Panasonic genutzt, mir ging aber die mehr oder weniger nicht mögliche BEfestigung an einem Gehäuse auf den Geist. Also habe ich mir mal (blind) neue besorgt, die man anschrauben kann.
Werde mir mal ErniBernis COde anschauen und schauen obs klappt oder ob Uwe Recht hat.
Allerdings frage ich mich wofür der Encoder gut sein soll, wenn er nicht für diese Anwendungen funktioniert? Ich hoffe dann mal auf einen Datenblattfehler.
so, habe mich an ErnieBernis Code gehalten, aber irgendwie komme ich nicht weiter.
Den BUtton habe ich erst mal deaktiviert. Angeschlossen ist der Encoder an 2,4 und an GND.
Frage: Ist es relevant, welche Baudrate man hier beim SerialPrint einstellt?
Hier der Code:
//**********************************************Rotary Encoder*********************************
#define PINA 2
#define PINB 4
#define PUSH1 3
#define INTERRUPTA 0
#define INTERRUPTB 1
volatile boolean turned; // rotary was turned
volatile boolean fired; // knob was pushed
volatile boolean up1; // true when turned cw
int d;
byte modus=0;
void setup ()
{
Serial.begin(115200);
//**********************************************Rotary Encoder*********************************
digitalWrite (PINA, HIGH);
digitalWrite (PINB, HIGH);
digitalWrite (PUSH1, HIGH);
attachInterrupt (INTERRUPTA, isr1, CHANGE);
// attachInterrupt (INTERRUPTB, isrp, FALLING);
}
// Interrupt Service Routine for a change pushpin
void isrp ()
{
if (!digitalRead (PUSH1))
fired = true;
}
// Interrupt Service Routine for a change to encoder pin A
void isr1 ()
{
if (digitalRead (PINA))
up1 = digitalRead (PINB);
else
up1 = !digitalRead (PINB);
turned = true;
} // end of isr
void loop ()
{
if (turned) {
if (up1) {
d=d-1;
Serial.print("Linksdrehen: ");
Serial.println(d,DEC);
}
else {
d=d+1;
Serial.print("Rechtsdrehen: ");
Serial.println(d, DEC);
turned = false;
}
}
}
currymuetze:
Allerdings frage ich mich wofür der Encoder gut sein soll, wenn er nicht für diese Anwendungen funktioniert? Ich hoffe dann mal auf einen Datenblattfehler.
Gruß
Dass frage ich mich auch. Ein Encoder mit Gray-Code kann die absolute Position bestimmen in der er sich gerade befindet; Dazu braucht es aber mehr als 2 Bit; mit 4 Bit sind 16 Positionen bestimmbar, mit 5Bit sind es 32.
Der Vorteil eines Gray-Codes ist daß bei jeder Inkrementierung / Decrementierung nue 1 Bit sich ändert und so eine nicht genau eingestelte Ableseeinheit keine Bitfehler verursacht.
Hi Uwe,
wie finde ich jetzt raus, ob der Encoder falsch ist (was ich mir irgendwie auch nicht vorstellen kann, leider habe ich aber kein weiteres Datenblatt)?
Habt ihr euch meinen letzten Testcode angeschaut? Meine Erwartung bei dem Code wäre: Die AUsgabe über Serial ist leer, bis ich an dem ENcoder drehe. Wenn ich drehe erscheint die Richtung mir dem Wert d.
Habe ich da irgendwo einen Fehler drin? Wenn nicht, dann kann es ja nur am Encoder liegen, aber so wie ich ErnieBernie wiederum verstanden habe halt auch nicht.
Farbtoaster sagt, ich habe einen Inkrementalgeber.
Jetzt lese ich noch mal weiter vorher von Volvodani
Der ander Code ist für einen Incrementalgeber bei dem sich die Signale anders verhalten.
woraus ich schließe dass ich eben keinen Incrementalgeber habe.
Das würde ich nun natürlich gerne mal klären und dann würde ich gerne klären, mit welchem Code ich testen kann/muss.
Mit diesem hier klappts leider nicht:
/* Digital Pin 2 accepts external interrupts. Pin1 of a rotary encoder
is attached to DigitalPin2. An interrupt routine will be called
when pin1 changes state, including noise.
This will be made more efficient with hardware debouncing.
*/
int pin1 = 2;
int pin2 = 3;
int counter;
boolean goingUp = false;
boolean goingDown = false;
void setup()
{
counter = 0;
//Serial prints for debugging and testing
Serial.begin(9600);
/* Setup encoder pins as inputs */
pinMode(pin1, INPUT); // Pin 2
pinMode(pin2, INPUT); // Pin 4
// encoder pin on interrupt 0 (pin 2)
attachInterrupt(0, decoder, FALLING);
}
void loop()
{
//using while statement to stay in the loop for continuous
//interrupts
while(goingUp==1) // CW motion in the rotary encoder
{
goingUp=0; // Reset the flag
counter ++;
Serial.println(counter);
}
while(goingDown==1) // CCW motion in rotary encoder
{
goingDown=0; // clear the flag
counter --;
Serial.println(counter);
}
}
void decoder()
//very short interrupt routine
//Remember that the routine is only called when pin1
//changes state, so it's the value of pin2 that we're
//interrested in here
{
if (digitalRead(pin1) == digitalRead(pin2))
{
goingUp = 1; //if encoder channels are the same, direction is CW
}
else
{
goingDown = 1; //if they are not the same, direction is CCW
}
}
Versuch mal 2 LEDs mit den Ausgang des Encoders anzusteuern und diesen langsam zu drehen. Wenn die LEDs immer, das eine zeitverzögert zum anderen leuchtet, dann ist es ein incrementeller Encoder mit 90 grad Phasenverschiebung zwischen den beiden Signalen.
Wenn nicht dann mußt Du dir eine Wahrheitstabelle zeichnen.
Grüße Uwe
Irgendwie läuft der Speicher recht schnell voll, wenn ich zu schnell drehe....irgendwann bricht zumindest die seriel Verbindung ab und bleibt stehen bei den d=d+10
Hi,
jetzt habe ich echt 2 STunden gelesen und gegoogelt, aber so ganz schlüssig isses mir noch nicht wie ich
a) den Button
b) den encoder
entprelle.
Wenn, dann möchte ich das auf jeden Fall Softwareseitig machen. Denke für meine Zwecke reicht das völligst aus.
Wenn mal jemand ein richtig gutes Tutorial kennt (auch für Einsteiger) würde mir das sehr helfen
So,
der code von erni bernie/Nick Gammon funktioniert jetzt auch:
// Rotary encoder example.
// Author: Nick Gammon
// Date: 25th May 2011
// Thanks for jraskell for helpful suggestions.
// Wiring: Connect common pin of encoder to ground.
// Connect pin A (one of the outer ones) to a pin that can generate interrupts (eg. D2)
// Connect pin B (the other outer one) to another free pin (eg. D5)
volatile boolean fired;
volatile boolean up;
volatile boolean turned;
#define PINA 2
#define PINB 4
#define INTERRUPT 0 // that is, pin 2
#define PUSHP 3
#define INTERRUPTB 1 // that is, pin 3
void isrp ()
{
if (!digitalRead (PUSHP))
fired = true;
} // end of isr
// Interrupt Service Routine for a change to encoder pin A
void isr ()
{
if (digitalRead (PINA))
up = digitalRead (PINB);
else
up = !digitalRead (PINB);
turned = true;
} // end of isr
void setup ()
{
digitalWrite (PINA, HIGH); // enable pull-ups
digitalWrite (PINB, HIGH);
digitalWrite (PUSHP, HIGH);
attachInterrupt (INTERRUPT, isr, CHANGE); // interrupt 0 is pin 2, interrupt 1 is pin 3
attachInterrupt (INTERRUPTB, isrp, FALLING);
Serial.begin (115200);
} // end of setup
void loop ()
{
static long rotaryCount = 0;
if (turned)
{
if (up)
rotaryCount++;
else
rotaryCount--;
turned = false;
Serial.print ("Count = ");
Serial.println (rotaryCount);
} // end if fired
else if (fired)
{
Serial.println ("Buttonpress");
fired = false;
}
} // end of loop
Wenn ich das richtig verstehe, ist der schon softwareseitig entprellt??? Ging erst nicht.
Habe dann mal einen 0.1u Cap an den Button und zwischen A-C und B-C gelötet:
Der BUtton geht seit dem 100%ig
Der Encoder selbst leider nicht, wobei die Caps Verbesserung gebracht haben:
Ohne Caps war das Verhalten folgend:
es wurden IMMER 2 Clicks auslöst, zwischendrin dann auch mal 3.
Mit den Caps habe ich durchgängig 2 Clicks. (Click= 1 tacken weiter drehen, aber 2* den interrupt auslösen)
mit dem Entprellen der Kontakte hab ich auch noch keine vernünftige Lösung gefunden.
Der Pushbutton ist mit 100nF wie bei dir hardwareseitig entprellt. Das funktioniert auch ganz gut.
Beim Encoder funktioniert das aber nicht.
Ich habe keine oder nur wenig Probleme, wenn ich den Encoder langsam drehe. Erst bei schnellen Drehungen verschluckt er sich.
Ich habe bei mir mal die Änderung RISING statt CHANGE in der Interruptsteuerung ausprobiert. Dann erkennt er aber erwartungsgemäß in eine Richtung nur jeden zweiten Schritt. Wahrscheinlich prellt dein Encoder mehr wie meiner und du hast durch das Prellen immer eine RISING Flanke.