Rotary Encoder auf anderen Wert-Bereich setzen

Hallo,
ich habe hier einen C&P Rotary Encoder Sketch. Der zählt von 0 bis 255 rauf und runter.

/*******Interrupt-based Rotary Encoder Sketch*******
by Simon Merrett, based on insight from Oleg Mazurov, Nick Gammon, rt, Steve Spence
*/

static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

void setup() {
  pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
  attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
  Serial.begin(115200); // start the serial monitor link
}

void PinA(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
  if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPos --; //decrement the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void PinB(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
  if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPos ++; //increment the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void loop(){
  if(oldEncPos != encoderPos) {
    Serial.println(encoderPos);
    oldEncPos = encoderPos;
  }
}

Ich möchte aber, das der nur von 0 bis 23 rauf und runter zählt.
In dieser Zeile wird erklärt, wie es gehen soll. Das kapiere ich aber nicht...

volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255

Kann mir einmal jemand erklären wie es gemacht wird?
Gruß und Dank
Andreas

SkobyMobil:
Ich möchte aber, das der nur von 0 bis 23 rauf und runter zählt.
In dieser Zeile wird erklärt, wie es gehen soll. Das kapiere ich aber nicht...

volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255

Kann mir einmal jemand erklären wie es gemacht wird?

Ich lese daraus, dass du hier den Wertebereich vergrößern kannst.

Wenn du ihn kleiner haben willst, musst du das durch begrenzen der Variable manuell machen.

Hallo,
wenn ich den > 255 mache kommt Mist raus.
setze ich den auf 24, dann fängt er mit 24 an- bei unter 0 zählt er 255 runter.
Wo bekommt er denn im Sketch die 255 her?
Gruß und Dank
Andreas

SkobyMobil:
Wo bekommt er denn im Sketch die 255 her?

Das nimmt er aus der "Byte-Variablen", die geht nur bis 255.

Ich würde unter void PinA()
versuchen

encoderPos --; //decrement the encoder's position count

durch encoderPos = (encoderPos +23)%24 ; //decrement the encoder's position count
ersetzen und unter PinB

encoderPos ++;

durch

encoderPos = (encoderPos +1)%24 ;

Die Modulo-Division schränkt encoderPos auf den möglichen Rest einer Division durch 24 ein-also 0..23.

Edit: Fehler berichtigt

Hallo,

kann man machen, nur springt das Ergebnis von Modulo bei weiter steigenden Encoderwert von 23 zurück auf 0 und wieder von vorn. Ob das gewollt ist weis ich nicht. Wäre vielleicht in einem Menü sinnvoll wenn man vom Ende gleich wieder an den Anfang springen möchte und nicht alle Seiten zurück blättern möchte.
Begrenzen wäre:
wenn encoderPos > 24 ?
dann encoderPos = 24

Theseus:
encoderPos --; //decrement the encoder's position count

durch encoderPos = (encoderPos -1)%24 ; //decrement the encoder's position count
ersetzen ...

Mein UNO ist da anderer Meinung:

byte encoderPos = 9;
byte zaehler = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
}

void loop() {
  if (zaehler < 20) {
    encoderPos = (encoderPos - 1) % 24;
    Serial.print(encoderPos);
    Serial.print("  ");
    zaehler++;
  } else {
    if (zaehler == 20) {
      Serial.println();
      zaehler++;
    }
  }
}

Ausgabe

Anfang
8 7 6 5 4 3 2 1 0 255 14 13 12 11 10 9 8 7 6 5
Oder macht der Typ vor dem UNO einen Fehler? (PICNIC = problem in chair, not in computer) :grin:

Alternative:

byte encoderPos = 9;
byte zaehler = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
}

void loop() {
  if (zaehler < 20) {
    if (encoderPos == 0) {
      encoderPos = 23;
    }else{
      encoderPos--;
    }
    Serial.print(encoderPos);
    Serial.print("  ");
    zaehler++;
  } else {
    if (zaehler == 20) {
      Serial.println();
      zaehler++;
    }
  }
}

Ausgabe

Anfang
8 7 6 5 4 3 2 1 0 23 22 21 20 19 18 17 16 15 14 13

Ich habe nicht an die Grenzen von Byte gedacht. Versuchs mal mit encoderPos = (encoderPos +23)%24

Theseus:
Versuchs mal mit encoderPos = (encoderPos +23)%24

Ausgabe:

Anfang
8 7 6 5 4 3 2 1 0 23 22 21 20 19 18 17 16 15 14 13

:sunglasses:

Hallo,
bin leider vor Montag nicht wieder im Haus. Ich probiere eure Vorschläge dann mal durch.
Jetzt läuft es so.
Sketch starten PosEnc 0
rechts drehen 0, 1, 2, 3...254, 255, 0, 1, 2....
links drehen 0, 255, 254, 253,...3, 2, 1, 0

Der Encoder hat 24 Rasterungen, ich möchte nur von 0, 1, 2,...22, 23, 0, 1, 2
oder 0, 23, 22, 21,...3, 2, 1, 0, 23
Also 0 bis 23 rauf und runter.
Man muß doch irgentwie auf diese 255 zugreifen können!?
Gruß und Dank
Andreas

SkobyMobil:
Man muß doch irgentwie auf diese 255 zugreifen können!?

Ja, wenn Du einen Sieben-Bit-Prozessor baust, dann geht es nur bis 127. Bei vier Bit wären es 15, bei fünf Bit 31. 23 ist nicht mit einer Zweierpotenz (-1) darstellbar, geht also nicht.

Arduino hat sich für übliche acht Bit entschieden, weshalb Zahlen von 0 bis 255 (28-1) darstellbar sind. Mit einem endlosen Inkrement ändert sich der Wert 0, 1, 2, 3 .... 253, 254, 255, 0, 1, 2 ... und so weiter. Willst Du einen anderen Wertebereich nutzen, mußt Du dies programmieren. Wie das geht, hat Dir Theseus schön gezeigt.

SkobyMobil:
Der Encoder hat 24 Rasterungen, ...

Hier steckt vermutlich das Mißverständnis. Ein Rotary Encoder erzeugt nur Impulse, die in der Drehrichtung unterschieden werden können. Anders als bei einem Drehschalter mit elektrisch unterscheidbaren Raststellungen gibt es für den Arduino keinerlei Informationen, wo sich der Encoder befindet oder wie viele Raststellungen Du beim Drehen pro Umdrehung spürst. Der Arduino kann nur Inkrementieren oder Dekrementieren unterscheiden und dementsprechend eine Variable verändern. In welchem Wertebereich sich diese Variable bewegt, mußt Du per Programmierung festlegen. Wie das geht ... Du weißt schon.

SkobyMobil:
Also 0 bis 23 rauf und runter.

Genau das tut der Vorschlag.

Dann will ich mal hoffen, diese Zeilen bringen Dir ein Aha-Erlebnis :slight_smile:

Als Maus müßtest Du bei mir sehr vorsichtig sein, ich stelle immer zwei Fallen zusammen auf.

Hallo,
HotSystems hatte ja schon angemerkt, das diese Zählerei zu Fuß erledigt werden
muss…
Ich hatte nur nach etwas elegantem gesucht, etwas das sich in die erste Funktion
schön einbetten läßt.

Die Geschichte mit Zähler ">" und Zähler "=" in "if" verpackt hatte ich vorher
schon probiert, hat mir aber nicht gefallen.

Mit dieser Bit & ByteSchieberei habe ich es nicht so. Vielleicht sollte ich mich
darum mal mehr kümmern.
Die Rasterung ist ein wenig unglücklich ausgedrück gewesen…
Vielleicht hätte man noch bemerken sollen, das diese Encoder High/Low Flanken
erzeugen, die ineinander greifen.

Diese Zeilen in dem Thread haben schon ein Aha-Erlebnis hervorgerufen. Ganz
besonders die Einzeiler von Theseus.

So in der Art hatte ich mit das vorgestllt, ohne viel gehampel elegant geändert.
Andreas sagt Danke schön- euch allen.
Gruß und Spaß
Andreas

P.S. wenn jemand etwas für einen Encoder sucht…
Dieser Sketch ist sauschnell. Man muss schon ziemlich am Encoder reißen, um ihn
aus den Tritt zubringen. Und- er braucht keine Lib.

Hallo,

ich nutze die Encoder Funktion von Peter Dannegger, die bringt nichts aus der Ruhe.
Hatte ich dir schon einmal verlinkt. Ich halte die für um Längen besser.
Interrupts kommen nur ins Spiel wenn Polling nicht reicht.
Die Eingänge muß man zeitgleich einlesen.
Deswegen könnte deine manchmal außer Tritt kommen, wenn das zeitlich nicht mehr paßt.

Wegen deinem 255 auf 24 runterbrechen Problem.

Wenn die Verteilung nicht gleich sein muß, dann teilste den Zähler vom Encoder durch 11.
Damit er erhälst du Werte zwischen und 0 und 23.
Teilst du durch 10, erhälst du Werte von 0 bis 25 mit besserer Verteilung.

Kannst auch die map Funktion verwenden.

const int Divisor = 10;
int a;

void setup() {
  Serial.begin(9600);

  for (int i=0; i<=255; i++)  {
    a = i/Divisor;       
    Serial.print(i); Serial.print(" / "); Serial.print(Divisor);
    Serial.print(" = "); Serial.println(a); 
  }

  Serial.println(); Serial.println();
  
  for (int i=0; i<=255; i++)  {
    a = map(i, 0, 255, 0, 24);       
    Serial.print(i); Serial.print('\t');
    Serial.print("... "); Serial.println(a);
  }
  
}


void loop() {

}

Hallo Doc,
ja da gibt es tausend Wege, die man mit einem Encoder beschreiten könnte.
Ich habe mir das Ding nur zum Ausgleich mitbestellt, wenn ich mit meinen
Projekten mal nicht weiter komme. So zum spielen.
Da der 24 Rasterungen hat, wollte ich auch von 0 bis 23 zählen können.
Das habe ich dank eurer Hilfe ja hinbekommen.
Jetzt habe ich für das Ding eine schöne Ausgangsposition auf der ich aufbauen
kann, zumal der noch einen Taster hat. Da läßt es sich bestimmt schön mit
fummeln.
Gruß und Dank
Andreas

Hallo
Ich heiße Jens und bin neu hier im Forum.
Ich habe gleich eine Frage zu Anfang.
Ich Versuche gerade einen Rotary Encoder der eigentlich aus einem Elektrischen Handrad stammt, zum Winkelmessen zu bewegen.
Es ist ein Encoder mit 100 Schritten, und er zählt mit meinem Scetch auch hoch und runter wie er soll.
Ich blicke nur nicht durch wie ich den Encoder Programieren muss damit er mir von 0 Grad bis 356,4 Grad in 3,6 Grad Schritten hoch zählt. Er soll Quasi bei 0 beginnen und bis 356,4 zählen, dann wieder auf 0 Springen und dann wieder von vorne. Beim wechseln der Drehrichtung einfach dann in die andere Richtung zählen.
Könnte mir vielleicht jemand am oben stehenden Sketch erklären wie ich das Programm für eine solche Zählweise umschreiben müsste?
Grüße aus dem Saarland
Jens

Warum verwendest du einen Uralt-Thread für ein Thema, welches doch ein anderes.

Bitte öffne einen neuen Thread mit geeigneter Themenüberschrift.
Dann wird dieser auch besser im Web gefunden.