Hi @my_xy_projekt ,
ich habe das Ganze bei Wokwi mal ergänzt (nicht vollständig!).
https://wokwi.com/projects/420594289441266689
/*
Forum: https://forum.arduino.cc/t/alkoholtestsensor-ze29a-c2h5oh-mit-arduino-verbinden-und-daten-lesen/1344484
Wokwi: https://wokwi.com/projects/420594289441266689
// Wokwi: https://wokwi.com/projects/420536876646490113
*/
const int frameLen {9};
const byte statusCmd[frameLen] {0xFF, 0x01, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A};
const byte readResultsCmd[frameLen] {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
const byte setIdleStateCmd[frameLen] {0xFF, 0x01, 0x87, 0x31, 0x00, 0x00, 0x00, 0x00, 0x47};
const byte setWarmUpStateCmd[frameLen] {0xFF, 0x01, 0x87, 0x32, 0x00, 0x00, 0x00, 0x00, 0x48};
const unsigned long cmds[] {statusCmd, readResultsCmd, setIdleStateCmd, setWarmUpStateCmd};
const int noOfCmds = sizeof(cmds) / sizeof(cmds[0]);
unsigned long lastRequestTime = 0;
int count = 0;
byte testerStatus = 0x31;
byte command[frameLen];
byte response[frameLen];
// Nur für Alkoholtester-Simulation
// ******************************
byte antwort[frameLen];
byte request[frameLen];
// ******************************
void setup() {
Serial.begin(115200); // Für die Kommunikation mit dem PC
Serial1.begin(9600);
Serial2.begin(9600);
Serial.println("Initialisierung des Sensors...");
delay(2000); // Wartezeit für Stabilisierung
}
void loop() {
sendCommand();
receiveResponse();
// Die folgende Zeile muss bei Anschluss eines echten Alkoholtesters
// auskommentiert werden ...
simulateAlkoTester();
}
void sendCommand() {
if (millis() - lastRequestTime > 1000) {
lastRequestTime = millis();
// Sende Befehl zum Lesen des Status
byte* cmd = cmds[count];
Serial1.write(cmd, frameLen);
count++;
if (count >= noOfCmds) {
count = 0;
}
}
}
void receiveResponse() {
// Empfange Antwort
if (Serial1.available()) {
Serial1.readBytes(response, 9);
Serial.print("Antwort des Sensors:\t");
for (int i = 0; i < 9; i++) {
Serial.print("0x");
Serial.print(response[i], HEX);
Serial.print(" ");
}
Serial.println();
handleResponse();
}
}
void handleResponse() {
// Auswertung der Daten
switch (response[1]) {
case 0x85:
decodeStatus();
break;
case 0x86:
decodeTestresult();
break;
case 0x87:
decodeStateCmds();
break;
}
}
void decodeStateCmds() {
if (response[2] == 1) {
Serial.println("Sensor-Status geändert");
} else {
Serial.println("Sensor-Status konnte nicht geändert werden");
}
}
void decodeStatus() {
switch (response[2]) {
case 0x31:
Serial.println("Sensor ist im Leerlauf.");
break;
case 0x32:
Serial.println("Sensor im Aufwärmmodus.");
break;
case 0x33:
Serial.println("Sensor wartet auf Blasen.");
break;
case 0x34:
Serial.println("Sensor im Blasmodus.");
break;
case 0x35:
Serial.println("Blasmodus abgebrochen");
break;
case 0x36:
Serial.println("Berechnungsstatus");
break;
case 0x37:
Serial.println("Sensor zeigt Testergebnisse an.");
break;
}
}
void decodeTestresult() {
int AlkoholWert = int(response[2]) * 256 + response[3];
Serial.print("Alkoholwert = ");
Serial.print(AlkoholWert);
Serial.println(" mg/100ml");
}
// *********************************************************************
// ************* Ab hier AlkoTester Simulation ************************
// *********************************************************************
void simulateAlkoTester() {
if (Serial2.available()) {
Serial2.readBytes(request, 9);
handleRequest();
}
}
void handleRequest() {
if (request[0] != 0xFF) return;
for (int i = 0; i < frameLen; i++) {
antwort[i] = 0x00;
}
antwort[0] = 0xFF;
antwort[1] = request[2];
switch (request[2]) {
case 0x85:
// Status Rückmeldung
antwort[2] = testerStatus;
break;
case 0x86:
// Read Testresult
antwort[2] = 0x00;
antwort[3] = 0x5A;
antwort[7] = 0x02;
break;
case 0x87:
// Switch Module Working Status
switchStates();
break;
}
byte checkSum = 0;
for (int i = 1; i < frameLen - 1; i++) {
checkSum += antwort[i];
}
antwort[frameLen - 1] = -checkSum;
Serial2.write(antwort, frameLen);
}
void switchStates() {
switch (request[3]) {
case 0x31:
antwort[2] = 0x01;
testerStatus = 0x31;
break;
case 0x32:
antwort[2] = 0x01;
testerStatus = 0x32;
break;
default:
// Dieser Status kann nicht gesetzt werden
antwort[2] = 0x02;
break;
}
}
- Serial2 simuliert Rückmeldung des Alkoholtesters gemäß der Doku.
- Serial1 sendet Kommandos, empfängt und decodiert Rückmeldungen.
Die Zeile
3. Check value algorithm: (negative (data 1 + data 2 + ... + data 7)) + 1.
passt m.E. nicht zu den Beispieldaten. Die Checksumme in den Beispielen ergibt sich wie folgt:
byte checkSum = 0;
for (int i = 1; i < frameLen - 1; i++) {
checkSum += antwort[i];
}
antwort[frameLen - 1] = -checkSum;
Den Sketch könnte man jetzt a) für alle Kommandos vervollständigen und b) die AlkoTester-Simulation in eine Klasse in einer include-Datei umwandeln, um sie komplett zu kapseln.

Gruß
ec2021