Mehr als 8 I2C Slaves an einen Arduino Uno

Guten Abend Community,

ich stehe mal wieder vor dem nächsten Problem.
Das letzte Problem habe ich nach einigen Anlaufschwierigkeiten und kleiner Hilfe einigermaßen elegant gelöst.

Jetzt steht unser Projekt allerdings vor einer weiteren Hürde.

Wir haben momentan an einem Arduino Uno über I2C 8 ICs zur Porterweiterung (mcp23017). Anfänglich dachten wir, dass wir damit auskommen werden, allerdings sind unsere Anforderungen enorm gestiegen. Zum Zeitpunkt würden wir 24 ICs benötigen.

Folgende Möglichkeiten haben wir uns ergooglt.

  1. Wir benutzen drei Unos (mit je 8 ICs) neben einander. Das Programm ist schon dafür umgeschrieben. Das Signal wird parallel an alle drei gesendet. Allerdings wahrscheinlich die teuerste Variante, sehr platzraubend und elegant ist auch was anderes.

  2. Ein Multiplexer. Könnte man den über einfaches "high" durch einen analog Port an den Eingängen A0,A1,A2 umschalten?

  3. Ein Nand-Gatter das ebenfalls über die analoge Ausgänge die SCL Leitungen schaltet. Könnte das funktionieren?

  4. Eine Lösung mit softi2c. Damit kennen wir uns überhaupt nicht aus und übersteigt unsere C Kenntnisse um ein vielfaches.

Vielleicht hat jemand eine Idee für die Lösung des Problems.

  1. Ein Nand-Gatter das ebenfalls über die analoge Ausgänge die SCL Leitungen schaltet. Könnte das funktionieren?

Nein. I2C ist bi-direktional. Deshalb die speziellen Multiplexer ICs

MarFried37:
2. Ein Multiplexer.

Das dürfte die einfachste Lösung sein.

Eventuell können auch Schieberegister verwendet werden, PI/SO für Eingänge und SI/PO für Ausgänge. Pins lassen sich damit aber auch kaum einsparen, gegenüber der Expander-Lösung.

Du kannst auch einen anderen Port Expander nehmen zB den PCA9555 und bis zu 8 von diesen dazuschalten. Aber dadurch habt ihr auch keine 24 Port Expander.

Andererseits kann es sein daß der Bus nicht soviele Geräte verkraftet (Last der Eingänge und Kapazität der Leitungen) und darum ein I2C Multiplexer die bessere Lösung ist. Beacht auch die Geschwindigkeit des Busses, daß dieser mit 24 Geräten nicht zu langsam ist.

Andererseits was macht Ihr mit 384 Ein/Ausgangspins?

Eklähr mal Euer Projekt sodaß wir Euch eine andere Lösung raten können.

Grüße Uwe

ich kann mir auch nicht vorstellen, wozu man so viele Ein-/Ausgänge brauchen sollte. Alternativ würde ich von den I2C Portexpandern umsteigen auf Schiebe-Register. Davon kann man theoretisch beliebig viele hintereinander hängen (von Zeit zu Zeit ist dann nur ein Leitungstreiber notwendig) oder in verschiedenen "Zweige" aufteilen.

Dann versuche ich mal das Projekt zu umreißen.

Wir arbeiten an einer realistischen Stellwerk Simulation. Die vier Hauptbestandteile sind das Stellpult, die Modellbahn, der Simulationsrechner und ein Tastenpult der Zugaufsicht (das heißt bestimmt anders, aber ich bin nicht mit der Materie vertraut).

Modelbahn, Stellpult, Tastenpult und Rechner kommunizieren pausenlos über eine COM-Verbindung (und mehrere µC) mit einander über Gleisfreimeldungen, Weichenstellungen, Tastendrücke, usw... Die Schnittstellen sind momentan nur simuliert vorhanden, aber sollten in der nächsten Woche fertig gestellt werden.

Das Stellpult sendet mittels USB-Tastatur-Treiber Signale an den Rechner, je nachdem welcher der 60 Taster gedrückt wird (funktioniert). Auf dem Stellpult sind 110 Lämpchen (eventuell kommen noch mehr dazu) die Anzeigen welche Weiche gestellt ist, welches Gleis frei ist, welches Signal geschaltet ist, usw...
Ein µC hört im ganzen Netzwerk nur zu und filtert alle Datentelegramme heraus die für ihn uninteressant ist.

Empfängt er ein Telegramm, werden bestimmte Lampen auf dem Pult geschaltet. Da die Lampen 24V benötigen, wird noch ein Treiber davor gelötet (funktioniert).
Das Telegramm enthält 2 hex Ziffern mit deren Hilfe wir jede mögliche Kombination der 8Bit senden können. Ein FF (255 oder 1111 1111) würde alle 8 Pins an Port A auf high setzen eine 00 auf low.
Insgesamt haben wir 36 verschiedene Signaltafeln, die über 8Bit Codes verändert werden können. Eine Signaltafel kann aus 7 Lampen bestehen, aber auch nur aus 2. Je nachdem was es für eine Signaltafel ist. Allerdings muss jeder einzelne Lampe jederzeit unabhängig geschaltet werden. Ein zusammenschieben, dass mehrere Signaltafeln an einem Port liegen, hat nicht funktioniert.
Am Telegramm können wir leider nichts ändern, sodass wir davon abgekommen sind, eine Lampe an einen Pin zu hängen.

Mit einem Arduino UNO können wir über I2C 16 verschiedene Signaltafeln ansteuern, was auch wunderbar mit LEDs funktioniert. Mit drei Arduino UNOs wären es 48, damit hätten wir sogar noch ein wenig Puffer.

Code für die Ausgabe der hex-Zahlen:

void ausgabe(byte dec, byte hex){                                     // Beginn Ausgabe Funktion
    byte adresse, seite;

    adresse =  (dec / 2) + 32;                                                     // Adresse Baustein
    seite = (dec % 2) + 18;                                                         // Adresse Port
                 Wire.beginTransmission(adresse);                               // Übergabe Adresse Baustein
                 Wire.write(seite);                                                    // Übergabe Adresse Port   
                 Wire.write(hex);                                                      // Übergabe Wert 
                 Wire.endTransmission();  }                                        // Ende Verbindung Baustein

würde jeder einzelnen Signal-Tafel einen eigenen Controller spendieren und einen Dip-Schalter zum einstellen der Adresse. Dann jedes Modul einzeln per I2C ansprechen. So könnte man 255 unabhängige Module an einem Bus haben. Macht die Programmierung einfacher, da nur ein kleine Teilfunktion pro Controller ausprogrammiert werden muss. Zudem ist auch der Austausch im Fehlerfall wohl bedeutend einfacher. Die Programmierung für die einzelnen Module sollte dabei immer die gleiche bleiben können. Für die einzelnen Module reicht sogar ein kleiner Controller wie ein Tiny45 oder so. Zudem ein paar Schieberegister und fertig ist die ganze Schaltung. Der UNO muss dann nur noch die I2C Kommunikation überwachen was auch seine Programmierung einfacher und übersichtlicher macht.

Der ganze Ansatz wäre deutlich modularer, was sich positiv auf Planbarkeit, Wartbarkeit und Skalierbarkeit / Erweiterbarkeit auswirkt.

Ich fürchte, daß man mit so einer Verlagerung auf viele Controller Probleme mit dem I2C Bus bekommt. Verteilen ja, aber so daß ein Controller weiterhin mehrere Ein-/Ausgänge bedient.

versteh mich nicht falsch ... das soll ja auch in meinem Vorschlag so sein. Aber MarFried spricht von 36 "Signal-Tafeln". Ich sage ja nicht, dass man für jede LED einen eigenen Controller vorsehen soll ... aber für jede dieser Tafeln einer erscheint mir sinnvoll. Dieser "Tafel-Controller" wird dann mit Schieberegistern so weit erweitert, dass er alle benötigten Eingänge (z. B. für die Adress-DIP-Schalter) sowie Ausgänge (für die LED's) hat. So kommt man zu autonomen Baugruppen, die untereinander per I2C verbunden werden. Jede einzelne Tafel kann aber für sich alleine genommen aufgebaut, programmiert und geteset werden. Und wenn die Anlage später doch nochmal wächst, kommt einfach noch eine 37te, 38te ... Tafel dazu.

Es spricht nichts gegen Modularisierung an sich, nur muß man bei vielen Modulen möglicherweise auf einen Bus mit leistungsfähigeren Treibern umsteigen (CAN, Ethernet...).

Zumindest wäre es doch höchst unerfreulich, wenn alle Module einzeln funktionieren, aber zurletzt nicht so zusammengeschaltet werden können wie geplant.

auch da gebe ich Dir Recht und wenn ich selbst das Projekt umsetzen würde, würde ich auch eher einen RS485 basierten Bus nehmen. Grundsätzlich ist I2C bei den zu erwartenden Leitungslängen auch eher suboptimal - auch bei seinem jetzigen Ansatz. Aber hier muss man halt auch immer die Vorkentnisse des TO mit berücksichtigen.

Ich glaue die Modularisierung übersteigt meine momentanen Fähigkeiten :smiley:

Wieso ist der I2C suboptimal?

Wäre die Programmierung mit dem Multiplexer aufwendig? Oder könnte ich das Ansprechen der einzelnen Ausgänge über das direkte Ansprechen der A0,A1,A2 Ausgänge am Multiplexer machen?

switch (var){                                              
      case 'S': {
                digitalWrite(pin1, high);
                ausgabe(decwert, hexwert); }

      break;                     // Arduino1
      case 'W': {
                digitalWrite(pin2, high);
                ausgabe2(decwert,hexwert); }
      break;                  // Arduino2
      case 'G': {
                digitalWrite(pin3, high);
      ausgabe2(decwert,hexwert); 
      break;                 // Arduino3
      }

Suboptimal wegen der eingeschränkten Kabellänge zu den einzelnen Modulen.

Die von dir angesprochenen Adresspins sind zur Einstellung der Adresse des Multiplexers selber.

Ah ok schade, dh ich muss den Multiplexer mit meinem I2C Bus ansprechen. Also ein bisschen mehr in die Programmierung rein arbeiten.

Die I2C Kabel sind nicht so lang, sondern höchstens 30-50cm lang. Die µC und MCP kommen direkt hinten in das Stellpult

MarFried37:
Ah ok schade, dh ich muss den Multiplexer mit meinem I2C Bus ansprechen. Also ein bisschen mehr in die Programmierung rein arbeiten.

Die I2C Kabel sind nicht so lang, sondern höchstens 30-50cm lang. Die µC und MCP kommen direkt hinten in das Stellpult

Ja, der Multiplexer wird auch per I2C angesprochen.

Und die Kabellänge für dein I2C ist noch ok, evtl. musst du da die Pullup-Widerstände ein wenig kleiner machen.

I2C wurde ursprünglich entwickelt, um innerhalb eines Fernsehgerätes die Platinen zu vereinfachen. Das Problem ist, dass die max. Leitungskapazität (und damit indirekt die max. Länge) bei I2C begrenzt ist (wenn ich mich nicht irre auf 400pF). Daraus ergibt sich eine max. Leitungslänge von wenigen Metern. Man kann das etwas erweitern, indem man mit der Übertragungsrate runter geht, aber irgendwann wird die Signal-Qualität dann einfach zu schlecht.

Besser sind deshalb z. B. RS485 basierte Busse. Diese arbeiten elektrisch ganz anders und erlauben max. Buslängen von mehr als 1km. Hierbei ist die max. Anzahl der anschließbaren Busteilnehmer aber begrenzt auf 32 ... oder um wieder genauer zu sein: die Last, mit der der Bus belastet werden darf ist auf 32 sog. Loads begrenzt. Jetzt gibt es aber auch Bus-Bausteine für RS485 mit 1/4 (z. B. MAX487)oder gar nur 1/8 Load, so dass man dann theoretisch wieder bis zu 128 oder gar 256 Bausteine an einen Bus hängen kann.

MarFried37:
Die I2C Kabel sind nicht so lang, sondern höchstens 30-50cm lang. Die µC und MCP kommen direkt hinten in das Stellpult

Auch hier steckt wieder der Teufel im Detail: entscheidend ist die gesamte Bus-Länge ... also nicht nur die max. Länge von einem Teilnehmer zum anderen :wink:

Dieser Ansatz ist zwar möglich, aber wie gesagt in meinen Augen wenig sinnvoll, da sehr viele lange Leitungen von den MCP's zu den einzelnen Verbrauchern gelegt werden müssen an Stelle von nur 2 Adern für den Bus (+ ggf. Spannungsversorgung).

Momentan läuft ein Arduino mit 8 MCP über eine 10cm Leitung. Die MCP sind alle auf einer kleinen Lochrasterplatine.

Sollten wir das mit dem Multiplexer versuchen, wird die Leitung eventuell länger (30cm), da wir die die MCP Platinen nur hinter einander in das Schaltpult verbauen können. Oder eventuell stacken, wenn das mit der Höhe passt. Dann hätten wir 3x 10-15cm zwischen MCP-Multiplex-Arduino.

LiY Litze hat üblicherweise eine Kapazität von rund 120 pF/m. Damit verlässt Du theoretisch nach einer Gesamt-Bus Länge vom ersten bis zum letzten Teilnehmer inkl. aller Stichleitungen von rund 3,5 Meter den spezifizerten Bereich für I2C. Das heißt im Umkehrschluss aber nicht automatisch, dass es darunter problemlos funktioniert :wink:

Abhilfe könnte man ggf. mit sog. Busextendern (das ist nicht das gleiche wie Busexpander) schaffen. Damit sind dann auch größere Leitungslängen drin.

MarFried37:

  1. Wir benutzen drei Unos (mit je 8 ICs) neben einander. Das Programm ist schon dafür umgeschrieben. Das Signal wird parallel an alle drei gesendet. Allerdings wahrscheinlich die teuerste Variante, sehr platzraubend und elegant ist auch was anderes.

Die UNOs halte ich für Testaufbauten mit Steckbrett geeignet, sonst würde ich eher Nanos oder ProMinis nutzen. Ob man die in China kauft oder in Europa, ist Ansichtssache. Der ProMini benötigt noch ein Konverter Modul, wobei eins für alle reicht. Das spart auch COM-Ports im Rechner.

Diese Lösung kann man also durchaus elegant und preisgünstig gestalten.