Wemos Mini OLED Display und IAQ Core

Hi Leute,
ich verzweifle und finde die Lösung nicht, hoffe ihr könnt helfen.

Ich benutze
( Lolin ) Wemos D1 Mini
OLED Display 128x32 , 0,91"
IAQ Core-C Luftgütesensor von AMS

Einzeln die beiden Komponenten zu betreiben ist kein Problem, das hat funktioniert. Auch die gemessenen CO2 / VOC Daten auf einen ioBroker auf einem Raspi zu spielen hat funktioniert.

Dann wollte ich die Daten auf dem OLED Display darstellen, was nicht hinhaut.

Wenn ich die beide am I2C betreiben möchte, kommen nur noch falsche, viel zu hohe Werte heraus.

Ich weiß nicht mehr, was ich noch versuchen soll. I2C Scanner spuckte aus

14:05:46.151 → I2C device found at address 0x3C !
14:05:46.188 → I2C device found at address 0x5A !

und so versuche ich die beiden auch im Sketch zu adressieren. Zumindest wenn ich ohne das OLED Display die Daten vom Sensor hole, sind die korrekt, auch wenn ich den Sensor mit der Adresse 0x5A anspreche.

Muss ich den Bus mit einem Widerstand abschließen ? Ist das bei er Konfiguration nötig ? Leider habe ich keinen zur Hand.

Sowas ist im Monitorfenster zu sehen, also viel zu hohe Werte für CO2, da wär ich schon tot :wink:

20:21:13.755 → Air ppm 49151
20:21:18.783 → Air ppm 47103
20:21:23.814 → Air ppm 33279
20:21:28.837 → Air ppm 57343
20:21:33.875 → Air ppm 65535
20:21:38.892 → Air ppm 49151

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <U8g2lib.h>
#include <U8x8lib.h>

#include <Wire.h>
#include "I2Cdev.h"
#include "IAQ2000.h"

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C OLED(U8G2_R0, U8X8_PIN_NONE);
IAQ2000 iaq(0x5A);
//IAQ2000 iaq;

#define INFO_SCREEN_DELAY 3000

uint16_t airQuality ;
uint16_t airQuality_old = 0;

uint8_t iAQstatus;

uint16_t airTvoc;
uint16_t airTvoc_old = 0;

String iAQtxtStatus = String(10);
String txt;


const char* ssid = "SSID";
const char* password = "...";
const char* mqtt_server = "...";

WiFiClient espClient;
PubSubClient client(espClient);

long lastMsg = 0;
char msg[50];
int value = 0;

void getIAQdata() {
  airQuality = iaq.getIaqpred();
  airTvoc = iaq.getIaqtvoc();
  iAQstatus = iaq.getIaqstatus();
 
}

void ShowTxt() {
  OLED.clearBuffer();
  OLED.setFontMode(1);
  OLED.setCursor(0, 15);
  txt  = "Air: " + String(airQuality) ;
  OLED.print(txt);
  OLED.setCursor(0, 30);
  txt  = "VOC: " + String(airTvoc) ;
  OLED.print(txt);
  OLED.sendBuffer();
  delay(INFO_SCREEN_DELAY);
  OLED.clearBuffer();         // clear the internal memory once
  delay(1000);
}


void setup_wifi() {
  delay(10);
  

  WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level

  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  Wire.begin();
  Wire.setClockStretchLimit(1500); // Wichtig, sonst klappt nix am Wemos D1 mini, bei Arduino nano nicht notwendig

  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  Serial.println("Initialisierung des Sensor...");
  iaq.initialize();

  Serial.println("Verbindung zum Sensor testen...");
  Serial.println(iaq.testConnection() ? "IAQ erfolgreich verbunden" : "IAQ Fehler");

 //u8g2_SetI2CAddress(OLED.getU8g2(), 0x3C*2); Display geht, falsche Werte

u8g2_SetI2CAddress(&OLED,  0x3C * 2);

// OLED.setI2CAddress(OLED.GetU8g2(), 0x3C * 2); klasse nicht bekannt
// OLED.setI2CAddress(0x3C * 2); Display geht, falsche Werte
// OLED.setI2CAddress(0x3C);  kein Display
  OLED.begin();
  OLED.enableUTF8Print();
  
  OLED.setFont(u8g2_font_cu12_tr);
 // OLED.setFont(u8g_font_6x10); // ziemlich klein
  
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 1000) { // Abfrage sowieso nur alle 60 Sek 60000
    lastMsg = now;

    getIAQdata(); // Neue Daten vom Sensor

    if ((airQuality >= airQuality_old + 10) || (airQuality <= airQuality_old - 10)) { // nur bei mindestens 10ppm +-
      Serial.print("Air  ppm  ");
      Serial.println(airQuality);

      String pubString  = String(airQuality);
      pubString.toCharArray(msg, pubString.length() + 1);

      //  Serial.println(msg);
      client.publish("IAQ_airQuality", msg);
      airQuality_old = airQuality;
    }

    if ((airTvoc >= airTvoc_old + 10) || (airTvoc <= airTvoc_old - 10)) { // nur bei mindestens 10ppb +-
      Serial.print("TVoc ppb  ");
      Serial.println(airTvoc);

      String pubString  = String(airTvoc);
      pubString.toCharArray(msg, pubString.length() + 1);

      //  Serial.println(msg);
      client.publish("IAQ_airTVOC", msg);
      airTvoc_old = airTvoc;
    }


  }

  delay(1000);
  ShowTxt();
}

Du brauchst für den I2C-Bus ganz sicher Pullup-Widerstände von 4,7 k gegen +Vcc.

Mit welcher Spannung betreibst du die einzelnen Komponenten ?

Wenn ich versuche, deine Bilder zu erkennen, sieht es danach aus, du betreibst das Display an 3,3 Volt und den Sensor an 5 Volt. Das gibt sicher Probleme mit dem Bus. Da solltest du eine einheitliche Spannung wählen oder einen Levelshifter verwenden.

Poste mal Hyperlinks zu den Modulen.

Hi Dieter, Stimmt, der IAQ möchte 3,3V und das Display 5.

https://www.az-delivery.de/collections/bestseller/products/0-91-zoll-i2c-oled-display?ls=de#description

https://www.mouser.de/datasheet/2/588/iAQ-core_DS000334_1-00-1512544.pdf

Also sollte ich einen Levelshifter besorgen und Widerstände. Sowas ? XCSOURCE® 5STK IIC I2C Logisches Level Konverter Bi-Direktional Modul 5V zu 3.3V TE291 https://www.amazon.de/dp/B0148BLZGE/ref=cm_sw_r_cp_tai_EQ9lCb7SZRWYJ Gibts das als Paketchen irgendwo ?

Vielen Dank schon mal !

Sorry, ich hatte dich um Hyperlinks gebeten, deine URL kann ich mobil hier nicht öffnen.

Zumindest der Name in der URL sagt etwas richtiges zum Levelshifter. Bei den richtigen Levelshiftern kannst du dann zusätzliche Pullup-Widerstände sparen, die sind auf dem Levelshifter mit drauf.

Ok, hier die Hyperlinks, sorry.

OLED

Sensor Datasheet

Ich hab mir mittlerweile ( 100km gefahren… ) 4,7kOhm Widerstände besorgt und sie auf dem Breadboard verbaut. Und oh Schreck, die Werte sind immer noch falsch.

Außerdem hab ich nur noch eine Spannungsversorgung genommen, das Display funktioniert auch mit nur 3,3V.

Ich hoffe, man kann erkennen, wie ich es verdrahtet habe. Ist das verkehrt ??

Vielen Dank schon mal…
Olli

8e9ae1267bec30c5a7902ecda7fbefa75e3ae73e.jpg

Leider kann ich an der Verdrahtung nichts erkennen. Die Kabel sin nicht zu verfolgen.

Kannst du den Sensorwert im seriellen Monitor ansehen ? Auch wen dein Display dran ist.

Hi, Ja den Sensorwert im seriellen Monitor sehe ich, ist leider der gleiche ( falsche ) wie auf dem Display. Wenn ich das so gesteckt lasse auf dem Breadboard und das Display oder den Sensor einzeln ansteuere, funktioniert es. Dann sollte die Verkabelung doch ok, sein ?

Ich benutze rote Kabel als 3,3V, blau für GND und gelb / weiß als SDA, SCL. Die Widerstände sind zwichen 3V und einmal SDA und einmal SCL. Dann gehts zum Sensor, anschließend zu Display. Ich hab alle Kabel abgenommen und noch mal neu verdrahtet, ohne Erfolg :(

Hilfe ...

Da fällt mir dann nichts mehr zu ein, außer: Poste bitte mal nacheinander die einzelnen Sketche, die funktionieren und den aktuellen, kompletten Sketch.

Evtl. sehen wir ja einen Fehler oder Unterschied.

Okay… dann mal los.
Passend zu Dieters Signatur “I2C = weniger ist mehr: weniger Kabel, mehr Probleme” hier also die verschiedenen Programme. Ich ändere nichts an der Hardware, die bleibt bei allen 3 Sketchs unverändert.

/*
  01.01.2019 initial
  06.01.2019 OLED und IAQ
  
*/
#include <Wire.h>
#include "I2Cdev.h"
#include "IAQ2000.h"
#include <U8g2lib.h>

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C OLED(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

#define INFO_SCREEN_DELAY 3000

IAQ2000 iaq(0x5A);

uint16_t airQuality ;
uint16_t airQuality_old = 0;
uint16_t airTvoc;
uint16_t airTvoc_old = 0;
long lastMsg = 0;
String txt;

void getIAQdata() {

  airQuality = iaq.getIaqpred();
  airTvoc = iaq.getIaqtvoc();

}

void setup() {
  Wire.begin();
  Wire.setClockStretchLimit(15000); // Wichtig, sonst klappt nix am Wemos D1 mini, bei Arduino nano nicht notwendig
  Serial.begin(9600);

  // initialize device
  Serial.println("Initialisierung des Sensors...");
  iaq.initialize();

  // verify connection
  Serial.println("Verbindung zum Sensor testen...");
  Serial.println(iaq.testConnection() ? "IAQ erfolgreich verbunden" : "IAQ Fehler");

  u8g2_SetI2CAddress(&OLED,  0x3C * 2);
  OLED.begin();
  OLED.setFont(u8g2_font_cu12_tr);

}

void ShowTxt() {
  OLED.clearBuffer();
  OLED.setFontMode(1);

  OLED.setCursor(0, 15);
  txt  = "Air: " + String(airQuality) ;
  OLED.print(txt);

  OLED.setCursor(0, 30);
  txt  = "VOC: " + String(airTvoc) ;
  OLED.print(txt);

  OLED.sendBuffer();
  delay(INFO_SCREEN_DELAY);
  OLED.clearBuffer();         // clear the internal memory once
  delay(1000);
}

void loop() {
  long now = millis();
  if (now - lastMsg > 1000) {
    lastMsg = now;
    getIAQdata(); // Neue Daten vom Sensor

    if ((airQuality >= airQuality_old + 10) || (airQuality <= airQuality_old - 10)) { // nur bei mindestens 10ppm +-
      Serial.print("Air  ppm  ");
      Serial.println(airQuality);
      airQuality_old = airQuality;
    }

    if ((airTvoc >= airTvoc_old + 10) || (airTvoc <= airTvoc_old - 10)) { // nur bei mindestens 10ppb +-
      Serial.print("TVoc ppb  ");
      Serial.println(airTvoc);
      airTvoc_old = airTvoc;
    }
  }

  ShowTxt();
}

Hier nur der für den Sensor

/*
  01.01.2019 initial
  02.01.2019 old / neu hinzugefügt und formatiert
  06.01.2019 reduziert auf Sensor
*/

#include <Wire.h>
#include "I2Cdev.h"
#include "IAQ2000.h"

IAQ2000 iaq(0x5A);

uint16_t airQuality ;
uint16_t airQuality_old = 0;
uint16_t airTvoc;
uint16_t airTvoc_old = 0;
long lastMsg = 0;

void getIAQdata() {

  airQuality = iaq.getIaqpred();
  airTvoc = iaq.getIaqtvoc();

}
void setup() {
  Wire.begin();
  Wire.setClockStretchLimit(15000); // Wichtig, sonst klappt nix am Wemos D1 mini, bei Arduino nano nicht notwendig
  Serial.begin(9600);

  // initialize device
  Serial.println("Initialisierung des Sensors...");
  iaq.initialize();

  // verify connection
  Serial.println("Verbindung zum Sensor testen...");
  Serial.println(iaq.testConnection() ? "IAQ erfolgreich verbunden" : "IAQ Fehler");

}

void loop() {
  long now = millis();
  if (now - lastMsg > 1000) {
    lastMsg = now;
    getIAQdata(); // Neue Daten vom Sensor

    if ((airQuality >= airQuality_old + 10) || (airQuality <= airQuality_old - 10)) { // nur bei mindestens 10ppm +-
      Serial.print("Air  ppm  ");
      Serial.println(airQuality);
      airQuality_old = airQuality;
    }

    if ((airTvoc >= airTvoc_old + 10) || (airTvoc <= airTvoc_old - 10)) { // nur bei mindestens 10ppb +-
      Serial.print("TVoc ppb  ");
      Serial.println(airTvoc);
      airTvoc_old = airTvoc;
    }
  }

}

Hier der für das OLED

/*
  01.01.2019 initial
  06.01.2019 nur OLED Display
*/

#include <U8g2lib.h>
#include <Wire.h>

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C OLED(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

#define INFO_SCREEN_DELAY 3000

uint16_t airQuality ;
uint16_t airTvoc;
String txt;

void getIAQdata() {
  airQuality =  random(100, 200);
  airTvoc = random(200, 500);
}


void ShowTxt() {
  OLED.clearBuffer();
  OLED.setFontMode(1);

  OLED.setCursor(0, 15);
  txt  = "Air: " + String(airQuality) ;
  OLED.print(txt);

  OLED.setCursor(0, 30);
  txt  = "VOC: " + String(airTvoc) ;
  OLED.print(txt);

  OLED.sendBuffer();
  delay(INFO_SCREEN_DELAY);
  OLED.clearBuffer();         // clear the internal memory once
  delay(1000);
}

void setup() {
  Wire.begin();
  Wire.setClockStretchLimit(15000); // Wichtig, sonst klappt nix am Wemos D1 mini, bei Arduino nano nicht notwendig

  Serial.begin(9600);

  u8g2_SetI2CAddress(&OLED,  0x3C * 2);
  OLED.begin();
  OLED.setFont(u8g2_font_cu12_tr);

  randomSeed(analogRead(0));

}

void loop() {

  getIAQdata();
  ShowTxt();
}

Ich hab noch mal ein Bildchen gemacht, vielleicht kann man doch etwas erkennen.

Ich hab da noch etwas an Doku gefunden, verstehe es aber nicht. Kann da jemand von Euch etwas mit anfangen um mein Problem vielleicht in den Griff zu bekommen ?

Insbesondere 4.1.2 Clock stretching !? Oder bin ich auf dem Holzweg ?

Manual IAQ

Gruß, Olli

Hi

Der Slave kann den Master beim I²C-Bus ausbremsen. Den Takt gibt der Master vor, Er muß aber darauf achten, ob 'die Leitung frei ist'. Wenn der Slave mit dem Abarbeiten der Befehle nicht rechtzeitig fertig ist, lässt Dieser den Clock-Pin nicht wieder nach HIGH. Der Master achtet darauf und erkennt so, daß der Slave noch nicht fertig ist - und wartet (zumindest sollte Er, wenn nicht, gibt's Datensalat).

Der Slave muß die Clock-Leitung aber auch wieder los lassen, da sonst der ganze Bus eingefroren ist.

Clock-Strechting betreibt nur der Slave, wenn Er nicht hinterher kommt. Der Master kann Clock und Data eh setzen, wie und wann Er will, die Slaves 'melden Sich', wenn's zu schnell wird.

MfG

Okay, danke für die Erklärung.

Also kann das wohl nicht mit meinem im Zusammenhang stehen.

Ratlos. :(

Gruß Olli