212 lines
6.5 KiB
C++
212 lines
6.5 KiB
C++
// 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 <Wire.h>
|
|
|
|
// 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"));
|
|
}
|