237 lines
7.3 KiB
Plaintext
237 lines
7.3 KiB
Plaintext
Deutsche Anleitung: I²C-Drucksensor an ESP32 (Arduino)
|
||
|
||
Basierend auf der Herstelleranleitung (siehe mitgeliefertes PDF).
|
||
|
||
============================================================
|
||
1) Überblick
|
||
============================================================
|
||
Der Sensor liefert kalibrierte digitale Messwerte über I²C:
|
||
- Druck als 24‑Bit ADC-Wert (signed) aus den Registern 0x06, 0x07, 0x08
|
||
- Temperatur als 16‑Bit Wert (signed) aus den Registern 0x09, 0x0A
|
||
- Messung wird über Register 0x30 gestartet; Fertig-Status über SCO-Bit (Bit 3) in 0x30
|
||
|
||
============================================================
|
||
2) Verdrahtung an ESP32 (WICHTIG: 3,3 V!)
|
||
============================================================
|
||
Kabelfarben → ESP32:
|
||
- Braun → 3V3 (Versorgung +)
|
||
- Blau → GND
|
||
- Weiß → SDA
|
||
- Schwarz→ SCL
|
||
|
||
Pull-Ups:
|
||
- Im Hersteller-Schaltbild sind 4,7 kΩ Pull-Ups eingezeichnet.
|
||
- Laut Text sind Pull-Ups bereits integriert → normalerweise keine zusätzlichen Pull-Ups nötig.
|
||
|
||
ESP32-Pins (Beispiel):
|
||
- SDA = GPIO 21
|
||
- SCL = GPIO 22
|
||
Du kannst andere I²C-fähige GPIOs nehmen und im Code Wire.begin(SDA, SCL) setzen.
|
||
|
||
============================================================
|
||
3) I²C-Adresse
|
||
============================================================
|
||
In der Hersteller-Bit-Tabelle ist A7..A1 = 1, danach W/R.
|
||
Das ergibt eine 7‑Bit‑Adresse von 0x7F.
|
||
|
||
Hinweis:
|
||
0x7F ist im I²C-Standard „speziell“/reserviert. Manche I²C‑Scanner finden ihn nicht.
|
||
Im Zweifel den Sensor trotzdem direkt mit 0x7F ansprechen (siehe Beispielcode).
|
||
|
||
============================================================
|
||
4) Messablauf (Register-Protokoll)
|
||
============================================================
|
||
1) Messung starten:
|
||
Schreibe 0x0A in Register 0x30 (Temp + Pressure acquisition)
|
||
|
||
2) Warten bis fertig:
|
||
Lies Register 0x30. Wenn SCO (Bit 3) = 0, ist die Messung fertig.
|
||
Alternativ kann man (laut Beispiel) ~50 ms warten.
|
||
|
||
3) Daten lesen:
|
||
Lies 0x06..0x0A in einem Rutsch (5 Bytes):
|
||
- 0x06,0x07,0x08: Druck (24-bit)
|
||
- 0x09,0x0A: Temperatur (16-bit)
|
||
|
||
============================================================
|
||
5) Umrechnung in Druck und Temperatur
|
||
============================================================
|
||
5.1 Druck (24‑Bit signed, Fullscale nötig)
|
||
Aus den drei Bytes:
|
||
- m = (x << 16) + (y << 8) + z (x=0x06, y=0x07, z=0x08)
|
||
|
||
Vorzeichenbehandlung:
|
||
- Wenn m > 2^23:
|
||
pressure = (m - 2^24) / 2^23 * Fullscale
|
||
- sonst:
|
||
pressure = m / 2^23 * Fullscale
|
||
|
||
WICHTIG:
|
||
Fullscale = Messbereich deines Sensors (z. B. 10 bar, 16 bar, 1.2 MPa, …)
|
||
Den musst du im Code passend setzen.
|
||
|
||
5.2 Temperatur (16‑Bit signed, Skalierung /256)
|
||
- n = (a << 8) + b (a=0x09, b=0x0A)
|
||
|
||
Vorzeichen & Skalierung:
|
||
- Wenn n > 2^15:
|
||
tempC = (n - 2^16) / 256
|
||
- sonst:
|
||
tempC = n / 256
|
||
|
||
============================================================
|
||
6) ESP32 Arduino-Beispielcode (Wire)
|
||
============================================================
|
||
WICHTIG: Setze FULLSCALE_BAR passend zu deinem Sensor!
|
||
|
||
```cpp
|
||
#include <Wire.h>
|
||
|
||
// --- I2C-Konfiguration ---
|
||
static constexpr uint8_t I2C_ADDR = 0x7F; // laut Hersteller-Tabelle (A7..A1 = 1)
|
||
static constexpr uint8_t REG_CMD = 0x30; // Command/Status Register
|
||
static constexpr uint8_t CMD_START = 0x0A; // Start: Temp + Pressure acquisition
|
||
|
||
// Datenregister
|
||
static constexpr uint8_t REG_DATA_START = 0x06; // 0x06..0x0A (5 Bytes)
|
||
|
||
// ESP32 Pins (anpassen falls nötig)
|
||
static constexpr int PIN_SDA = 21;
|
||
static constexpr int PIN_SCL = 22;
|
||
|
||
// --- Sensor-Messbereich (WICHTIG anpassen!) ---
|
||
static constexpr float FULLSCALE_BAR = 16.0f; // Beispiel: 16 bar Fullscale
|
||
|
||
// I2C: 1 Byte in Register schreiben
|
||
bool i2cWriteReg(uint8_t addr, uint8_t reg, uint8_t value) {
|
||
Wire.beginTransmission(addr);
|
||
Wire.write(reg);
|
||
Wire.write(value);
|
||
return (Wire.endTransmission() == 0);
|
||
}
|
||
|
||
// I2C: 1 Byte aus Register lesen
|
||
bool i2cReadReg(uint8_t addr, uint8_t reg, uint8_t &value) {
|
||
Wire.beginTransmission(addr);
|
||
Wire.write(reg);
|
||
if (Wire.endTransmission(false) != 0) return false; // Repeated start
|
||
if (Wire.requestFrom((int)addr, 1) != 1) return false;
|
||
value = Wire.read();
|
||
return true;
|
||
}
|
||
|
||
// I2C: mehrere Bytes ab Startregister lesen
|
||
bool i2cReadBytes(uint8_t addr, uint8_t startReg, uint8_t *buf, size_t len) {
|
||
Wire.beginTransmission(addr);
|
||
Wire.write(startReg);
|
||
if (Wire.endTransmission(false) != 0) return false; // Repeated start
|
||
int got = Wire.requestFrom((int)addr, (int)len);
|
||
if (got != (int)len) return false;
|
||
for (size_t i = 0; i < len; i++) buf[i] = Wire.read();
|
||
return true;
|
||
}
|
||
|
||
// Umrechnung nach Herstellerformeln
|
||
float convertPressureBar(uint8_t b0, uint8_t b1, uint8_t b2) {
|
||
uint32_t m = ((uint32_t)b0 << 16) | ((uint32_t)b1 << 8) | (uint32_t)b2;
|
||
|
||
// Hersteller: wenn m > 2^23 => negativ, sonst positiv
|
||
// 2^23 = 8388608, 2^24 = 16777216
|
||
float ratio;
|
||
if (m > 8388608UL) {
|
||
ratio = ((int32_t)m - 16777216.0f) / 8388608.0f;
|
||
} else {
|
||
ratio = (float)m / 8388608.0f;
|
||
}
|
||
return ratio * FULLSCALE_BAR;
|
||
}
|
||
|
||
float convertTempC(uint8_t b0, uint8_t b1) {
|
||
uint16_t n = ((uint16_t)b0 << 8) | (uint16_t)b1;
|
||
|
||
// Hersteller: wenn n > 2^15 => negativ
|
||
// 2^15 = 32768, 2^16 = 65536, Skalierung /256
|
||
float t;
|
||
if (n > 32768U) {
|
||
t = ((int32_t)n - 65536.0f) / 256.0f;
|
||
} else {
|
||
t = (float)n / 256.0f;
|
||
}
|
||
return t;
|
||
}
|
||
|
||
bool readPressureAndTemp(float &pressureBar, float &tempC) {
|
||
// 1) Messung starten (0x0A nach 0x30)
|
||
if (!i2cWriteReg(I2C_ADDR, REG_CMD, CMD_START)) return false;
|
||
|
||
// 2) Fertig abfragen (SCO = Bit3). Alternativ könnte man fix 50ms warten.
|
||
// Wir machen: kurze Warte + Polling mit Timeout.
|
||
const uint32_t t0 = millis();
|
||
while (true) {
|
||
uint8_t st = 0;
|
||
if (!i2cReadReg(I2C_ADDR, REG_CMD, st)) return false;
|
||
|
||
bool scoBusy = (st & (1 << 3)) != 0; // SCO bit3
|
||
if (!scoBusy) break;
|
||
|
||
if (millis() - t0 > 100) return false; // Timeout 100ms
|
||
delay(5);
|
||
}
|
||
|
||
// 3) 5 Bytes lesen: 0x06..0x0A
|
||
uint8_t data[5];
|
||
if (!i2cReadBytes(I2C_ADDR, REG_DATA_START, data, sizeof(data))) return false;
|
||
|
||
pressureBar = convertPressureBar(data[0], data[1], data[2]);
|
||
tempC = convertTempC(data[3], data[4]);
|
||
return true;
|
||
}
|
||
|
||
void setup() {
|
||
Serial.begin(115200);
|
||
delay(200);
|
||
|
||
Wire.begin(PIN_SDA, PIN_SCL);
|
||
Wire.setClock(100000); // 100 kHz als solider Start
|
||
|
||
Serial.println("I2C Drucksensor Start");
|
||
}
|
||
|
||
void loop() {
|
||
float pBar, tC;
|
||
if (readPressureAndTemp(pBar, tC)) {
|
||
Serial.print("Druck [bar]: ");
|
||
Serial.print(pBar, 3);
|
||
Serial.print(" | Temp [C]: ");
|
||
Serial.println(tC, 2);
|
||
} else {
|
||
Serial.println("Sensor-Lesefehler (I2C/Timeout).");
|
||
}
|
||
|
||
delay(200);
|
||
}
|
||
```
|
||
|
||
============================================================
|
||
7) Typische Stolpersteine & Debug
|
||
============================================================
|
||
1) Spannung wirklich 3,3 V?
|
||
Der Hersteller zeigt 3,3 V im Wiring-Bild. 5 V können je nach Sensor/Board problematisch sein.
|
||
|
||
2) I²C-Adresse 0x7F „ungewöhnlich“
|
||
Wenn dein I²C-Scanner nichts findet: trotzdem den Sensor direkt mit 0x7F testen.
|
||
|
||
3) Kabelfarben prüfen
|
||
Braun=V+, Blau=GND, Weiß=SDA, Schwarz=SCL.
|
||
|
||
4) Messbereich (Fullscale) falsch → Druckwerte falsch skaliert
|
||
Beispiel: 16 bar statt 10 bar führt zu Faktor 1,6.
|
||
|
||
5) Lange Leitungen in der Maschine
|
||
Bei Aussetzern:
|
||
- I²C-Clock reduzieren (z. B. 50 kHz oder 10 kHz)
|
||
- SDA/GND und SCL/GND verdrillen
|
||
- saubere Masseführung
|
||
|
||
Ende.
|