360 RotaryEncoder und 4051 Multiplexer

Kommt die Bibliothek mit dem Timer-Interrupt auch noch mit einem Multiplexer klar?

@Doc_Arduino
Du hast recht mit der I2C Verbindung wenn es nicht mit den Multiplexen klappt.

@DrDiettrich
Das werde ich noch testen.
Allerdings habe ich die Befürchtung das deine Zweifel berechtigt sind!
Sollte das nicht der Fall sein werde ich den Mega am Leonardo lassen das geht super mit I2C.

Deswegen den Encoder pollen. Allerdings sollten die A/B Signale möglichst zeitgleich abgefragt werden.

Ich habe versucht den Code zu vereinfachen von:

RotaryEncoder encoder0  (22,23, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder1  (24,25, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder2  (26,27, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder3  (34,35, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder4  (32,33, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder5  (30,31, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder6  (28,29, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder7  (42,43, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder8  (40,41, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder9  (38,39, RotaryEncoder::LatchMode::FOUR3);
RotaryEncoder encoder10 (36,37, RotaryEncoder::LatchMode::FOUR3);

zu:

int encoderPIN_1[] = {22,24,26,34,32,30,28,42,40,38,36};
int encoderPIN_2[] = {23,25,27,35,33,31,29,43,41,39,37};
int encoder[]      = { 0, 1, 2, 3, 4, 5, ,6 ,7 ,8 ,9 ,10};

for(byte i=0; i<11; i++)  {
RotaryEncoder encoder[i]  (encoderPIN_1[i],encoderPIN_2[i], RotaryEncoder::LatchMode::FOUR3);
} 

Leider mit mäßigen Erfolg.
Was muss ich da anders machen?

Hallo,

das Objekt encoder muss schon vorher bekannt sein. Die for Schleife ist vor setup nicht anwendbar. An der Stelle wären wiederum keine Objekte global anlegbar.
Was man noch kann ist ein Array von Objekten anlegen und darüber iterieren.

#include <RotaryEncoder.h>

RotaryEncoder encoderArray[] =
{
  { 2, 3, RotaryEncoder::LatchMode::FOUR3},
  {12,11, RotaryEncoder::LatchMode::TWO03},
  {36,37, RotaryEncoder::LatchMode::FOUR3}
};

void setup()
{
  Serial.begin(250000);
  while (! Serial);
  Serial.println("\nStart #### ####"); 
}

void loop()
{
  for (RotaryEncoder &i : encoderArray) 
  {
   i.tick();
  } 
}
1 Like

Hallo,

damit alle Daten zugehörig zusammenbleiben, muss wieder ein struct rein.
Was anderes fällt mir dazu nicht ein. Vielleicht gibts noch jemanden der andere Ideen hat?
Mit Zeigern ist immer so eine Sache. Habs nicht geprüft ob das unter allen Umständen sicher ist.

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.13
  avr-gcc 10.3.0
  Arduino Mega2560
  18.04.2021
  https://forum.arduino.cc/t/360-rotaryencoder-und-4051-multiplexer/849947/28
*/

#include <RotaryEncoder.h>

RotaryEncoder encoderArray[] =
{
  { 2, 3, RotaryEncoder::LatchMode::FOUR3},
  {12,11, RotaryEncoder::LatchMode::TWO03},
  {36,37, RotaryEncoder::LatchMode::FOUR3}
};
// ermitteln wieviel Objekte angelegt wurden, also wieviel Array Elemente angelegt wurden
const byte ANZAHLENCODER = sizeof(encoderArray) / sizeof(encoderArray[0]);

// Datentyp 'DatenEncoder' anlegen
struct DatenEncoder
{
  RotaryEncoder *enc;
  long oldPos;
  long newPos;
  int dir;
};

// Array 'encDaten' anlegen, so groß wie Anzahl der Encoderobjekte
DatenEncoder encDaten [ANZAHLENCODER];

void setup()
{
  Serial.begin(250000);
  while (! Serial);
  Serial.println("\nStart #### ####"); 

  // einmalig alle Objektaddressen zuweisen
  for (byte i=0; i<ANZAHLENCODER; i++) 
  {
    encDaten[i].enc = &encoderArray[i];
  }
}

void loop()
{
  for (auto &i : encDaten) 
  {
   i.enc->tick();
   i.newPos = i.enc->getPosition();
  } 
}
1 Like

Echt vielen dank!

Puhhh jetzt bin ich durch!

Es geht super allerdings habe ich jetzt keine Ahnung wie man die Arrays abruft!
Und der Wert bei DIR ist immer 0, allerdings muss ich an einer andern stelle die Dreh Richtung
wissen!

Hierbei versteh ich nur noch Bahnhof.
Ich bleibe bei deiner ersten Version etwas mehr Code allerdings kann ich damit arbeiten.

Ich danke euch!!!

Hallo,

ohne Direction Abfrage keine Werte. :wink:

i.dir = (int)i.enc->getDirection();

Weil die Richtungs Rückgabewerte enums sind muss man das vorher casten.

Wenn du mehrere Arrays miteinander in einer for behandeln möchtest, dann funktioniert die Bereichsbasierte for nicht. Dann müßte man die "klassische" for nehmen. Das musste ich einmal machen um die Objektadressen ins Array zubekommen. Das erspart im Nachgang dieses immer wieder tun zu müssen. Deswegen habe ich im letzten Bsp. den struct Datentyp DatenEncoder zusammengebaut. Damit werden im Array encDaten soviele erstellt wie Encoder vorhanden sind.

In den zugehörige struct Datentyp DatenEncoder kannste noch mehr Member definieren.
Bspw. dein MidiKanal. Alles was zu einem Encoder gehört. Abfrage und Zuweisung erfolgt wie bei den anderen.

Ich weiß das es etwas viel auf einmal ist. Du wolltest weiter vereinfachen. :grinning:

OK das mit der Direction Abfrage hätte ich sehen müssen beim anschauen der andern CODE Beispiele.

Den Array einbinden habe ich versucht :

// Datentyp 'DatenEncoder' anlegen
struct DatenEncoder
{
  RotaryEncoder *enc;
  long oldPos;
  long newPos;
  int dir;
  byte encoderControllerNummer[] =  {9 ,10,11,12,13,14,15,16,17,18,19};
};

Was ist mit den InterruptRotator soll ich den in deinen CODE einbinden oder lieber nicht?
Eine Begründung währe toll.

Den LimitedRotator konnte ich ohne Probleme in deine CODE einbinden:

void rotaryEncoder()
{
  for (auto &i : encDaten) 
  {
   i.enc->tick();
   i.newPos = i.enc->getPosition() * ROTARYSTEPS;
   i.dir = (int)i.enc->getDirection();

   if (i.newPos < ROTARYMIN) {
        i.enc->setPosition(ROTARYMIN / ROTARYSTEPS);
        i.newPos = ROTARYMIN;
    
      } else if (i.newPos > ROTARYMAX) {
        i.enc->setPosition(ROTARYMAX / ROTARYSTEPS);
        i.newPos = ROTARYMAX;
      } 

   if(i.newPos != i.oldPos)    
   {   
       Serial.print(" counts: ");
       Serial.print(i.newPos);
       Serial.print(" dir: ");
       Serial.println(i.dir);
       sendI2C(0, 10, i.newPos); 
       i.oldPos = i.newPos;
  } 
  }
}

Was soll denn die encoderControllerNummer darstellen?

Das Bsp. LimitedRotator ist ja nichts anderes, nur das im Code die Zählerwerte auf Limits überwacht werden.

Mit InterruptRotator haste noch eine Baustelle. In seinem Bsp. brauchst du dafür die Port Interrupts. Das heißt du müßtest mehrere Interrupt Routinen behandeln. Davon rate ich dir erstmal ab. Das könnte dein I2C beeinflussen. Möglicherweise.
Falls das Polling zu langsam ist, kann man immer noch darüber nachdenken. Aber dann eher ein Timer Interrupt worin man alle Encodersignale auf einmal abfragt. Falls noch eine Timer frei ist. Man möchte ja im zeitlichen Intervall die Signale abfragen und nicht auf ein Signal reagieren.

Eines sollte klar sein. Die ultimative Lösung gibts nicht. Man kann immer nur auf die Anforderung hin eine Lösung erstellen.

Also ich versende ja MIDI-Daten wie Pitchwheel, Noten oder CC = ControlChange alle befehle
haben 3 byte (byte command, byte firstData, byte secondData).

zB beim CC sind das MIDI-Kanal, ControllerNummer (Poti 1,2,3...), PotiWert.

Je nach Anwendung ändert sich der Kanal oder die Kontroller Nummer etc.

Der Kontroller hat 6 Bänke a 8 Regler:
Bank 1 (weiß) Encoder mit Taster
Bank 2-6 (blau bis lila) Potis

MIt Rot und Gelb werden die settings gesetzt. (LCD für das Menu muss noch angeschlossen werden über I2C).

Demzufolge gehört die ControllerNummer nicht zum Encoder. Demzufolge hat sie nichts im Daten struct des Encoders zu suchen. Dann haben wir uns falsch verstanden. Das struct dient dazu alle Daten die zu einem Encoder gehören zusammen zu halten. Damit muss man nicht Tausend einzelne Variablen erstellen wonach niemand mehr durchblickt.
Es beschreibt praktisch die Eigenschaften eines Encoders.
Zählerstand
Richtung
Taster (falls Taster dran oder zur Encoder Einheit gehört)

Anders gesagt, du musst überlegen was alles zu einem Encoder gehört bzw. zusammenhängt.

Zum Bild.
Sieht optisch erstmal gut aus. Sind das alles Potis oder alles Encoder oder bunt gemischt?

Ich habe mit Musik/Midi nichts am Hut. Aber Du siehst in den vielen Potis noch durch, was Du machst? Wenn ja, mein Respekt.

Gruß Tommy

Doch die gehören auch zum encoder(die weißen) alles in der DAW wird über MIDI gesteuert.
Also muss in die Struktur rein!!!

Weiß, Rot, Gelb sind Encoder der rest Potis.

@Tommy56 der ist noch klein. Und noch heftiger wir es bei einen Modularen Synthesizer

images

Allerdings kann ich mir das nicht leisten! Und muss leider den Sound simulieren.
Auch eine guten Kontroller kaufen als Familienvater no way!

Also selber machen.

Ich weiß noch nicht so recht wegen dem struct, aber man muss die Arraygöße mit angeben. Ermittelt der Compiler an der Stelle nicht automatisch. Wenn die Werte konstant bleiben, dann const machen. Was wir dabei gleich noch nachholen ist eine saubere Initialisierung der struct Member. Auf jeden Fall sollte der Zeiger sauber initialisiert werden.

// Datentyp 'DatenEncoder' anlegen
struct DatenEncoder
{
  RotaryEncoder *enc {nullptr};
  long oldPos {0};
  long newPos {0};
  int dir {0};
  const byte numberControler[11] = {9,10,11,12,13,14,15,16,17,18,19};
};
1 Like

Wenn ich die daten abrufe kommen bei der ControllerNummer falsche Werte.

Mein versuch mit:
sendI2C(encoderMidiKanal, i.encoderControllerNummer, i.newPos);

Liefert folgende Ausgabe:
Statt:
9 = -36
10 = -13
11 = 10
12 = 33
13 = 56
14 = 79
15 = 102
16 = 125
17 = -108
18 = -85
19 = -62

Serial.print(i.encoderControllerNummer); geht auch nicht!

Muss ich da erst was casten wie bei der Direction Abfrage?

Hallo,

überleg mal in Ruhe.
Frage: Was ist encoderControllerNummer?

byte encoderControllerNummer[] =  {9 ,10,11,12,13,14,15,16,17,18,19};

Antwort: Es ist ein Array vom Datentyp byte bestehend aus 11 Elementen.
Frage: Wie greift man auf diese Elemente zu?
Antwort: Über den Index.
Frage: Greifst du mittels Index auf diese Elemente zu?
Antwort: Nein.

Bevor ich dir irgendwie helfen kann, sollte ich wissen ob das überhaupt so gewollt ist wie dargestellt. Zu einem Encoder gehören 11 weitere Controller? Was genau sind diese Controller? Potis, ...? Was bedeuteten die Werte der Elemente im Arrays?
Gesetz den Fall das ist so wie gewollt. Würde bedeuten wenn du den Encoder abfragst, dann möchtest auch in einem Rutsch alle 11 zugehörigen Controller abfragen? Wo landen diese Werte der 11 abgefragten Controller?

1 Like