GruppeC/firmware/ccs811_diagnose/ccs811_diagnose.ino

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"));
}