Treppenlicht mit I2C

Hallo Freunde,

nun das ist meine erster Beitrag hier, sollte ich mich komisch ausdrücken ... seht es mir nach. Ich bin ein Frischling in Sachen Arduino aber programmiere schon seit 20 Jahren in Perl und verdiene auch mein Geld damit.

UPDATE: Wurde inzwischen realisiert (Unwegbarkeiten und Unsicheres: Stairlight 1.0)

Kommen wir aber zu meinem ersten Projekt. Ich habe mir einige Anleitungen für "Treppenlichter" angesehen und diese sehen meist auch toll aus. Ich wollte aber einen anderen Weg gehen und mich näher mit I2C beschäftigen. Ein Treppenlicht bietet sich da förmlich an, hier also mein Plan:

Steuerung(Arduino nano) --> I2C Bus:

I2C_1 ATtiny85 mit Drucksensor (FSR) und Lichtsensor
I2C_2 ATtiny85 mit Nachbau BlinkM Modul
I2C_X ATtiny85 mit Nachbau BlinkM Modul
I2C_14 ATtiny85 mit Drucksensor (FSR)

Die Treppe besteht aus 13 Stufen, also benötige ich 13 I2C Devices die mit der Firmware von BlinkM arbeiten. Plus 2 Devices, die ermitteln ob die erste oder letzte Stufe betreten wurde sowie ein Lichtsensor. Hier wurden auch schon Leiterplatten mit Fritzing erstellt und in Auftrag gegeben. Die ATtinys selber werden ja immer billiger, ich habe mich für den ATtiny85 entschieden. bei 0.80 Euro braucht man da nicht mehr nachdenken 8)

Das Hauptprogramm wird noch geschrieben, ich habe aber einige Fragen zu I2C:

  • Welche Software oder Module kann ich bei den Drucksensoren als I2C Slave einsetzen? Es scheint ja einige Module zu geben (Wire, TinyWire, ...)
  • Kann man im Arduino mehr als ein Modul für die I2C Kommunikation einsetzen,also Wire und TinyWire gleichzeitig um verschiedene Devices anszusprechen ...
  • im Grunde muss ich die Drucksensoren alle 100ms abfragen, gibt es ein kleines Beispiel für die Software auf dem ATtiny mit dem Drucksensor. Im Grunde liest der nur die Werte auf Anfrage aus und schickt diese zum I2C Master ...

Falls Interesse besteht, würde ich hier alles dokumentieren :wink:

cu
Frank

Hi,
mh, wenn ich das soweit richtig verstanden hab, dann sieht das ganze wie folgt aus:
ATiny holt sich analoge/digitale Daten vom Sensor
ATiny setzt die Daten auf I2C um und sendet sie an den Arduino

•Welche Software oder Module kann ich bei den Drucksensoren als I2C Slave einsetzen? Es scheint ja einige Module zu geben (Wire, TinyWire, ...)

Für den Arduino würde ich Wire nehmen, hat bei mir bisher (fast) immer tadellos funktioniert (nur nicht in Timer ISR) und für die ATiny´s TinyWire.

•Kann man im Arduino mehr als ein Modul für die I2C Kommunikation einsetzen,also Wire und TinyWire gleichzeitig um verschiedene Devices anszusprechen ...

Beide Bibliotheken machen genau das selbe, nur das sie für unterschiedliche Zielsysteme (Microcontroller)sind. Daher einsatz beider irgendwie total sinnlos.

•im Grunde muss ich die Drucksensoren alle 100ms abfragen, gibt es ein kleines Beispiel für die Software auf dem ATtiny mit dem Drucksensor. Im Grunde liest der nur die Werte auf Anfrage aus und schickt diese zum I2C Master ...

Wenn du mir verrätst wie der Sensor heißt, dann könnte ich dir auch ein kleines Beispiel geben....
Die frage ist dann natürlich auch auf was du optimieren möchtest, geringe Busauslastung oder schnelle Verfügbarkeit der Werte.

Noch eine Anmerkung zum I2C:
Der I2C ist kein Feldbus, dh. er ist eigentlich nur zum übertragen von Daten innerhalb eines Gerätes gedacht.
Definiert ist das ganze über die Leitungskapazität, welche 400pF nicht überschreiten darf/soll! Terminierung und Kapazitäten – I2C Bus
Bei deiner Anwendung also wahrscheinlich definitiv im Grenzbereich, was nicht heißt das es nicht funktioniert.
Zur gibt´s da auch noch Trick´s wie Pegelwandler, Busextender usw.

MfG Jago

Jago:
mh, wenn ich das soweit richtig verstanden hab, dann sieht das ganze wie folgt aus:
ATiny holt sich analoge/digitale Daten vom Sensor
ATiny setzt die Daten auf I2C um und sendet sie an den Arduino

Genau so habe ich es mir vorgestellt :wink:

Wenn du mir verrätst wie der Sensor heißt, dann könnte ich dir auch ein kleines Beispiel geben....
Die frage ist dann natürlich auch auf was du optimieren möchtest, geringe Busauslastung oder schnelle Verfügbarkeit der Werte.

Die Werte sollten schnell verfügbar sein, ich glaube die Busauslastung können wir erst einmal ausser Acht lassen. Der Sensor ist ein einfacher "Drucksensor Fsr-402" ... Hier ein Beispiel: FSR. Vielen Dank im voraus :wink:

Der I2C ist kein Feldbus, dh. er ist eigentlich nur zum übertragen von Daten innerhalb eines Gerätes gedacht.
...
Zur gibt´s da auch noch Trick´s wie Pegelwandler, Busextender usw.

Darüber habe ich mir auch schon Gedanken gemacht, wie du aber in dem (ziemlich spannenden) Artikel sehen kannst, ist eine Menge möglich: http://sjalbers.nl/Atmel/BlinkM/BlinkM.htm

Hier wurde folgender IC verwendet: http://sjalbers.nl/Atmel/BlinkM/PCA9512AD.pdf

Möglich ist viel mit I2C, das steht außer frage, nur Normgerecht ist das alles nicht. Das längste was ich bisher gelesen hab war irgendwo zwischen 100m und 300m (allerdings mit CAT 5 Leitung, erhöhte Busspannung, niedrige Taktung usw.) Ich persönlich mag den I2C weil er so schön einfach ist und ich keine zusätzlichen Bauteile brauch, was natürlich nicht mehr der Fall ist wenn man sich außerhalb der Normung bewegt. Da du nur Microcontroller ansprechen willst, kann man zur Not ja auch noch auf einen anderen Bus umbauen ohne die Hardware großartig zu ändern. (Bin selbst grad am überlegen ob ich einen eigenen seriellen Bus entwickle. Soll in Richtung ASI-Bus gehen, nur Byteorintiert anstatt Bit. Ziel ist nur zwei Leitungen zu haben Gnd und Versorgungsspannung mit aufmodulierten Signal (Menchestercode))
Werd dir heut abend mal ein Beispiel schreiben, kann grad nicht deine Links öffnen (warum kannst du dir denken... :roll_eyes:)
MfG Jago

PS: Den PCA9512A kannte ich noch garnicht, hab immer den ADuM1251ARZ verwendet. Deiner ist aber wesentlich günstiger (was auch klar ist, beim ADuM steckt noch eine galvanische Trennung drin).

Ach ja, gefährliche sache mit dem Halbwissen...
Könntest du mir den Link zur der ATiny I2C Bibliothek geben? Die ich im Kopf hatte arbeitet mit 1 bzw 8MHz....
Das die I2C Schnittstelle beim ATiny85 keine "echte" ist hast du bemerkt? (Wusste ich bisher nicht. Könnte zu Problem führen, ich denk da an Clockstretching und ähnlichen gemeinheiten. Hab selbst mal versucht einen Software I2C zu erstellen und bin damit gescheitert)
MfG Jago

Jago:
Ach ja, gefährliche sache mit dem Halbwissen...
Könntest du mir den Link zur der ATiny I2C Bibliothek geben? Die ich im Kopf hatte arbeitet mit 1 bzw 8MHz....

Ich bin etwas verwirrt, die einzige Bibliothek die ich jetzt kenne ist die TinyWire. Da du keine Links aufrufen kannst, hier als Attachement. Wegen den 8Mhz, da hat der Autor folgendes unter Arduino Playground - USIi2c geschrieben:

By default the I2C master library (TinyWireM) is set to run at 1MHz. To run at 8MHz, #defines in USI_TWI_Master.h / .cpp must be changed. No changes are necessary for the I2C slave library (TinyWireS).

Ich hoffe das hilft dir ein wenig weiter, ich werde mich auch mal am Wochenende daran setzen :wink:

cu
Frank

TinyWireM.zip (14.6 KB)

TinyWireS.zip (8.36 KB)

Warum eigentlich große Distanzen mit einem nicht dafür ausgelegten Bussystem überbrücken? Dafür gibt es wesentlich flexiblere Busse wie z.B. CAN oder EIB... nur weil billiger, da schon integriert? ich glaube nicht dass man mit nem i²c-Bus ohne zusätzliche hardware auf Distanzen von mehreren Metern kommt, eher noch im cm-Bereich...

Nachtrag: Hab hier mal eine interessante Aufstellung der verschiedenen Busvarianten gefunden - unter anderem auch den I²C als Hausbus... anschleinend gibt es Treiber, die Kabellängen um die 100m ermöglichen.
http://www.mikrocontroller.net/articles/Hausbus#Vergleich_von_Hausbussystemen

Also, I2C ist für mein Projekt perfekt. Die kette ist maximal 3m lang und es werden ca. 15 Devices angesprochen. Wenn ich später den zweiten Stock dazuschalten will, kann ich den I2C Bus mit einem Treiber sowie 15 Devices ohne Probleme erweitern.

Also was soll gegen I2C sprechen? :wink:

Die maximale Leitungslänge hängt ja auch von der Geschwindigkeit des Busses ab. Ich denke, wenn man sich im Standard Mode (vgl. I2C-Spezifikationen, 100 kHz) bewegt, lassen sich auch mit Leitungslängen bis 5m realisieren.

So, hier jetzt das versprochene Beispiel (alles ungetest!!!):

//Für Arduino/Master:

#include <wire.h>

void setup () {
wire.begin();
}

void loop (){

byte Puffer [10];
byte i = 0;

Wire.beginTransmission (Slaveadesse); //Sensordaten vom Slave anfordern
Wire.write (Daten); //irgendein Wert den der Slave so versteht das er den Sensor auslesen soll
Wire.endTransmission

delay(5); //dem Slave Zeit geben um die Anfrage zu bearbeiten

Wire.requestFrom(Slaveadresse,2); //High und Low Byte vom Slave anfordern

while (Wire.available){
Puffer [i] = Wire.read();	//Byte auslesen, High und Low Byte müssen noch zusammengefügt werden 
}

//zweiten Slave auslesen

//Daten auswerten 

Wire.beginTransmission (Slaveadesse);
Wire.write (Daten); //irgendein Wert den der Slave versteht
Wire.endTransmission

delay (100);
}




//Für Slave / ATiny:

#include <TinyWireS.h>

void Setup () {
TinyWireS.begin (Slaveadresse);
}

void loop(){
byte Rec;
int Wert;

if (TinyWireS.available()){  //"Warten" bis Slave von Master angesprochen wird und egal 
			  //welcher Wert gesendet wird, der Slave schickt den Sensorwert zurück 
 Rec = TinyWireS.receive();
 Wert = analogRead(AnalogPin); //hier würde sich auch anbieten den 10bit-Wert auf 8bit Auflösung zu reduzieren
 TinyWireS.send(byte(Wert & 0xFF)); //Lowbyte senden
 TinyWireS.send(byte(Wert >> 8)); //Highbyte senden
}
}

@Marcus W: Was heißt hier nur weil billiger? Hier gehts ja nicht um ein paar Prozent günstiger! Zwischen I2C und EIB Geräten liegt einfach mal locker Faktor 10 bis 20! Bei CAN weis ich das nicht genau, was ich gesehen hatte war aber auch nicht wirklich im einstelligen Euro Bereich. Sicher hat alles seine Gründe, möchte da auch keine Diskusion in die Richtung starten. Wo ich dir natürlich recht geben muss, wenn man nur unter uC Daten überträgt kann man auch ander Bussysteme kostenneutral verwenden (oder man denkt sich selbst ein Protokoll aus ^^). Ich geh aber mal davon aus das da vielleicht auch mal andere I2C Geräte angeschlossen werden sollen :wink:

Jago:
So, hier jetzt das versprochene Beispiel (alles ungetest!!!):

Vielen Dank, das du daran noch gedacht hast. Ich werde das am Wochenende ausprobieren. laut "Wire" kann ich ja als Daten einfach nur einen integer Wert schicken, so wie ich es verstehe geht es ja nur darum dem Slave ein Signal zu schicken, das er den Wert des FSR rausrücken soll, richtig?

Aus der Diskussion wegen I2C halte ich mich mal raus, ich habe aber eine menge Artikel gelesen wo mit der entsprechenden Geschwindigkeit auf dem Bus durchaus mehrere 100 Meter Leitung möglich sind:

http://www.mikrocontroller.net/topic/71426

cu
Frank

Gerade bei diesem Link wird der I²C - wie von mir vorgeschlagen - auf CAN umgesetzt... noch dazu mit einer Wandlerplatine die pro Gerät knapp 20€ kostet :wink:

@xpix: Für mein Beispiel magst du recht haben das du nur irgendwas schicken musst. Aber bei deiner Anwendung wirst du konkrete Werte brauchen, da du dem ATiny sagen musst ob er nun den Sensor auslesen soll oder die LED schalten.
Ob die Funktion Wire.write den Datentyp Integer annimmt weis ich nicht, müsste man ggf untersuchen (zulässig sind char, byte und string/chararray mit Stringbegrenzer). I2C ist ursprünglich nur zum senden von einem Byte vorgesehen gewesen (Startbit Adresse Ack-Bit Datenbyte Stopbit ACK-Bit), später wurde dann das senden mehrer Bytes ohne vorangestellte Adresse hinzugefügt. Dh will wahrscheinlich die Funktion nur Bytes sehen, würde ich vermuten.

@Marcus: Mh, ganz sicher bin ich mir jetzt nicht wie du deinen Post meinst, mir wären 20€ aber zuviel (15 x 20€ = 300€ !!!!). Wenns mit dem I2C nicht klappen sollte würde ich aber dem nicht auf CAN gehen. Jedenfalls nicht wenn ich unter uC Daten übertragen will. Für ein Differenzsignal brauch ich zusätzliche Hardware, wenn ich meine Daten Manchestercodiert übertrage kann ich darauf verzichten und brauch keinen Cent mehr ausgeben.
Letztendlich hat xpix aber recht, die ganze Diskussion bringt nichts. Man müsste beide Lösungen ausarbeiten um zu sagen was nun besser ist, so ist doch alles nur Spekulation und Bauchgefühl(wobei natürlich ein paar Eckpunkte klar sind).

Vielleicht hat xpix am WE ein wenig Zeit und kann das ganze mal simulieren. Einfach mal 5m Leitung dazwischen und schauen ob es noch geht.

Hab übrigens noch was gefunden. Eine cat5-Leitung hat ca. 50pF je m und bei einer Busfrequenz von 100kHz sind 400pF zulässig. Damit beträgt die maximale Leitungslänge 4m, da xpix nur 3m braucht ist alles schön und schick. Störeinstrahlung wird ja wahrscheinlich nicht so das Thema sein, dh. denk mal das man auch Leitungen mit geringerer Kapazität findet (hab noch Stegleitung herumliegen wo die Leiter 5mm auseinander sind, denk mal die kommt unter 10pF).

Ich mein schon auch, dass 20€ zuviel dafür ist :slight_smile:

Jago:
@xpix: Für mein Beispiel magst du recht haben das du nur irgendwas schicken musst. Aber bei deiner Anwendung wirst du konkrete Werte brauchen, da du dem ATiny sagen musst ob er nun den Sensor auslesen soll oder die LED schalten.

Ich hab mal deine Beispiele so umgeschrieben, das sie durch den Compiler laufen. Ich muss mich noch ein wenig mit "Bit Mathe" beschäftigen :wink: Jedenfalls, die LED und Sensoren laufen alle getrennt auf jeweils einem I2C Device, deswegen ist das Signal erst einmal egal ... obwohl ... bei einem Device habe ich auch noch den Fotowiderstand, da muss er dann entscheiden. Sollte aber nicht so schwierig sein, das zu implementieren :wink:

Ich werd mal eine 3m (Pollin Flachbandkabel 4adrig) Leitung dazwischen hängen, mal sehen was passiert :wink:

@xpix: Wie gesagt, ungetestet... ...hab das Prog in Wordpad geschrieben.
Wenn du eine 4 adrige Leitung hast dann kannst du ja auch gleich mal 6m probieren. Würd mich nur mal so interessieren...
(aus kapazitätssicht ist die Verwendung der äußeren beiden Leiter garantiert auch sehr vorteilhaft)
Hab noch was gefunden, ist aber denk ich mal uninteressant für dich:
http://arduino.cc/forum/index.php/topic,68367.0.html

@Marcus: Na dann sind sich ja alle einig! Wunderbar! Weitermachen! 8)

Hallo zusammen

zu I2C und der Kabellänge kann ich einen kleinen Erfahrungsbericht beisteuern. In meinem "Newbi Projekt: Lüftersteuerung" bin ich vor dem Problem gestanden, einen I2C Themperatursensor anzusteuern, der auch ein paar meter entfernt vom UNO liegt. Try & Error hat mir keine Probleme aufgezeigt. Aktuell laufen durch den Kabelkanal neben den 2,5m Leitungen für den i2C auch noch 12V leitungen für die Lüfter und Messleitungen für 2 analoge Themperatursensoren.Alles 0,25mm²Elektroniklitze. Der Sensor lässt sich seit über 3 Monaten problemlos auslesen. Da dürften deine 3m kein Problem darstellen, noch dazu, wo du fast keine Leistung in der Nähe hast.Ich werde beim nächsten I2C Projekt meine alten CAT5 Kabel verbauen, dann haben die noch einen guten Zweck erfüllt (sind CAT5 STP) und ich werde (hoffentlich) keine Probleme bekommen.

Ich gebe den anderen Beitragsschreibern aber vollkommen Recht im Bezug auf die festgeschriebenen Spezifikationen und die Einhaltung der Grenzwerte.

Jago:
@xpix: Wie gesagt, ungetestet... ...hab das Prog in Wordpad geschrieben.

So, alles aufgebaut und was soll ich sagen, es funktionierte auf Anhieb. Hier mal ein Foto des Versuchsaufbau's und der Code für master und Slave. Auf dem Foto seht ihr den Arduino Nano sowie ein BlinkM Device sowie das I2C mit dem Drucksensor FSR 402. Das BlinkM hat in dem Aufbau erst einmal keine Funktion ... sobald man den Sensor betätigt bekommt man Werte bis 256 auf der Konsole.

//Für Arduino/Master:

#include <Wire.h>

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

void loop (){

  byte Puffer;
  byte i = 0;
  byte Daten = 1;
  int Slave = 4;

  Wire.beginTransmission(Slave); //Sensordaten vom Slave anfordern
  Wire.write(Daten); //irgendein Wert den der Slave so versteht das er den Sensor auslesen soll
  Wire.endTransmission();
  
  delay(5); //dem Slave Zeit geben um die Anfrage zu bearbeiten
  
  Wire.requestFrom(Slave, 2); //High und Low Byte vom Slave anfordern
  
  while (Wire.available()){
    Puffer = Wire.read();	//Byte auslesen, High und Low Byte müssen noch zusammengefügt werden 
    Serial.print("Receive: ");
    Serial.println(Puffer);
  }

  //zweiten Slave auslesen (in sub auslagern)
  //dritten Slave auslesen
  delay (100);
}
//Für Slave / ATiny:

#include <TinyWireS.h>

int Slave = 4; // Slave Adresse 
int AnalogPin = 2; // Port wo der FSB angeschlossen ist

void setup () {
  TinyWireS.begin (Slave);
}

void loop(){
  if (TinyWireS.available()){  //"Warten" bis Slave von Master angesprochen wird und egal 
    //welcher Wert gesendet wird, der Slave schickt den Sensorwert zurück 
    byte Rec = TinyWireS.receive();
    int Wert = analogRead(AnalogPin); 
    TinyWireS.send(byte(Wert & 0xFF)); //Lowbyte senden
    TinyWireS.send(byte(Wert >> 8)); //Highbyte senden
  }
}

Der Test mit den 3m sowie 6m kommt morgen dran, als Pullups konnte ich nur 5,2k einsetzen aber das sollte gehen.

Wie kann man eigentlich die Geschwindigkeit des Busses einstellen unter Wire?

Foto.JPG

Foto(1).JPG

Der Test mit den 3m sowie 6m kommt morgen dran, als Pullups konnte ich nur 5,2k einsetzen aber das sollte gehen.

Leider haben mich die Renovierung meines Hauses doch ein wenig mehr in Anspruch genommen, nun laut UPS kommen die ersten PCB's heute und dann werd ich den 6m Test etwas verschieben müssen. Aber es ist alles auf dem Weg :wink:

Na das freut mich doch das alles funktioniert hat!
Schöner Aufbau, mir gefällt vorallem der Gummi :smiley:
Wie man die Geschwindigkeit einstellt weis ich nicht. Vorgesehen ist in der Bibliothek nichts, soweit ich weis. Also müsste man mal ins Datenblatt schauen und das entsprechende Prescalerregister manipulieren (oder die Bibliothek umschreiben). Weis allerdings nicht wo das noch mit drin hängt. Könnt mir vorstellen das man da irgendeinen Timer mit beeinflusst und dann PWM, Millis oder micros "nicht mehr richtig" funktioniert.
5,2k sollte funktionieren, besser ist aber weniger (Stichwort umladen der Leitungskapazität). Ich bin garnicht sicher wo die Grenze war, glaube ein Kiloohm oder so.
Was meinst du mit PCB´s?
Das Problem mit dem Zeitmangel kenn ich, steck grad im Umzugsstreß....
MfG Jago