// Schritt-fuer-Schritt-Diagnose fuer den CCS811 (CJMCU-811), ohne Adafruit-Bibliothek, direkt ueber I2C. // Ausgabe im Serial Monitor (9600 Baud). ESP nicht angeschlossen. // Verdrahtung: VCC -> 3,3 V, GND -> GND, SDA -> A4, SCL -> A5, WAK -> GND, ADD -> GND (Adresse 0x5A) #include // CCS811-Register (Datenblatt) const uint8_t REG_STATUS = 0x00; const uint8_t REG_MEAS_MODE = 0x01; const uint8_t REG_ALG_RESULT = 0x02; const uint8_t REG_HW_ID = 0x20; const uint8_t REG_HW_VERSION = 0x21; const uint8_t REG_FW_BOOT_VERSION = 0x23; const uint8_t REG_FW_APP_VERSION = 0x24; const uint8_t REG_ERROR_ID = 0xE0; const uint8_t REG_APP_START = 0xF4; const uint8_t REG_SW_RESET = 0xFF; uint8_t adresse = 0; bool bereit = false; bool schreibe(uint8_t reg, const uint8_t* daten, uint8_t n) { Wire.beginTransmission(adresse); Wire.write(reg); Wire.write(daten, n); return Wire.endTransmission() == 0; } bool lese(uint8_t reg, uint8_t* daten, uint8_t n) { Wire.beginTransmission(adresse); Wire.write(reg); if (Wire.endTransmission() != 0) return false; if (Wire.requestFrom(adresse, n) != n) return false; for (uint8_t i = 0; i < n; i++) daten[i] = Wire.read(); return true; } void hex(uint8_t wert) { Serial.print(F("0x")); if (wert < 0x10) Serial.print('0'); Serial.print(wert, HEX); } void zeigeStatus(uint8_t s) { Serial.print(F(" STATUS = ")); hex(s); Serial.print(F(" ERROR=")); Serial.print(s & 0x01); Serial.print(F(" DATA_READY=")); Serial.print((s >> 3) & 1); Serial.print(F(" APP_VALID=")); Serial.print((s >> 4) & 1); Serial.print(F(" FW_MODE=")); Serial.println((s >> 7) & 1); } void zeigeFehler() { uint8_t e; if (!lese(REG_ERROR_ID, &e, 1)) { Serial.println(F(" ERROR_ID nicht lesbar")); return; } Serial.print(F(" ERROR_ID = ")); hex(e); Serial.println(); if (e & 0x01) Serial.println(F(" - WRITE_REG_INVALID")); if (e & 0x02) Serial.println(F(" - READ_REG_INVALID")); if (e & 0x04) Serial.println(F(" - MEASMODE_INVALID")); if (e & 0x08) Serial.println(F(" - MAX_RESISTANCE: Sensorelement defekt oder extremer Wert")); if (e & 0x10) Serial.println(F(" - HEATER_FAULT: Heizer defekt")); if (e & 0x20) Serial.println(F(" - HEATER_SUPPLY: Versorgungsspannung zu schwach -> 3,3 V / GND pruefen")); } // Liefert false und Erklaerung, wenn ein Schritt scheitert bool initialisiere() { // 1) Pegel der Leitungen ohne interne Pull-ups: die Platine zieht SDA/SCL auf ihre 3,3 V pinMode(A4, INPUT); pinMode(A5, INPUT); delay(10); Serial.print(F("\n[1] Pegel: SDA(A4)=")); Serial.print(digitalRead(A4) ? F("HIGH") : F("LOW")); Serial.print(F(" SCL(A5)=")); Serial.println(digitalRead(A5) ? F("HIGH") : F("LOW")); if (!digitalRead(A4) || !digitalRead(A5)) { Serial.println(F(" -> LOW = Leitung haengt auf GND oder Modul hat keinen Strom (VCC an 3,3 V?)")); } // 2) I2C-Scan Wire.begin(); Wire.setClock(100000); Wire.setWireTimeout(25000, true); // kein Haengenbleiben bei blockiertem Bus Serial.println(F("\n[2] I2C-Scan")); uint8_t gefunden = 0; for (uint8_t a = 1; a < 127; a++) { Wire.beginTransmission(a); uint8_t r = Wire.endTransmission(); if (r == 0) { Serial.print(F(" Geraet bei ")); hex(a); Serial.println(); gefunden++; if (a == 0x5A || a == 0x5B) adresse = a; } else if (r == 5) { Serial.println(F(" Timeout: Bus blockiert (SDA/SCL Kurzschluss oder vertauscht?)")); return false; } } if (adresse == 0) { Serial.println(gefunden ? F(" Kein CCS811 bei 0x5A/0x5B (andere Geraete gefunden)") : F(" KEIN Geraet: SDA/SCL vertauscht? VCC/GND? Loetstellen der Stiftleiste?")); return false; } // 3) Software-Reset -> Bootloader-Modus const uint8_t reset[] = {0x11, 0xE5, 0x72, 0x8A}; schreibe(REG_SW_RESET, reset, 4); delay(100); // 4) Chip-ID und Versionen uint8_t id, hw, v[2]; Serial.println(F("\n[3] Chip")); if (!lese(REG_HW_ID, &id, 1)) { Serial.println(F(" HW_ID nicht lesbar (I2C-Fehler)")); return false; } Serial.print(F(" HW_ID = ")); hex(id); Serial.println(id == 0x81 ? F(" (richtig)") : F(" (FALSCH, erwartet 0x81: kein CCS811 oder gestoerter Bus)")); if (id != 0x81) return false; if (lese(REG_HW_VERSION, &hw, 1)) { Serial.print(F(" HW_VERSION = ")); hex(hw); Serial.println(); } if (lese(REG_FW_BOOT_VERSION, v, 2)) { Serial.print(F(" Bootloader = ")); Serial.print(v[0] >> 4); Serial.print('.'); Serial.print(v[0] & 0x0F); Serial.print('.'); Serial.println(v[1]); } if (lese(REG_FW_APP_VERSION, v, 2)) { Serial.print(F(" App-Firmware = ")); Serial.print(v[0] >> 4); Serial.print('.'); Serial.print(v[0] & 0x0F); Serial.print('.'); Serial.println(v[1]); } // 5) Firmware starten uint8_t s; Serial.println(F("\n[4] Status vor APP_START")); lese(REG_STATUS, &s, 1); zeigeStatus(s); if (!(s & 0x10)) { Serial.println(F(" APP_VALID=0: keine gueltige Firmware auf dem Sensor (muesste neu geflasht werden)")); return false; } schreibe(REG_APP_START, nullptr, 0); delay(100); Serial.println(F("\n[5] Status nach APP_START")); lese(REG_STATUS, &s, 1); zeigeStatus(s); if (s & 0x01) zeigeFehler(); if (!(s & 0x80)) { Serial.println(F(" FW_MODE=0: Firmware startet nicht")); return false; } // 6) Messmodus 1: jede Sekunde ein Wert const uint8_t modus = 0x10; schreibe(REG_MEAS_MODE, &modus, 1); delay(10); lese(REG_STATUS, &s, 1); if (s & 0x01) { Serial.println(F("\n[6] Fehler beim Setzen des Messmodus")); zeigeFehler(); return false; } Serial.println(F("\n[6] Messung laeuft (die ersten ~20 min sind 400 ppm / 0 ppb normal)\n")); return true; } void setup() { Serial.begin(9600); Serial.println(F("\n===== CCS811 Diagnose =====")); delay(500); // CCS811 braucht nach dem Einschalten ~20 ms bereit = initialisiere(); if (!bereit) { Serial.println(F("\n##### Abbruch, siehe letzten Schritt #####")); } } void loop() { if (!bereit) return; delay(1000); uint8_t d[6]; if (!lese(REG_ALG_RESULT, d, 6)) { Serial.println(F("Lesefehler (I2C)")); return; } uint8_t status = d[4]; if (status & 0x01) { zeigeStatus(status); zeigeFehler(); return; } if (!(status & 0x08)) { Serial.println(F("noch keine neuen Daten")); return; } Serial.print(F("eCO2: ")); Serial.print(((uint16_t)d[0] << 8) | d[1]); Serial.print(F(" ppm TVOC: ")); Serial.print(((uint16_t)d[2] << 8) | d[3]); Serial.println(F(" ppb")); }