Wenn AB das Bitmuster einer int8_t Variable ist, ist diese negativ und hat den Wert -85.
-85 in Hex Darstellung ist FFFFFFAB
Also es handelt sich um ein EHEIM Visit-02 mit RS232 und 9600 Baud. Alles richtig angeschlossen an einen Arduino Uno mit RS232 Shield von joy-it an Pin 2&3.
Wobei es auch über Hterm gesendet bei dem Sketch aus meinem ersten post FFFFFFAB am seriellen Monitor ausgibt.
Muss ich dann die Variable anders deklarieren um positive Werte zu bekommen?
read() liefert nicht umsonst int zurück (und nicht char)
Wenn dein gewünschter Wertebereich 0 .. 255 ( oder -1 für nichts da ) ist, wäre int ausnahmsweise mal richtig.
Wenn die -1 schon weggefiltert ist, wäre auch der Datentyp byte möglich.
Ansonsten kann man in C++ auf zig Arten Datentypen anders behandeln als sie eigentlich definiert sind. Man muss sich aber in jedem Fall um Datentypen von Variablen kümmern.
konkret ist der Auslöser in deinem Sketch diese Zeile
char rs232_inChar;
du willst nicht character empfangen sondern binäre Daten.
Wenn du das auf uint8_t änderst, gibt es keinen Überlauf wenn bytes >127 eintreffen und dann kommt der print auch damit zurecht und es wird korrekt ausgegeben.
Ich habs mal mit den Test-Nachrichten mit denen ich meinen Sketch getestet habe probiert:
mit char schlagen die Überläufe im print zu,
mit uint8_t ist es in Ordnung.
da du außen rum eine Prüfung auf available hast, reicht ein byte. Aber du brauchst eben einen unsigned Typ.
Der Sketch funktioniert einwandfrei. Das Problem war nur das die Werte bereits dezimal ankommen. Wenn man die Startbits dezimal angibt macht es genau das was es soll.
Vielen Dank dafür!!
Kann ich jedoch noch Relais schalten und Pausen einfügen?
Sobald ich ein delay in den Loop einfüge findet kein Update der Werte statt und es wird nur Null ausgegeben.
nein Delay ist verboten. Der Parser muss in der Lage sein hereinkommende Zeichen zeitgerecht auszulesen bevor der Eingangsbuffer überläuft.
wenn "Timer" notwendig sind, so machen wie bei der zeitgesteuerten Ausgabe auf die serielle Schnittstelle
timerOutput()
Das Beispiel zeigt ja auch: es erfolgt laufend ein einlesen, die Ausgabe aber nur alle paar Sekunden.
MIch hätte ja mal interessiert, was der Code aus #7 so hergibt.
Der Code gibt immer die ersten 15 Bytes aus und nennt sie immer an Indexposition 118.
Da fehlt der Zähler...
Ersetze mal bitte das case:
case 118 ... 120:
Serial.print(F("IndexPosition: "));
Serial.print(idx);
Serial.print('\t');
Serial.print(F("Inhalt: "));
Serial.println(rs232_inChar, HEX);
idx++;
break;
Ja, das funktioniert dann!!
Mit dem verarbeiten der einzelnen Werte und gleichzeitig ein Relais steuern komme ich aber leider nicht voran.
Du könntest fragen. Wenn Du Dein aktuelles Programm zeigst, könnte man Dir vermutlich helfen.
So nu ist die Frage, was Du da verarbeiten willst und was das Relais wann machen soll.
Ich hab das mal neu gebaut mit der LED auf dem UNO, die dann schön vor sich her blinkt um Dir zu zeigen, das Du Dir dafür eine Funktion schreiben kannst.
Bei den Werten musst Du schauen, ob das case 118 ... 120 wirklich stimmt und nicht etwa 117 ... 119 sein soll. Ich hab das oben in Konstanten gepackt, wann angefangen werden soll die Werte aufzunehmen und wann beendet.
#include <SoftwareSerial.h>
SoftwareSerial RS232(2, 3);
byte rs232_inChar;
byte idx;
constexpr byte startbyte {118};
constexpr byte endbyte {120};
byte wert[endbyte - startbyte] = {0};
void setup()
{
Serial.begin(9600);
while (!Serial)
{}
RS232.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
einlesen();
ausgeben();
heartBeat(1000);
}
void einlesen()
{
if (RS232.available() > 0)
{
rs232_inChar = RS232.read();
{
// *INDENT-OFF*
switch (idx)
{
case 0:
[[fallthrough]]
case 2: if (rs232_inChar == 0x56) { idx++; } else { idx = 0; } break;
case 1: if (rs232_inChar == 0xAB) { idx++; } else { idx = 0; } break;
case 3: if (rs232_inChar == 0x20) { idx++; } else { idx = 0; } break;
case 4 ... startbyte-1: { idx++; } break;
case startbyte ... endbyte:
Serial.print(F("IndexPosition: "));
Serial.print(idx);
Serial.print('\t');
Serial.print(F("Inhalt: "));
Serial.println(rs232_inChar, HEX);
wert[idx-startbyte]=rs232_inChar;
idx++;
break;
default:
idx = 0;
break;
}
// *INDENT-ON*
}
}
}
void ausgeben()
{
static uint32_t lastValue = 0;
uint32_t myValue = 0;
for (byte b = 0; b < endbyte - startbyte; b++)
{ myValue += wert[b]; }
if (idx > endbyte && lastValue != myValue)
{
lastValue = myValue;
Serial.print(F("Neuer Wert erkannt: "));
Serial.println(myValue);
}
}
void heartBeat(uint32_t blinkTime)
{
static uint32_t lastBlink = 0;
if (millis() - lastBlink > blinkTime)
{
lastBlink = millis();
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.print(F("BLINKLED: "));
Serial.println(digitalRead(LED_BUILTIN) ? F("EIN") : F("AUS"));
}
}
Ja, das geht schon in die Richtung bzw. bringt es mich ein bisschen weiter den Aufbau zu verstehen.
Ich habe jetzt mal versucht es weiter anzupassen. Leider kann ich es aber zurzeit nicht testen.
Der Ablauf soll dann folgend aussehen:
-Relais1 an PIN 4 öffnen
-X Sekunden warten (zum testen ist X=5)
-Werte berechnen und ausgeben
-Relais 1 schließen
-wiederholen für Relais 2-4
-nach Relais4 alles abbrechen
Ich werde dann voraussichtlich morgen mal testen ob es irgendetwas macht oder ob ich mir nur Mist ausgedacht habe.
#include <SoftwareSerial.h>
SoftwareSerial RS232(2, 3);
long myTimer = 0;
long myTimeout = 5000;
byte rs232_inChar;
byte O2;
byte H2S1;
byte H2S2;
byte H2S3;
byte H21;
byte H22;
byte H23;
byte CO21;
byte CO22;
byte CO23;
byte CH41;
byte CH42;
byte CH43;
byte idx;
int Relais = 4;
void setup()
{
digitalWrite(Relais, HIGH); // öffnet Relais1 an PIN 4
Serial.begin(9600);
while (!Serial)
{
;
}
RS232.begin(9600);
}
void loop()
{
einlesen();
timer_und_ausgeben();
}
void timer_und_ausgeben()
{
if (millis() > myTimeout + myTimer ) {
myTimer = millis();
Serial.print(O2 /10);
Serial.print(" Vol.-%;");
Serial.print(H2S1 + H2S2 * 256 + H2S3 * 65536);
Serial.print(" ppm H2S;");
Serial.print(CO21 + CO22 * 256 + CO23 * 65536);
Serial.print(" ppm CO2;");
Serial.print(CH41 + CH42 * 256 + CH43 * 65536);
Serial.println(" ppm CH4;");
digitalWrite(Relais, LOW);
Relais = Relais + 1;
if (Relais = 8) {exit(0);} //beendet Lauf nach Relais 7
else
{ digitalWrite(Relais, HIGH);
}
}
}
void einlesen()
{
if (RS232.available() > 0)
{
rs232_inChar = RS232.read();
{
// *INDENT-OFF*
switch (idx)
{
case 0:
[[fallthrough]]
case 2: if (rs232_inChar == 86) { idx++; } else { idx = 0; } break;
case 1: if (rs232_inChar == 171) { idx++; } else { idx = 0; } break;
case 3: if (rs232_inChar == 2) { idx++; } else { idx = 0; } break;
case 4 ... 116: { idx++; } break;
case 117: O2 = rs232_inChar; break;
case 118: H2S1 = rs232_inChar; break;
case 119: H2S2 = rs232_inChar; break;
case 120: H2S3 = rs232_inChar; break;
case 121: H21 = rs232_inChar; break;
case 122: H22 = rs232_inChar; break;
case 123: H23 = rs232_inChar; break;
case 124: CO21 = rs232_inChar; break;
case 125: CO22 = rs232_inChar; break;
case 126: CO23 = rs232_inChar; break;
case 127: CH41 = rs232_inChar; break;
case 128: CH42 = rs232_inChar; break;
case 129: CH43 = rs232_inChar; break;
idx++;
break;default:
idx = 0;
break;
}
// *INDENT-ON*
}
}
}
Da sind einige Patzer drin.
Als erstes:
Da fehlt das festlegen, das der PIN ein OUTPUT ist.
Und hier:
bist Du ganz und gar auf dem Holzweg.
Der Teil hier wird Dir das Genick brechen.
Relais wird immer 8 sein und damit ist die Bedingung immer erfüllt.
Warum hast Du meinen Vorschlag mit der Berechnung der richtigen Start- und Endposition nicht übernommen?
millis() ist vom Typ unsigned long.
myTimer wird also nicht ausreichen und überlaufen.
Ausserdem ist das hier:
in die Zukunft gerechnet.
Da kommt es im Falle des Überlaufes beim addieren zu eigenartigen Effekten....
Ziehe von millis() die letzte gemerkte Zeit ab und vergleiche die Differenz mit dem von Dir gewünschten Timeout. Das funktioniert dann auch im Falle des Überlaufes.
Und hier:
ist irgendwas ganz schief gegangen.
Also vor dem ersten Test nochmal überarbeiten ![]()
Ja, da habe ich wohl was verwechselt.
Der Teil hier wird Dir das Genick brechen.
technikum:
if (Relais = 8) {exit(0);} //beendet Lauf nach Relais 7Relais wird immer 8 sein und damit ist die Bedingung immer erfüllt.
Da fehlt ja etwas. ![]()
Warum hast Du meinen Vorschlag mit der Berechnung der richtigen Start- und Endposition nicht übernommen?
Die Berechnung habe ich nicht wirklich verstanden und daher es versucht mit dem bereits getesteten zu realisieren.
Ausserdem ist das hier:
technikum:
if (millis() > myTimeout + myTimer ) {in die Zukunft gerechnet.
Da kommt es im Falle des Überlaufes beim addieren zu eigenartigen Effekten....
Ziehe von millis() die letzte gemerkte Zeit ab und vergleiche die Differenz mit dem von Dir gewünschten Timeout. Das funktioniert dann auch im Falle des Überlaufes.
Ich bin davon ausgegangen, dass es bei einer maximalen Laufzeit von 3 Stunden ausreichen würde. Werde es aber jetzt noch ändern.
Und hier:
technikum:
case 129: CH43 = rs232_inChar; break; idx++; break;default: idx = 0; break;ist irgendwas ganz schief gegangen.
Ist hier das default nicht richtig eingerückt?
Also vor dem ersten Test nochmal überarbeiten
Wird gemacht. Bei mir läuft es leider zurzeit immer noch nach dem try and error-Prinzip. ![]()
Ist hier das default nicht richtig eingerückt?
Nö.
Aber das idx++ ist zwischen zwei break und das passt ganz und gar nicht. ;
Die Berechnung habe ich nicht wirklich verstanden
Die war gar bicht so schwer.
Das startByte ist das erste, welches Du auswerten willst.
Daher ist das letzte, was einfach durchläuft und nur den idx auslöst startbyte-1
Das endbyte ist das letzte Byte, welches Du auswerten willst.
Die Differenz aus endbate - startbyte ist Deine Anzahl bytes die Du liest.
Du löst es jetzt ein wenig anders.
Las Dir erstmal die Daten richtig ausgeben.
Benutze viel Serial.print().
Dann sehen wir weiter.
Die Differenz aus endbate - startbyte ist Deine Anzahl bytes die Du liest.
Ja, ich habe nicht rausbekommen wie die einzelnen Werte Variablen zuordne.
Und ja viel Serial.print() sollte ich bis zum Ende noch einfügen.
Hallo,
vielen Dank nochmal an alle die geholfen haben.
Das größte Problem ist gelöst und über die Feinheiten muss ich mir noch Gedanken machen.
Hier noch der fertige Sketch:
#include <SoftwareSerial.h>
#include <SD.h>
const int chipSelect = 10;
SoftwareSerial RS232(2, 3);
long myTimer = 0;
long myTimeout = 240000;
byte rs232_inChar;
float O2;
byte H2S1;
byte H2S2;
byte H2S3;
byte H21;
byte H22;
byte H23;
byte CO21;
byte CO22;
byte CO23;
byte CH41;
byte CH42;
byte CH43;
byte idx;
int i = 4;
int s = 1;
int t = 1;
void setup() {
// PIN 4-9 und 14-15 als Output für Relais
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
digitalWrite(i, HIGH); // öffnet Relais1 an PIN 4
Serial.begin(9600);
while (!Serial)
;
RS232.begin(9600);
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
while (1)
;
}
Serial.println("card initialized.");
}
void einlesen() {
if (RS232.available() > 0) {
rs232_inChar = RS232.read();
{
// *INDENT-OFF*
switch (idx) {
case 0:
[[fallthrough]] case 2 : if (rs232_inChar == 86) {
idx++;
}
else {
idx = 0;
}
break;
case 1:
if (rs232_inChar == 171) {
idx++;
} else {
idx = 0;
}
break;
case 3:
if (rs232_inChar == 2) {
idx++;
} else {
idx = 0;
}
break;
case 4 ... 116:
{
idx++;
}
break;
case 117: O2 = rs232_inChar;
case 118: H2S1 = rs232_inChar;
case 119: H2S2 = rs232_inChar;
case 120: H2S3 = rs232_inChar;
case 121: H21 = rs232_inChar;
case 122: H22 = rs232_inChar;
case 123: H23 = rs232_inChar;
case 124: CO21 = rs232_inChar;
case 125: CO22 = rs232_inChar;
case 126: CO23 = rs232_inChar;
case 127: CH41 = rs232_inChar;
case 128: CH42 = rs232_inChar;
case 129:
CH43 = rs232_inChar;
idx++;
break;
default:
idx = 0;
break;
}
// *INDENT-ON*
}
}
}
void timer_und_ausgeben() {
if (millis() - myTimer > myTimeout) {
myTimer = millis();
Serial.print("Gassack: ");
Serial.print(s);
Serial.print("; ");
Serial.print(O2 / 10);
Serial.print(" Vol.-%;");
Serial.print(H2S1 + H2S2 * 256 + H2S3 * 65536);
Serial.print(" ppm H2S;");
Serial.print(H21 + H22 * 256 + H23 * 65536);
Serial.print(" ppm H2;");
Serial.print(CO21 + CO22 * 256 + CO23 * 65536);
Serial.print(" ppm CO2;");
Serial.print(CH41 + CH42 * 256 + CH43 * 65536);
Serial.println(" ppm CH4;");
Serial.println(millis());
File dataFile = SD.open("datalog.txt", FILE_WRITE);
// if the file is available, write to it:
if (dataFile) {
dataFile.print(" Gassack: ");
dataFile.print(t);
dataFile.print(" ;");
dataFile.print(O2 / 10);
dataFile.print(";Vol.-% O2;");
dataFile.print(H2S1 + H2S2 * 256 + H2S3 * 65535);
dataFile.print(";ppm H2S;");
dataFile.print(H21 + H22 * 256 + H23 * 65535);
dataFile.print(";ppm H2;");
dataFile.print(CO21 + CO22 * 256 + CO23 * 65535);
dataFile.print(";ppm CO2;");
dataFile.print(CH41 + CH42 * 256 + CH43 * 65535);
dataFile.print(";ppm CH4 ;");
dataFile.print(O2);
dataFile.print(" ;");
dataFile.print(H2S1);
dataFile.print(";H2S1;");
dataFile.print(H2S2);
dataFile.print(";H2S2;");
dataFile.print(H2S3);
dataFile.print(";H2S3;");
dataFile.print(H21);
dataFile.print(";H21;");
dataFile.print(H22);
dataFile.print(";H22;");
dataFile.print(H23);
dataFile.print(";H23;");
dataFile.print(CO21);
dataFile.print(";CO21;");
dataFile.print(CO22);
dataFile.print(";CO22;");
dataFile.print(CO23);
dataFile.print(";CO23;");
dataFile.print(CH41);
dataFile.print(";CH41;");
dataFile.print(CH42);
dataFile.print(";CH42;");
dataFile.print(CH43);
dataFile.print(";CH43;");
dataFile.println();
dataFile.close();
}
t = t + 1;
digitalWrite(i, LOW);
delay(120000);
myTimeout=360000;
s = s + 1;
i = i + 1;
if (i == 10) i = 14;
// if (i == 16) i = 4;
if (i == 16) {
Serial.print("Ende der Messung");
exit(0); //beendet Lauf nach Relais 8
}
} else
digitalWrite(i, HIGH);
}
void loop() {
einlesen();
timer_und_ausgeben();
}
if (millis() - myTimer > myTimeout) {
Das wirft Dir eine Warnung aus.
Zu recht!
Und die solltest Du unbedingt beheben.
Hier:
case 117: O2 = rs232_inChar; case 118: H2S1 = rs232_inChar; case 119: H2S2 = rs232_inChar; case 120: H2S3 = rs232_inChar; case 121: H21 = rs232_inChar; case 122: H22 = rs232_inChar; case 123: H23 = rs232_inChar; case 124: CO21 = rs232_inChar; case 125: CO22 = rs232_inChar; case 126: CO23 = rs232_inChar; case 127: CH41 = rs232_inChar; case 128: CH42 = rs232_inChar; case 129: CH43 = rs232_inChar; idx++; break;
solltest Du nochmal in Dich gehen - das wird nicht das was Du willst... (Abgesehen von der Warnung, die dann aber weg ist, wenn das richtig ist ![]()