7 Sensoren am Multiplexer

Moin,

ich möchte 8 Temperatur- und Luftfeuchtigkeitssensoren miteinander vergleichen (absolute Werte, Langzeitstabilität, Lebensdauer draußen).
Dazu habe ich mir jeweils einen DHT22, DHT20, AHT10, AHT20, AHT25, HTU21, HTU31 und einen GXHT30 besorgt.
Den DHT22 kann man mit einem digitalen Pin abfragen. Alle anderen habe eine I²C Schnittstelle. Um die sieben I²C Sensoren abfragen zu können werden diese Nacheinander mit einem Multiplexer angesteuert. Der Multiplexer ist an einem nodeMCU ESP82666 angeschlossen, damit wieder letztenendes per WLAN die Daten funken kann. Soweit so gut.
Dann habe ich mir für jeden Sensor Beispielsketche angesehen und ausprobiert, bis ich für jeden ein lauffähiges Sketch hatte. Dann habe ich den Multiplexer dazwischen geschaltet, und habe jedes einzelne Sketch so geändert, dass ich den jeweiligen Sensor durch den Multiplexer ansprechen kann. Danach wollte ich dann alle Sketche zusammenführen. Aber es ergeben sich schon bei dem Schritt davor Probleme.
Scheinbar funktioniert irgendwas mit dem Multiplexer nicht.
Der erste Sensor erschien mir zu funktionieren.
Als ich das gleiche mit dem zweiten und dritten Sensor gemacht habe, habe ich erkannt, die die Messwerte bis auf die zweite Nachkommastelle identisch sind. Ich hätte allerdings geringe Abweichungen (1-2 °C und ein paar Prozent in der Luftfeuchtigkeit erwartet). So ist es jedenfalls zwischen dem DHT22 und dem DHT20 Sensor, und auch bei meinen Einzeltests war das so.
Die ersten vier i²C Sensoren haben alle die gleiche Adresse 0x38.
Ich vermute, dass meine unterschiedlichen Sketche immer den gleichen Sensor abfragen, sonst würden da nicht die gleichen Ergebnisse bei rauskommen können.

Wo liegt der Fehler?

Hier meine drei Einzelsketche:
DHT20:

// Angeschlossen an:
// 3,3V, GND
// SDA+SCL am Multiplexer

#include "Wire.h"
#include "DHT20.h"
DHT20 DHT(&Wire);
#define I2CmultiADDR 0x70             // Multiplexeradresse

enum I2CDevice {
  dht20 = 0,
  aht10 = 1,
  aht20 = 2,
  aht25 = 3,
  htu21 = 4,
  htu31 = 5,
  gxht30 = 6
};
void I2Cmulti(I2CDevice num) {
  uint8_t i = (uint8_t) num;
  if (i > 7) return;
  Wire.beginTransmission(I2CmultiADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

void setup()
{
#if defined(ESP8266) || defined(ESP32)
  DHT.begin(4, 5);  //  select your pin numbers here
#else
  DHT.begin();
#endif
  Serial.begin(115200);
  delay(200);
  I2Cmulti(dht20);
  delay(2000);
}

void loop()
{
  //  READ DATA
  int status = DHT.read();
  switch (status)
  {
    case DHT20_OK:
      //Serial.println("OK,\t");
      break;
    case DHT20_ERROR_CHECKSUM:
      Serial.println("Checksum error,\t");
      break;
    case DHT20_ERROR_CONNECT:
      Serial.println("Connect error,\t");
      break;
    case DHT20_MISSING_BYTES:
      Serial.println("Missing bytes,\t");
      break;
    case DHT20_ERROR_BYTES_ALL_ZERO:
      Serial.println("All bytes read zero");
      break;
    case DHT20_ERROR_READ_TIMEOUT:
      Serial.println("Read time out");
      break;
    case DHT20_ERROR_LASTREAD:
      Serial.println("Error read too fast");
      break;
    default:
      Serial.println("Unknown error,\t");
      break;
  }

  //  DISPLAY DATA, sensor has only one decimal.
  Serial.print("DHT20 Luftfeuchtigkeit: ");
  Serial.print(DHT.getHumidity(), 1);
  Serial.print("\t");
  Serial.print("DHT20 Temperatur: ");
  Serial.println(DHT.getTemperature(), 1);

  delay(2000);
}

AHT10:

#include "Wire.h"
#include <Adafruit_AHT10.h>
Adafruit_AHT10 aht;
#define I2CmultiADDR 0x70             // Multiplexeradresse

// Angeschlossen an:
// 3,3V, GND
// SDA+SCL am Multiplexer

enum I2CDevice {
  dht20 = 0,
  aht10 = 1,
  aht20 = 2,
  aht25 = 3,
  htu21 = 4,
  htu31 = 5,
  gxht30 = 6
};
void I2Cmulti(I2CDevice num) {
  uint8_t i = (uint8_t) num;
  if (i > 7) return;
  Wire.beginTransmission(I2CmultiADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

void setup() {
  Serial.begin(115200);
  delay(200);
  I2Cmulti(aht10);
  if (! aht.begin()) {
    Serial.println("Could not find AHT10? Check wiring");
    while (1) delay(10);
  }
  //Serial.println("AHT10 found");
}

void loop() {
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
  Serial.print("AHT10 Luftfeuchtigkeit: ");
  Serial.print(humidity.relative_humidity);
  Serial.print("\t");
  Serial.print("AHT10 Temperatur: ");
  Serial.println(temp.temperature);
  delay(2000);
}

AHT20:

#include "Wire.h"
#include <Adafruit_AHTX0.h>
Adafruit_AHTX0 aht;
#define I2CmultiADDR 0x70             // Multiplexeradresse

// Angeschlossen an:
// 3,3V, GND
// SDA+SCL am Multiplexer

enum I2CDevice {
  dht20 = 0,
  aht10 = 1,
  aht20 = 2,
  aht25 = 3,
  htu21 = 4,
  htu31 = 5,
  gxht30 = 6
};
void I2Cmulti(I2CDevice num) {
  uint8_t i = (uint8_t) num;
  if (i > 7) return;
  Wire.beginTransmission(I2CmultiADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

void setup() {
  Serial.begin(115200);
  delay(200);
  I2Cmulti(aht20);
  if (! aht.begin()) {
    Serial.println("Could not find AHT? Check wiring");
    while (1) delay(10);
  }
  //Serial.println("AHT20 found");
}

void loop() {
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
  Serial.print("AHT20 Luftfeuchtigkeit: ");
  Serial.print(humidity.relative_humidity);
  Serial.print("\t");
  Serial.print("AHT20 Temperatur: ");
  Serial.println(temp.temperature);
  delay(2000);
}

AHT25:

// Angeschlossen an:
// 3,3V, GND
// SDA+SCL am Multiplexer

#define I2CmultiADDR 0x70             // Multiplexeradresse

#include <Wire.h>
#include <AHTxx.h>
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#endif

float ahtValue;                               //to store T/RH result

AHTxx aht_25(AHTXX_ADDRESS_X38, AHT2x_SENSOR); //sensor address, sensor type

enum I2CDevice {
  dht20 = 0,
  aht10 = 1,
  aht20 = 2,
  aht25 = 3,
  htu21 = 4,
  htu31 = 5,
  gxht30 = 6
};
void I2Cmulti(I2CDevice num) {
  uint8_t i = (uint8_t) num;
  if (i > 7) return;
  Wire.beginTransmission(I2CmultiADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}


/**************************************************************************/
/*
    setup()

    Main setup
*/
/**************************************************************************/
void setup()
{
  #if defined(ESP8266)
  WiFi.persistent(false);  //disable saving wifi config into SDK flash area
  WiFi.forceSleepBegin();  //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep
  #endif

  Serial.begin(115200);
  delay(200);
  I2Cmulti(aht25);
  Serial.println();
  
  while (aht_25.begin() != true) //for ESP-01 use aht_25.begin(0, 2);
  {
    Serial.println(F("AHT2x not connected or fail to load calibration coefficient")); //(F()) save string to flash & keeps dynamic memory free

    delay(5000);
  }

  Serial.println(F("AHT25 OK"));

  //Wire.setClock(400000); //experimental I2C speed! 400KHz, default 100KHz
}


/**************************************************************************/
/*
    loop()

     Main loop
*/
/**************************************************************************/
void loop()
{
  /* DEMO - 1, every temperature or humidity call will read 6-bytes over I2C, total 12-bytes */
  Serial.println();
  Serial.println(F("DEMO 1: read 12-bytes"));

  ahtValue = aht_25.readTemperature(); //read 6-bytes via I2C, takes 80 milliseconds

  Serial.print(F("Temperature...: "));
  
  if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
  {
    Serial.print(ahtValue);
    Serial.println(F(" +-0.3C"));
  }
  else
  {
    printStatus(); //print temperature command status

    if   (aht_25.softReset() == true) Serial.println(F("reset success")); //as the last chance to make it alive
    else                             Serial.println(F("reset failed"));
  }

  delay(2000); //measurement with high frequency leads to heating of the sensor, see NOTE

  ahtValue = aht_25.readHumidity(); //read another 6-bytes via I2C, takes 80 milliseconds

  Serial.print(F("Humidity......: "));
  
  if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
  {
    Serial.print(ahtValue);
    Serial.println(F(" +-2%"));
  }
  else
  {
    printStatus(); //print humidity command status
  }

  delay(2000); //measurement with high frequency leads to heating of the sensor, see NOTE

  /* DEMO - 2, temperature call will read 6-bytes via I2C, humidity will use same 6-bytes */
  Serial.println();
  Serial.println(F("DEMO 2: read 6-byte"));

  ahtValue = aht_25.readTemperature(); //read 6-bytes via I2C, takes 80 milliseconds

  Serial.print(F("Temperature: "));
  
  if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
  {
    Serial.print(ahtValue);
    Serial.println(F(" +-0.3C"));
  }
  else
  {
    printStatus(); //print temperature command status
  }

  ahtValue = aht_25.readHumidity(AHTXX_USE_READ_DATA); //use 6-bytes from temperature reading, takes zero milliseconds!!!

  Serial.print(F("Humidity...: "));
  
  if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
  {
    Serial.print(ahtValue);
    Serial.println(F(" +-2%"));
  }
  else
  {
    printStatus(); //print temperature command status not humidity!!! RH measurement use same 6-bytes from T measurement
  }

  delay(10000); //recomended polling frequency 8sec..30sec
}


/**************************************************************************/
/*
    printStatus()

    Print last command status
*/
/**************************************************************************/
void printStatus()
{
  switch (aht_25.getStatus())
  {
    case AHTXX_NO_ERROR:
      Serial.println(F("no error"));
      break;
    case AHTXX_BUSY_ERROR:
      Serial.println(F("sensor busy, increase polling time"));
      break;
    case AHTXX_ACK_ERROR:
      Serial.println(F("sensor didn't return ACK, not connected, broken, long wires (reduce speed), bus locked by slave (increase stretch limit)"));
      break;
    case AHTXX_DATA_ERROR:
      Serial.println(F("received data smaller than expected, not connected, broken, long wires (reduce speed), bus locked by slave (increase stretch limit)"));
      break;
    case AHTXX_CRC8_ERROR:
      Serial.println(F("computed CRC8 not match received CRC8, this feature supported only by AHT2x sensors"));
      break;
    default:
      Serial.println(F("unknown status"));    
      break;
  }
}

Beste Grüße,
Chris

lass uns nicht raten - mach einen Schaltplan und Echtbilder von deinem Aufbau.
Angabe vom "Multiplexer" fehlt auch.

Hast die Warnings in der IDE aktiviert? kompiliert das alles ohne Warnings?

mach mal einen Sketch ohne wifi - nur mit zwei Sensoren.

mach dir je Sensor eine "begin" Funktion (für setup) und eine "run" Funktion für loop. Das würde den Sketch leichter lesbar machen.

Ich bin ja noch gar nicht so weit, dass ich zwei oder mehr Sensoren in einem Sketch abfrage, sondern jeweils nur einen, aber den über den Multiplexer.

Der Multiplexer ist ein PCA9548A.



Alle Sensoren und der Multiplexer sind mit GND und 3,3V vom nodeMCU verbunden.
Vom DHT22 hängt der "OUT" am D5 vom nodeMCU.
Vom Multiplexer hängt SDA an D2 vom nodeMCU.
Vom Multiplexer hängt SCL an D1 vom nodeMCU.
Der DHT20 hängt mit SDA am SD0 und SCL am SC0 vom Multiplexer.
Der AHT10 hängt mit SDA am SD1 und SCL am SC1 vom Multiplexer.
Der AHT20 hängt mit SDA am SD2 und SCL am SC2 vom Multiplexer.
Der AHT25 hängt mit SDA am SD3 und SCL am SC3 vom Multiplexer.
Der HTU21 hängt mit SDA am SD4 und SCL am SC4 vom Multiplexer.
Der HTU31 hängt mit SDA am SD5 und SCL am SC5 vom Multiplexer.
Der GXHT30 hängt mit SDA am SD6 und SCL am SC6 vom Multiplexer.

Einzeln ohne Multiplexer funktioniert alles.
Einzeln mit Multiplexer auch, aber die Werte sind immer verdächtig identisch. (ich vermute der Multiplexer tut nicht was er soll)

Beste Grüße,
Chris

adaptiere erst mal einen i2c scanner sketch und mach außen rundherum die Umschaltung auf die 8 Kanäle und schau ob du alle Sensoren erreichst.

edit ungeprüft:

// --------------------------------------
// i2c_scanner with matrix

#include <Wire.h>

// function to switch bus/channel on the TCA9548A
uint8_t TCA9548A(uint8_t bus)       // switch bus
{
  Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
  Wire.write(1 << bus);          // send byte to select bus
  return Wire.endTransmission(); // 0 = success, can be used to react on error
}

void setup() {
  Wire.begin();

  Serial.begin(9600);
  while (!Serial); // Leonardo: wait for Serial Monitor
  Serial.println("\nI2C Scanner");
}

void loop() {
  int nDevices = 0;

  Serial.println("Scanning...");

  for (byte channel = 0; channel < 8; channel ++)
  {
    Serial.print(F("Test on channel ")); Serial.println(channel);
    TCA9548A(channel);
    for (byte address = 1; address < 127; ++address) {
      if (address == 0x70) break;  // used for the matrix
      
      // The i2c_scanner uses the return value of
      // the Wire.endTransmission to see if
      // a device did acknowledge to the address.
      Wire.beginTransmission(address);
      byte error = Wire.endTransmission();

      if (error == 0) {
        Serial.print("I2C device found at address 0x");
        if (address < 16) {
          Serial.print("0");
        }
        Serial.print(address, HEX);
        Serial.println("  !");

        ++nDevices;
      } else if (error == 4) {
        Serial.print("Unknown error at address 0x");
        if (address < 16) {
          Serial.print("0");
        }
        Serial.println(address, HEX);
      }
    }

  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  } else {
    Serial.println("done\n");
  }
  delay(5000); // Wait 5 seconds for next scan
}

Es fehlte nur ein einziges ";" in Zeile 29 :star_struck:, dann ließ es sich kompilieren, läuft und ergibt:

Scanning...
Test on channel 0I2C device found at address 0x38 !
Test on channel 1I2C device found at address 0x38 !
Test on channel 2I2C device found at address 0x38 !
Test on channel 3I2C device found at address 0x38 !
Test on channel 4I2C device found at address 0x40 !
Test on channel 5I2C device found at address 0x40 !
Test on channel 6I2C device found at address 0x44 !
Test on channel 7done

demnach scheint der Multiplexer und die Sensoren ja richtig angeschlossen zu sein und auch zu funktionieren.

dann mach mal:

mit der Schalter-Funktion von mir.

Ich habe das Sketch um das fehlende ";" ergänzt und in der Ausgabe noch ein Komma und ein Leerzeichen eingefügt.
Frage: Warum kommt auf Kanal 7 keine Fehlermeldung?

// --------------------------------------
// i2c_scanner with matrix

#include <Wire.h>

// function to switch bus/channel on the TCA9548A
uint8_t TCA9548A(uint8_t bus)       // switch bus
{
  Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
  Wire.write(1 << bus);          // send byte to select bus
  return Wire.endTransmission(); // 0 = success, can be used to react on error
}

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(200);
  while (!Serial); // Leonardo: wait for Serial Monitor
  Serial.println("\nI2C Scanner");
}

void loop() {
  int nDevices = 0;

  Serial.println("Scanning...");

  for (byte channel = 0; channel < 8; channel ++)
  {
    Serial.print(F("Test on channel ")); Serial.print(channel);
    TCA9548A(channel);
    for (byte address = 1; address < 127; ++address) {
      if (address == 0x70) break;  // used for the matrix

      // The i2c_scanner uses the return value of
      // the Wire.endTransmission to see if
      // a device did acknowledge to the address.
      Wire.beginTransmission(address);
      byte error = Wire.endTransmission();

      if (error == 0) {
        Serial.print(", I2C device found at address 0x");
        if (address < 16) {
          Serial.print("0");
        }
        Serial.print(address, HEX);
        Serial.println("  !");

        ++nDevices;
      } else if (error == 4) {
        Serial.print("Unknown error at address 0x");
        if (address < 16) {
          Serial.print("0");
        }
        Serial.println(address, HEX);
      }
    }

  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  } else {
    Serial.println(", done\n");
  }
  delay(5000); // Wait 5 seconds for next scan
}

Ausgabe:


I2C Scanner
Scanning...
Test on channel 0, I2C device found at address 0x38 !
Test on channel 1, I2C device found at address 0x38 !
Test on channel 2, I2C device found at address 0x38 !
Test on channel 3, I2C device found at address 0x38 !
Test on channel 4, I2C device found at address 0x40 !
Test on channel 5, I2C device found at address 0x40 !
Test on channel 6, I2C device found at address 0x44 !
Test on channel 7, done


gibt es keine. Der Zähler geht ja über alle.

hmmmm, Bahnhof?!
Was für eine Schalter Funktion?

uint8_t TCA9548A(uint8_t bus)

Ich bin noch nicht soweit, dass ich mehrere Sensoren in einem Sketch abfragen will.

Ich wollte erstmal für jeden Sensor einen Sketch machen, wo der Sensor trotzdem schon über den Multiplexer abgefragt wird.

Und wollte erst danach die Einzelsketches zu einem Sketch zusammenführen.

Den Schalter hab ich mir ja schon gebaut:

enum I2CDevice {
  dht20 = 0,
  aht10 = 1,
  aht20 = 2,
  aht25 = 3,
  htu21 = 4,
  htu31 = 5,
  gxht30 = 6
};
void I2Cmulti(I2CDevice num) {
  uint8_t i = (uint8_t) num;
  if (i > 7) return;
  Wire.beginTransmission(I2CmultiADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

Und dann wird die Adresse/Sensor z.B. mit "I2Cmulti(dht20);" umgeschaltet

Wäre noch zu klären ob jeder I2C Zweig zwischen dem I2C-Multiplexer und den einzelnen Sensoren Pullupswiderstände hat.
Grüße Uwe

? Wüsste nicht, dass man die braucht?! Kann dazu nichts finden?!

du könntest ja mal das ausprobieren:

  Serial.println(1 << dht20);
  Serial.println(1 << aht10);
  Serial.println(1 << aht20);
  Serial.println(1 << aht25);
  Serial.println(1 << htu21);
  Serial.println(1 << htu31);
  Serial.println(1 << gxht30);

und dann überleg dir noch mal ob der shift das macht was du willst.

ergibt:

1
2
4
8
16
32
64

Leider habe ich keine Ahnung was das "1 <<" im print befehl tut.

Gegoogelt: " Der Shift-Left-Operator erwartet zwei Operanden als rvalues und wird von links nach rechts abgearbeitet. Der Rückgabewert ist ein rvalue, der stets ein Integer-Typ ist. Der Shift-Left-Operator ist nur für Integer-Werte zulässig."

Was hat das jetzt mit meinem Thema zu tun?

Trotzdem leider nur Bahnhof, ich kenne weder Haltestelle noch Windrichtung?!
Was tut es? (es leuchtet blau...is klar)

Das hat mir leider gar nicht geholfen :frowning:

Code-Ausschnitt von noiasca aus post # 4

Das ist das was themanfrommoon auch macht

Und ich übrigens auch
ich habe auch mal drei Sensoren über den Multiplexer ausgelesen

void TCA9548A(uint8_t p_busNr)
{
  Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
  Wire.write(1 << p_busNr);          // send byte to select bus
  Wire.endTransmission();
}

Das hat so funktioniert
Ich interpretiere die Funktion des I2C-multiplexer-Chip so
durch diesen Befehl wird in ein Register geschrieben das bestimmt welcher Port mit dem µC verbunden werden soll. Und dazu wird das entsprechende Bit im Register gesetzt und deswegen macht es Sinn bitshifting per 1 << zu machen.

Als nächsten Test würde ich folgendes machen.

Alle bis auf einen I2C-Sensor vom Multiplexer-Chip abklemmen und dann den Scan laufen lassen
Dann müsste ja nur dieser eine gefunden werden.
Dann den Sensor vom ersten Test auch abklemmen und nur den zweiten anklemmen usw.

Außerdem könntest du dir ausgeben lassen was jetzt wirklich für ein Zahlenwert
beim

  Wire.write(1 << MEINE_VARIABLE);

.
.

  Wire.write(1 << MEINE_VARIABLE);
  Serial.print("Wire.write(1 << MEINE_VARIABLE=");
  Serial.println(MEINE_VARIABLE);

übertragen wird.
Das würde ich in den Scanner-Sketch und in deinen Sketch einbauen.
Es hat schon immer am meisten geholfen die Fakten zu überprüfen
In diesem Fall sind die Fakten die übergebenen Zahlenwerte

vgs

Der I2C Bus braucht Pullupwiderstände um ein HIGH Pegel darstellen zu können. Die "Ausgänge" der I2C Geräte haben nur Transistoren die das Signal auf Masse ziehen können.
Wahrscheinlich sind auf den Modulen Pullupwiderstände vorhanden. Je nach Wert kann bei längeren Verbindungsdräten diese nicht ausreichend sein und zusätzliche Pullupwiderstände notwendig sein.
Ich weiß jetzt nicht ob das ein Versuch ist mal zu verstehen wie ein Multiplexer funktioniert oder wie die Sensoren verschieden messen oder ob das ein Versuchsaufbau ist und das endgültige Projekt die Sensoren weit voneinander entfernt montiert hat.
Im letzten Fall wird es Probleme mit dem I2C Bus geben.
Grüeß Uwe

Aktuell ist es noch ein Testaufbau. Wenns funktioniert kommen die Sensoren aber alle ganz dicht ran an den Multiplexer aif eine Lochrasterplatine. Dann ist die Leitungslänge nir noch 2-4cm.
Allerdings möchte ich zwischen nodeMCU und Multiplexer bestenfalls 5m Leitungslänge realisieren. Mal sehen, vielleich ein CAT7 Kabel hab ich noch. Werde ich probieren.

Im Datenblatt zum DHT20 (Seite 7) steht jedenfalls, dass ein externer Pullup benötigt wird.

Musst mal schauen, ob auf der Rückseite der Platine bei den Labels R1 und R2 was aufgelötet ist oder nicht.