Nachdem das erste Projekt (ISKRA und Momentanwertauswertung - Nulleinspeisung) hänge ich nun am anderen Projekt. Um das auslesen des Gesamtwertes in ein anderes Projekt einbauen zu können, muss es erst mal richtig funktionieren.
Im folgenden Sketch wird ein Datenblock von 120 Byte eingelesen, anschließend mit der Suche nach dem Gesamtwert vortgesetzt. Sobald er gefunden ist, wird er errechnet und auf dem seriellen Monitor ausgegeben.
Nun soll eigentlich der Rest der eingelesenen Daten komplett gelöscht und ein neuer Block eingelesen werden. um einen aktuellen Wert zu filtern.
Allerding gibt es nur weitere Werte aus dem vorher gelesenen Block, bist dieser abgearbeitet ist. Erst dann wird gelöscht und neu eingelesen.
Leider finde ich den Fehler nicht, welcher wahrscheinlich einfach ist, aber mitlerweile habe ich Scheuklappen auf.
#include <Wire.h>
#include <SoftwareSerial.h>
#include <SPI.h>
SoftwareSerial mySerial(D3, D5); // D3 RX, D5 nicht benutzt, da ISKRA M681 keinen IR Eingang zur Kommunikation der SML zulässt
constexpr uint16_t maxSize{ 200 }; // Speichergröße für einen Dump
byte myByte[maxSize] = { 0 }; // Speicherinhalt auf 0 setzen
uint16_t idx = 0; // Index initialisieren
int wert19, wert20, wert21, wert22; // Werte des Gesamtverbrauchs
int LED = D4; // Ausgang LED zur Anzeige Daten aus Zähler lesen
long lastValueFound = millis(); // Zeitwert zur Abschaltung der Heizung bei Verlust von Daten
unsigned long lastReadTime = 0; // Zeitstempel für 10 Sekunden Abfrage
void setup() {
Serial.begin(115200);
mySerial.begin(9600);
pinMode(LED, OUTPUT); // LED Ausgang setzen
}
void loop() {
// Prüfen, ob Daten vorhanden sind und lesen dieser
if (mySerial.available()) {
digitalWrite(LED, HIGH); // LED einschalten, wenn Daten empfangen werden
myByte[idx] = mySerial.read();
idx++;
// Verhindere Überlauf des Indexes
if (idx >= maxSize - 1) {
idx = maxSize - 1;
}
} else {
digitalWrite(LED, LOW); // LED ausschalten, wenn keine Daten empfangen werden
}
// Verarbeite die Daten, wenn genug Bytes empfangen wurden
if (idx > 140) {
boolean valueFound = false;
for (uint16_t i = 0; i < 140; i++) {
// Suche nach der Byte-Reihe für den Gesamtwert
if (((myByte[i]) == 119) && ((myByte[i + 1]) == 7) && ((myByte[i + 2]) == 1) && ((myByte[i + 3]) == 0) &&
((myByte[i + 4]) == 1) && ((myByte[i + 5]) == 8) && ((myByte[i + 6]) == 0) && ((myByte[i + 7]) == 255)) {
valueFound = true;
// Gesamtverbrauchswerte berechnen
wert19 = myByte[i + 19]; wert20 = myByte[i + 20]; wert21 = myByte[i + 21]; wert22 = myByte[i + 22];
long dezimalwert = (long(wert19) << 24) | (long(wert20) << 16) | (long(wert21) << 8) | long(wert22);
float Bezug = (dezimalwert / 10000.0000); // Gesamtleistung in kWh
Serial.print("Bezug: "); Serial.println(Bezug, 4);
// Speicher leeren und Index zurücksetzen
clearBuffer(); idx = 0; break;
}
}
if (!valueFound) {
clearBuffer();
idx = 0;
}
}
// Verhindere Überlaufen des Speichers durch regelmäßige Leerung
if (millis() - lastReadTime > 10000) { // Alle 10 Sekunden
lastReadTime = millis();
if (idx > 0) {
clearBuffer();
idx = 0;
}
}
}
// Funktion zum Leeren des Speichers
void clearBuffer() {
for (uint16_t i = 0; i < maxSize; i++) {
myByte[i] = 0;
}
}
Ich hoffe, das jemand das Problem erkennt.Schon mal danke
weil Datenschutz ? oder glaubst du etwa die neu eingelesene Daten werden die alten nicht überschreiben können?
wie ich sehe brauchst du nur 23 Bytes. Wieso dann nicht nur die letzte 23 zu speichern?
eigentlich könnte man auch darauf verzichten und die 8 Bytes des Erkennungsverfahrens nur mitzählen, sobald alle 8 gezählt sind werden 12 folgende ignoriert und dann 4 weitere zusammen addiert.
#include <Wire.h>
#include <SoftwareSerial.h>
#include <SPI.h>
SoftwareSerial mySerial(D3, -1); // D3 RX, D5 nicht benutzt, da ISKRA M681 keinen IR Eingang zur Kommunikation der SML zulässt
const uint32_t Abtatstrate = 10000;//ms
const byte LED = D4; // Ausgang LED zur Anzeige Daten aus Zähler lesen
const byte Chain[] = {0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xff};
void setup() {
Serial.begin(115200);
mySerial.begin(9600);
pinMode(LED, OUTPUT); // LED Ausgang setzen
}
void loop() {
static uint32_t oldMillis = 0;
if (millis() - oldMillis < Abtatstrate)while (mySerial.available() > 0)mySerial.read();
else {
digitalWrite(LED, HIGH); // LED einschalten, wenn Daten empfangen werden
delay(20);
if (mySerial.available() > 22) {
bool itsOK = true;
for (byte i = 0; i < 8; i++) {
byte CurrByte = mySerial.read();
if (CurrByte != Chain[i]) {
itsOK = false;
i = 8;
}
}
if (itsOK) {
oldMillis += Abtatstrate;
for (byte i = 0; i < 11; i++)mySerial.read();
uint32_t dezimalwert = 0;
for (byte i = 0; i < 4; i++) {
dezimalwert = (dezimalwert << 8) | mySerial.read(); // es ist nicht klar ob die Daten wirklich decimal sind oder doch float
}
digitalWrite(LED, LOW); // LED ausschalten, wenn keine Daten empfangen werden
Serial.print("Bezug: "); Serial.println(dezimalwert); // mal sehen was es ausgibt
}
}
else {
digitalWrite(LED, LOW); // LED ausschalten, wenn keine Daten empfangen werden
delay(20);
}
}
}
Das ist mir schnuppe, ob überschreiben oder vorher löschen. Es soll funktionieren.
Ja, aber man muss sie erst mal finden in dem Block.
Das verstehe ich nicht. Leider ist es nicht einfach diese Daten zu finden und auszurechnen . Aber das ist ja auch garnicht das Problem. Das finden und rechnen funktioniert ja. Das Problem ist, wie beschrieben, das er nur den ersten Wert in dem kompletten Block finden, errechnen und ausgeben soll, dann den rest in diesem Block ignorieren und einen neuen Block einlesen (oder den alten Block überschreiben) um dann einen aktuellen Wert ausgeben soll
So war der Plan, ist aber nicht aufgegangen, deshalb habe ich hier die Anfrage gestartet.
Ich erhalte als Ausdruck jedesmal 2-4 gleiche Werte, dann eine kurze Pause und dann erst neue Werte.
Ich werde Dir aber nicht weiterhelfen.
Selbst wenn ich es könnte.
Dieses Gefummel abseits der Gegegebenheiten ist eben nur ein Gefummel und damit Fehleranfällig und wird Dir immer wieder auf die Füße fallen.
z.B. dieses Konstrukt:
if (idx > 140)
{
boolean valueFound = false;
for (uint16_t i = 0; i < 140; i++)
{
// Suche nach der Byte-Reihe für den Gesamtwert
if (((myByte[i]) == 119) && ((myByte[i + 1]) == 7) && ((myByte[i + 2]) == 1) && ((myByte[i + 3]) == 0) &&
((myByte[i + 4]) == 1) && ((myByte[i + 5]) == 8) && ((myByte[i + 6]) == 0) && ((myByte[i + 7]) == 255))
{
Was soll der Unterschied sein? Der Sketch ließt einen Block ein (200Bytes : constexpr uint16_t maxSize{ 200 };)
Dann fängt er an, in diesem Block nach dem passenden Code für den Gesamtverbrauch zu suchen. Hat er ihn gefunden, errechnet er den Wert und gibt ihn auf dem Monitor aus. Dann soll er eigentlich den Block löschen, oder auch überschreiben mit den nächsten 200Byte. Das macht er aber nicht, sondern sucht in dem alten Block weiter und gibt mir den nächsten gefundenen Wert aus. Erst wenn er alle 2-4 enthaltenen Werte gefunden hat, ließt er wieder einen neuen Block ein. Das ist der eigentliche Fehler.
Nun möchte ich wissen, warum nach der ersten Rechnung kein neuer Block eingelesen wird.
Wusste nicht, das das so ein Aufruhr erzeugt, tut mir leid, aber es ist nur eine Frage.
Lässt sich kompilieren und drauf spielen. Die LED flackert, wenn kein Signal reinkommt, leuchtet (jedenfallsaugenscheinlich) bei Signaleingang.
Der serielle Monitor zeigt leider garnichts
Ich habe beim meinem Sketch das i und das idx mit auf den Monitor genommen und nach der Ausgabe eine ein sekündige Pause eingefügt. Jetzt sieht die Ausgabe so aus:
das kommt wenn gesuchte Sequenz zu nah am Ende ist so liest es außer gefüllten Bereich die Nullen die du beim Leeren reinschreibst.
und warst darüber gewarnt:
ich würde ehe fragen was würde passieren wenn i = 132 ? so wird es viel mehr offensichtlich.