I²C Pins umschalten

Moin,

ich möchte die i²C Pins umschalten.
Wie stelle ich das an?

Ich habe insgesamt 6 Stück BME 280 Sensoren.
Ich möchte zu Testzwecken die Werte von diesen 6 Sensoren mitloggen und schauen wie die Abweichungen der einzelnen Sensoren sind.
Dazu möchte ich also 6 dieser Sensoren an den I²C Bus anschließen.
Leider kann man bei den Sensoren nur zwischen 2 verschiedenen Adresse wählen.
"0x76" oder "0x77"

Nun habe ich jeweils 3 Stück auf "0x76" und 3 Stück auf "0x77" gejumpert.
Um nun die Werte von den 6 Sensoren zu bekommen möchte ich diese auf 3 unterschiedlichen I²C Bussen abfragen.
Die SCL Pins sind alle miteinander und mit D1 vom nodeMCU verbunden.
Die SDA Pins sind in drei Gruppen zusammengefasst und mit den Pins D2, D3 und D4 verbunden.

Im Sketch möchte ich dann nacheinander die Werte der beiden Sensoren auf dem Bus an Pin D2 abfragen.
Danach dann die Werte der beiden Sensoren auf dem Bus an Pin D3.
Und danach dann die Werte der beiden Sensoren auf dem Bus an Pin D4.

Ich muss also im Sketch die Pins für SDA umstellen.
Wie stelle ich das an?

Lieben Gruß,
Chris

Das geht mit einem I2C-Multiplexer.
Z.B. TCA9548A.

Geht das nicht viel einfacher per Software?
Ich habe folgendes gefunden:
Wire.begin([SDA], [SCL])

Ich weiss aber nicht wie/in welchem Format ich da die Pins angeben kann?!

Lieben Gruß,
Chris

Über welchen µC redest du?
Ein AVR wirds ja wohl nicht sein....

Bei welchem Prozessor?

Gruß Tommy

themanfrommoon:
Geht das nicht viel einfacher per Software?
Ich habe folgendes gefunden:
Wire.begin([SDA], [SCL])

Und was erwartest Du jetzt von uns?! Könntest Du vielleicht wenigstens verraten, WO Du das gefunden hast?!

themanfrommoon:
Ich weiss aber nicht wie/in welchem Format ich da die Pins angeben kann?!

Hast Du denn wenigstens schon mal ein bisschen probiert? Oder dort gelesen, wo Du's gefunden hast?

Gruß

Gregor

themanfrommoon:
Geht das nicht viel einfacher per Software?

Das wurde dir ja schon umfangreich beantwortet.
Also mir ist da bezgl. AVR auch nichts bekannt.

Moin,

nodeMCU / ESP8266

Mit der Wire.h Library

Hab ich zum Beispiel hier gefunden, gelesen, aber nicht wirklich verstanden :frowning:

oder auch hier:
https://learn.sparkfun.com/tutorials/esp8266-thing-hookup-guide/using-the-arduino-addon

Lieben Gruß,
Chris

themanfrommoon:
Moin,

nodeMCU / ESP8266

Mit der Wire.h Library

Hab ich zum Beispiel hier gefunden, gelesen, aber nicht wirklich verstanden :frowning:
https://github.com/esp8266/Arduino/issues/2607
oder auch hier:
ESP8266 Thing Hookup Guide - learn.sparkfun.com

Lieben Gruß,
Chris

Und in der Sparkfun-Beschreibung steht doch genau, was das heißt.
Du kannst die Pins selbst festlegen. Was aber nicht sagt, dass es mehrere sein dürfen.

Moin,

ja, das es geht scheint wohl so zu sein.
Aber das war ja auch nicht meine Frage, ob es geht, sondern wie es geht.
Zuerst habe ich mir die Adafruit_BME280.h Library installiert, und mir die Beispiele angeschaut.
...Da wird die I²C Adresse und auch nicht die Pins für den I²C Bus definiert, bzw. die sind in der Library hardcoded. Da ich im Sketch aber alle paar Sekunden diese Adressen umschalten will konnte ich damit so nichts anfangen.
Dann hab ich die BlueDot_BME280.h Library installiert, weil in der Beschreibung steht, das man zwei Sensoren auf einem I²C Bus abfragen kann. Das ist ja schon mal das halbe Ziel. Das funktioniert auch soweit.
Aber in dem Beispielsketch kommt nirgendwo Wire.begin() vor.
An der Stelle hätte ich dann angreifen wollen, aber war nichts.

Hier das ausführliche Beispielsketch:

#include <Wire.h>
#include "BlueDot_BME280.h"
BlueDot_BME280 bme1;   //Object Sensor 1
BlueDot_BME280 bme2;   //Object Sensor 2
int bme1Detected = 0;  //Checks if Sensor 1 is available
int bme2Detected = 0;  //Checks if Sensor 2 is available
void setup() {
  Serial.begin(9600);
  Serial.println(F("Basic Weather Station"));
  //********BASIC SETUP - SAFE TO IGNORE********
  //This program is set for the I2C mode
    bme1.parameter.communication = 0;   //I2C communication Sensor 1 (bme1)
    bme2.parameter.communication = 0;   //I2C communication Sensor 2 (bme2)
  //********BASIC SETUP - SAFE TO IGNORE********
  //Set the I2C address of your breakout board  
    bme1.parameter.I2CAddress = 0x77;   //I2C Address Sensor 1 (bme1)
    bme2.parameter.I2CAddress = 0x76;   //I2C Address Sensor 2 (bme2)
  //********ADVANCED SETUP - SAFE TO IGNORE********
  //Now choose on which mode your device will run
  //On doubt, just leave on normal mode, that's the default value
  //0b00:     In sleep mode no measurements are performed, but power consumption is at a minimum
  //0b01:     In forced mode a single measured is performed and the device returns automatically to sleep mode
  //0b11:     In normal mode the sensor measures continually (default value)
    bme1.parameter.sensorMode = 0b11;   //Setup Sensor mode for Sensor 1
    bme2.parameter.sensorMode = 0b11;   //Setup Sensor mode for Sensor 2 
  //********ADVANCED SETUP - SAFE TO IGNORE********
  //Great! Now set up the internal IIR Filter
  //The IIR (Infinite Impulse Response) filter suppresses high frequency fluctuations
  //In short, a high factor value means less noise, but measurements are also less responsive
  //You can play with these values and check the results!
  //In doubt just leave on default
  //0b000:      factor 0 (filter off)
  //0b001:      factor 2
  //0b010:      factor 4
  //0b011:      factor 8
  //0b100:      factor 16 (default value)
    bme1.parameter.IIRfilter = 0b100;   //IIR Filter for Sensor 1
    bme2.parameter.IIRfilter = 0b100;   //IIR Filter for Sensor 2
  //********ADVANCED SETUP - SAFE TO IGNORE********
  //Next you'll define the oversampling factor for the humidity measurements
  //Again, higher values mean less noise, but slower responses
  //If you don't want to measure humidity, set the oversampling to zero
  //0b000:      factor 0 (Disable humidity measurement)
  //0b001:      factor 1
  //0b010:      factor 2
  //0b011:      factor 4
  //0b100:      factor 8
  //0b101:      factor 16 (default value)
    bme1.parameter.humidOversampling = 0b101;   //Humidity Oversampling for Sensor 1
    bme2.parameter.humidOversampling = 0b101;   //Humidity Oversampling for Sensor 2
  //********ADVANCED SETUP - SAFE TO IGNORE********
  //Now define the oversampling factor for the temperature measurements
  //You know now, higher values lead to less noise but slower measurements
  //0b000:      factor 0 (Disable temperature measurement)
  //0b001:      factor 1
  //0b010:      factor 2
  //0b011:      factor 4
  //0b100:      factor 8
  //0b101:      factor 16 (default value)
    bme1.parameter.tempOversampling = 0b101;   //Temperature Oversampling for Sensor 1
    bme2.parameter.tempOversampling = 0b101;   //Temperature Oversampling for Sensor 2
  //********ADVANCED SETUP - SAFE TO IGNORE********
  //Finally, define the oversampling factor for the pressure measurements
  //For altitude measurements a higher factor provides more stable values
  //On doubt, just leave it on default
  //0b000:      factor 0 (Disable pressure measurement)
  //0b001:      factor 1
  //0b010:      factor 2
  //0b011:      factor 4
  //0b100:      factor 8
  //0b101:      factor 16 (default value)  
    bme1.parameter.pressOversampling = 0b101;   //Pressure Oversampling for Sensor 1
    bme2.parameter.pressOversampling = 0b101;   //Pressure Oversampling for Sensor 2 
  //********ADVANCED SETUP - SAFE TO IGNORE********
  //For precise altitude measurements please put in the current pressure corrected for the sea level
  //On doubt, just leave the standard pressure as default (1013.25 hPa);
    bme1.parameter.pressureSeaLevel = 1013.25;   //default value of 1013.25 hPa (Sensor 1)
    bme2.parameter.pressureSeaLevel = 1013.25;   //default value of 1013.25 hPa (Sensor 2)
  //Also put in the current average temperature outside (yes, really outside!)
  //For slightly less precise altitude measurements, just leave the standard temperature as default (15°C and 59°F);
    bme1.parameter.tempOutsideCelsius = 15;   //default value of 15°C
    bme2.parameter.tempOutsideCelsius = 15;   //default value of 15°C
    bme1.parameter.tempOutsideFahrenheit = 59;   //default value of 59°F
    bme2.parameter.tempOutsideFahrenheit = 59;   //default value of 59°F
  //********ADVANCED SETUP IS OVER - LET'S CHECK THE CHIP ID!********
  if (bme1.init() != 0x60)
  {    
    Serial.println(F("Ops! First BME280 Sensor not found!"));
    bme1Detected = 0;
  }
  else
  {
    Serial.println(F("First BME280 Sensor detected!"));
    bme1Detected = 1;
  }
  if (bme2.init() != 0x60)
  {    
    Serial.println(F("Ops! Second BME280 Sensor not found!"));
    bme2Detected = 0;
  }
  else
  {
    Serial.println(F("Second BME280 Sensor detected!"));
    bme2Detected = 1;
  }
  if ((bme1Detected == 0)&(bme2Detected == 0))
  {
    Serial.println();
    Serial.println();
    Serial.println(F("Troubleshooting Guide"));
    Serial.println(F("*************************************************************"));
    Serial.println(F("1. Let's check the basics: Are the VCC and GND pins connected correctly? If the BME280 is getting really hot, then the wires are crossed."));
    Serial.println();
    Serial.println(F("2. Did you connect the SDI pin from your BME280 to the SDA line from the Arduino?"));
    Serial.println();
    Serial.println(F("3. And did you connect the SCK pin from the BME280 to the SCL line from your Arduino?"));
    Serial.println();
    Serial.println(F("4. One of your sensors should be using the alternative I2C Address(0x76). Did you remember to connect the SDO pin to GND?"));
    Serial.println();
    Serial.println(F("5. The other sensor should be using the default I2C Address (0x77. Did you remember to leave the SDO pin unconnected?"));
    Serial.println();
    while(1);
  }
  Serial.println();
  Serial.println();
}
//********NOW LET'S START MEASURING********
void loop() {
  Serial.print(F("Duration in Seconds:  "));
  Serial.println(float(millis())/1000);
  if (bme1Detected)
  {
    Serial.print(F("Temperature Sensor 1 [°C]:\t\t")); 
    Serial.println(bme1.readTempC());
    Serial.print(F("Humidity Sensor 1 [%]:\t\t\t")); 
    Serial.println(bme1.readHumidity());
    Serial.print(F("Pressure Sensor 1 [hPa]:\t\t")); 
    Serial.println(bme1.readPressure());
    Serial.print(F("Altitude Sensor 1 [m]:\t\t\t")); 
    Serial.println(bme1.readAltitudeMeter());
    Serial.println(F("****************************************"));    
  }
  else
  {
    Serial.print(F("Temperature Sensor 1 [°C]:\t\t")); 
    Serial.println(F("Null"));
    Serial.print(F("Humidity Sensor 1 [%]:\t\t\t")); 
    Serial.println(F("Null"));
    Serial.print(F("Pressure Sensor 1 [hPa]:\t\t")); 
    Serial.println(F("Null"));
    Serial.print(F("Altitude Sensor 1 [m]:\t\t\t")); 
    Serial.println(F("Null"));
    Serial.println(F("****************************************"));   
  }
  if (bme2Detected)
  {
    Serial.print(F("Temperature Sensor 2 [°C]:\t\t")); 
    Serial.println(bme2.readTempC());
    Serial.print(F("Humidity Sensor 2 [%]:\t\t\t")); 
    Serial.println(bme2.readHumidity());
    Serial.print(F("Pressure Sensor 2 [hPa]:\t\t")); 
    Serial.println(bme2.readPressure());
    Serial.print(F("Altitude Sensor 2 [m]:\t\t\t")); 
    Serial.println(bme2.readAltitudeMeter());
  }
  else
  {
    Serial.print(F("Temperature Sensor 2 [°C]:\t\t")); 
    Serial.println(F("Null"));
    Serial.print(F("Humidity Sensor 2 [%]:\t\t\t")); 
    Serial.println(F("Null"));
    Serial.print(F("Pressure Sensor 2 [hPa]:\t\t")); 
    Serial.println(F("Null"));
    Serial.print(F("Altitude Sensor 2 [m]:\t\t\t")); 
    Serial.println(F("Null"));
  }
   Serial.println();
   Serial.println();
   delay(1000);
}

themanfrommoon:
Hier das ausführliche Beispielsketch:

...

int bme1Detected = 0;  //Checks if Sensor 1 is available
int bme2Detected = 0;  //Checks if Sensor 2 is available
...

Au weia. Kann mir mal jemand sagen, wieso man für eine ja/nein-Info ein int verwendet?! Von Dingen/Leuten/Firmen/..., die so einen Scheiß programmieren, halte ich normalerweise möglichst großen Abstand.

Gruß

Gregor

Hallo,

warum kaufst du dann Arduino? Weil fast alle Bsp. mit int geschrieben wurden?

@TO:
Auch wenn ich die Hardwarelösung bevorzugen würde, wäre dein Stichwort "Software I2C". Beim umschalten I2C beenden und neu initialisieren. Sollte theoretisch funktionieren.

Doc_Arduino:
warum kaufst du dann Arduino? Weil fast alle Bsp. mit int geschrieben wurden?

Falls Du mich meinst: Ich kaufe Arduino, weil das Basteln damit so viel Spaß macht. Da ich schon vor rund 10 Jahren mit C/C++ angefangen habe, brauche ich fast nie irgendwelche Beispiele. Insofern ist mir wurscht, ob dort Integer oder Booleans für so einen Kram benutzt werden. Gerade in Beispielen, die als Start- oder Orientierungshilfe gegeben werden, sollte man doch wenigstens halbwegs ordentlich programmieren. Für einen ja/nein-Kram eine Integer-Variable zu benutzen halte ich für hochgradigen Pfusch und Stümperei.

Gruß

Gregor

PS/BTW: Ich habe mal auf die Schnelle nach Beispielcode gesucht, in dem für bool-Kram Integer benutzt werden. Ich habe keinen gefunden.

gregorss:
PS/BTW: Ich habe mal auf die Schnelle nach Beispielcode gesucht, in dem für bool-Kram Integer benutzt werden. Ich habe keinen gefunden.

weil bool ja auch kacke ist am AVR. Da kannst gleich ein uint8_t nehmen.

weil bool ja auch kacke ist

:o :o :o :o :o :o :o

combie:
:o :o :o :o :o :o :o

sags du mir, was ist das tolle an bool?

Was du an bool kacke findest, ist mir egal.
Und ob ich es toll finde, durfte dir egal sein.

Meine Ansicht:
Ich verwende Datentypen, und kreiere selber welche.
Aus dem einfachen Grund, weil ich dann "sehe" was drin ist.

Wenn ich eine Variable, oder was auch immer, als bool definiere, dann ist das selbsterklärend!
Diese Variable kann nur 2 Zustände annehmen.
Das sehe ich dann auf einen Blick.
Und jeder andere unbedarfte Leser ebenso.

Dein Vorschlag, statt bool doch uint8_t zu verwenden, ist aus dem Betrachtungswinkel völlig dämlich, absurd, schwachsinnig, und, wer weiß was sonst noch.


Sags du mir, was ist toll daran uint8_t statt bool zu verwenden?

Hi

Er schrieb nicht, daß Er dafür uint8_t benutzt, sondern, daß man genauso gut uint8_t benutzen könnte - der Kompiler packt jedes Bool in ein eigenes Byte - Das kann dann zwar immer noch nur 0 oder 1 annehmen (bool), braucht aber immer noch die 8 Bit Platz.
Ein ‘Verbinden’ mehrerer Bool zu einem Byte wäre mir ebenfalls noch nicht aufgefallen - lasse mich aber hier sehr gerne belehren - wäre doch toll, wenn der Kompiler hier Platz vor Geschwindigkeit stellt. (wobei auf ein einzelnes Bit Prüfen nun auch nicht sooo zeitintensiv ist - zumindest in ‘Maschinennähe’)

MfG

Er schrieb nicht, daß Er dafür uint8_t benutzt, sondern, daß man genauso gut uint8_t benutzen könnte -

Nein, er schrieb, dass bool "kacke" ist.
Das ist eine vernichtende Wertung.
Damit ist aus meiner Sicht klar, dass er NIEMALS bool verwendet.

der Kompiler packt jedes Bool in ein eigenes Byte

Beim AVR....
Bei einem 32Bit Prozessor kann bool 4 Byte breit sein.

Ein 'Verbinden' mehrerer Bool zu einem Byte wäre mir ebenfalls noch nicht aufgefallen - lasse mich aber hier sehr gerne belehren

Suche "C++ struct Bitfeld"


Dass ein bool auf dem AVR 8 Bit breit ist, hat den Vorteil, dass man Zeiger darauf setzen kann. Referenzen nutzen. Das wäre sonst nicht möglich. Zeiger kann man nur auf Speicherstellen zeigen lassen, nicht auf einzelnen Bits in einer solchen Zelle.