Plötzlich komisches verhalten Uno/Mega fehlerhafte Impulse

Hallo,

mir ist gestern etwas komisches aufgefallen.

Ich habe einen Uno + LCD an einen So-Bus Zähler angeschlossen.
Das Coding ist ganz schlicht. Es wird jeder Impuls(1000 Imp je kWh) gelesen und auf dem Display ausgegeben.

Das hat mehrere Tage super funktioniert, gestern wollte ich das Coding auf Interrupt umstellen. Leider ohne erfolg.
Also habe ich das alte Coding wieder hochgeladen.

Der So-Bus hängt an Digital 2. Ich bin dann durch Zufall gegen den Pin gekommen und musste feststellen er fängt an zu zählen.

Habe dann meinen Mega genommen und musste das gleiche verhalten feststellen.

In Kurzform:
Wenn ich den Pin 2 berühre, werden extrem viele Impulse gelesen.
Auch wenn ich den Arduino wieder an den So-Bus anschließe, zählt er plötzlich falsch.

Schaltung ist sehr überschaubar. GRD + Pin2

Hat jemand eine Idee was es sein kann?
Das Coding hatte ich im Internet gefunden und es hat auch wunderbar funktioniert.
Wenn Pin2 == High Zähler hochzählen.

Hat jemand einen Tipp für mich?

Dank und Grüße,
nox

Hier noch das Coding


#include <EEPROM.h>
#include <Arduino.h>  // for type definitions
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);    // Pinbelegung für SainSmart LCD Keypad Shield

const int IMPULSE = 1000;     // hier die Impulse pro kWh vom Stromzähler eintragen
const int long RECHENIMP = 3600000 / IMPULSE * 1000;
const int sobus = 2;
int long ElapsedTime = 0; 
int long StartTime = 0; 
int long WATT = 0; 
int long COUNT = 0; 
float KWH; 

int impState = 0;
int lastimpState = 0;

void setup() {
  
  pinMode(sobus, INPUT);             
  digitalWrite(sobus, LOW);   

  lcd.begin(16, 2);
  lcd.print("Boot...");
  delay(500);
}

void loop() {

  impState = digitalRead(sobus);      // Pin 2 auslesen

  if (impState != lastimpState) {
    if (impState == HIGH) {

      ElapsedTime = millis() - StartTime;
      StartTime = millis();
      WATT = RECHENIMP / ElapsedTime;

      COUNT++;

      KWH = (float)COUNT / IMPULSE;

      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Aktuell:");
      lcd.setCursor(9, 0);
      lcd.print(WATT);

      lcd.setCursor(0, 1);
      lcd.print("kW/h:");
      lcd.setCursor(9, 1);
      lcd.print(KWH);

      delay(20);
    }
  }

  lastimpState = impState;  
}
pinMode(sobus, INPUT);             
digitalWrite(sobus, LOW);

Was willst du denn damit erreichen? Ein digitaler Eingang mnuss immer ein definiertes Pegel haben, sonst fängt man sich massiv Störungen ein, der Pin wirkt wie eine Antenne. So wie es aussieht, brauchst du nur einen externen Pull-Down-Widerstand, wenn du auf impstate auf HIGH-Pegel prüfst.

Hi,

ursprünglich war es anders.

pinMode(sobus, INPUT);
digitalWrite(sobus, HIGH); <- Pullup

Leider hat es so nicht bei mir funktioniert.

Bin aktuell noch sehr neu in dem Thema.

<brauchst du nur einen externen Pull-Down-Widerstand, wenn du auf impstate auf HIGH-Pegel prüfst.

Wärst du so nett und würdest es etwas ausführen? Und ist es erklärbar, warum es eine kurze Zeit funktioniert hat?

Dank und Grüße,
nox

losNOXos:
ursprünglich war es anders.

pinMode(sobus, INPUT);
digitalWrite(sobus, HIGH); <- Pullup

Leider hat es so nicht bei mir funktioniert.

Input Signale offen lassen geht nicht. Mindestens wenn ein Stück Draht dranhängt, das auf der anderen Seite nicht verbunden ist, fängst du dir irgendein Signal, beliebig schnell wechselnd, ein.
Schau dir das Button-Beispiel an. Das benutzt einen PullDown Widerstand.

digitalWrite(sobus, HIGH);   //  Pullup ...sorgt dafür, dass ein offenes Eingangssignal sicher HIGH ist. Um ein LOW Signal zu erhalten, verbindest du es direkt mit GND ( z.B. über einen Taster ), ohne einen externen Widerstand zu brauchen.

Kleine Anmerkung:

pinMode(sobus, INPUT);             
digitalWrite(sobus, HIGH);

Dieser Code aktiviert den internen Pull-Up-Widerstand. Da diese beiden Zeilen aber (gerade für Anfänger) sehr verwirrend sind, kann man in den neueren Versionen der Arduino-IDE auch einfach: pinMode(sobus, INPUT_PULLUP); schreiben.
Einen internen Pull-Down-Widerstand gibt es übrigens nicht, wenn benötigt muss eben ein externer Widerstand vorgesehen werden.

Hi,

danke für die Tipps!

Aber eins verstehe ich einfach nicht. Warum ging es 2-3 Tage? Zufall?

Und noch eine viel wichtigere Frage, wie lernt man sowas? Einfach durch Erfahrung?
Elektro Studium?

Für Anfänger:
Wie unter dem Link "Button" angegeben, sollte ich eine Wiederstand auf GND legen?

Bin wie gesagt noch am lernen. Deswegen die für manche bestimmt "blöden" Fragen.

Dank und Grüße,
nox

losNOXos:
Aber eins verstehe ich einfach nicht. Warum ging es 2-3 Tage? Zufall?

Ja, Zufall und/oder günstige Bedingungen.

Und noch eine viel wichtigere Frage, wie lernt man sowas? Einfach durch Erfahrung?
Elektro Studium?

Ich glaube, die wenigsten haben hier ein Elektronik-Studium hinter sich. Es fällt aber auch nicht unter den Bereich Allgemeinwissen. Wenn man sich erst einmal damit auseinandergesetzt hat, denkt man von ganz allein an solche Sachen.

Für Anfänger:
Wie unter dem Link "Button" angegeben, sollte ich eine Wi~~e~~derstand auf GND legen?

Richtig erkannt, steht auch als Kommentar im Quellcode: * 10K resistor attached to pin 2 from ground

Bin wie gesagt noch am lernen. Deswegen die für manche bestimmt "blöden" Fragen.

Dafür gibt es ja das Forum, dass man Fragen stellen kann. Und irgendwann kann man was vom Gelernten wieder zurückgeben.

losNOXos:
Und noch eine viel wichtigere Frage, wie lernt man sowas? Einfach durch Erfahrung?
Elektro Studium?
Bin wie gesagt noch am lernen. Deswegen die für manche bestimmt "blöden" Fragen.

Es gibt keine blöden Fragen, nur blöde Antworten. Einige dieser "blöden" Fragen sind die fiesesten zu beantworten. :wink: :wink: :wink:
Das lernst Du aus Erfahrung, weil Du diese Fehler machst. Dann beim nächsten mal erinnerst Du Dich sicher und machst andere Fehler :wink: :wink: :wink:
Grüße Uwe

Hallo,

vielen Dank für eure Hilfe.
Stand jetzt scheint es zu funktionieren.

Leider bin ich dann direkt zu mutig geworden und wollte es mit einem Interrupt + DS18B20 versuchen.

Das funktioniert aber nicht so wirklich. Vermutlich benutze ich den Interrupt falsch.
Werde noch berichten ob ich Erfolg hatte.

Eine Frage habe ich noch. Ich scheine mit der Stromversorgung leichte Probleme zu haben. Ich wollte den Uno+LCD für den So-Bus Zähler über ein Iphone Lagegerät laufen lassen. Aber wenn ich das angeschlossen habe, wird auf dem LCD totaler quatsch angezeigt. Über das Notebook sieht es ok aus. Mag es an der fehlenden Leistung des Netzteils liegen?

Grüße,
nox

Wenn Du die Hintergrundbeleuchtung des Displays an hast: wahrscheinlich. Klemm diese mal ab.
Grüße Uwe

Hallo,

danke ich benutze ich ein andere Netzteil.

Auf den ersten Blick funktioniert jetzt alles. Leider aber nur auf den ersten.
Wenn der Arduino länger läuft, gehen die Zählerstände auseinander.
Zum Test habe ich schon einen einfachen Counter eingebaut, um mir die Takte ansehen zu können.

Das verhalten habe ich , wenn ich es mit Interrupt versuche und mit den alten Coding.

Hat noch jemand eine Idee? Bin mir langsam nicht mehr sicher, ob der Zähler auch wirklich 1000 imp/kWh ausgibt.

#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);    // Pinbelegung für SainSmart LCD Keypad Shield


const int IMPULSE = 1000;     // hier die Impulse pro kWh vom Stromzähler eintragen

const int long RECHENIMP = 3600000 / IMPULSE * 1000;

int long ElapsedTime = 0;
int long StartTime = 0;
int long WATT = 0;
int long COUNT = 0;
int counter;
float KWH;

int impState = 0;
int lastimpState = 0;


void setup() {
  lcd.begin(16, 4);
  lcd.print("Boot...");
  delay(200);
  lcd.clear();
  lcd.setCursor(0, 0);   
  lcd.print("BASTELGARAGE.de");
  delay(100);
  lcd.setCursor(0, 1);   
  lcd.print("EnergieMonitor");
  delay(400);

  pinMode(2, INPUT);             // Pin 2 als Eingang
  digitalWrite(2, HIGH);         // Interner Pullup Widerstand AN

}



void loop() {

  impState = digitalRead(2);      // Pin 2 auslesen

  if (impState != lastimpState) {
    if (impState == LOW) {

      counter++;

      ElapsedTime = millis() - StartTime;
      StartTime = millis();
      WATT = RECHENIMP / ElapsedTime;

      COUNT++;

      KWH = (float)COUNT / IMPULSE;

      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Aktuell:");
      lcd.setCursor(9, 0);
      lcd.print(WATT);

      lcd.setCursor(0, 1);
      lcd.print("kW/h:");
      lcd.setCursor(9, 1);
      lcd.print(KWH);
      lcd.setCursor(1, 2);
      lcd.print(counter);
      delay(20);
    }
  }
  lastimpState = impState;  
}

Grüße,
nox

Du schreibst auf dein LCD "Bastelgarage.de", die Seite habe ich mir mal angesehen. Da ist auch eine Abbildung deines Stromzählers mit einem kleinen Hinweis "1600 imp/kwh". Sollte das schon die Lösung sein? Oder hast du einen anderen Zähler zu überwachen?

Hi,

ja das kommt von da. Dachte es ist fair es erst mal drin zu lassen.

Die Impulse habe ich angepasst.

const int IMPULSE = 1000; // hier die Impulse pro kWh vom Stromzähler eintragen

Zum Test habe ich auch einen Counter eingebaut. Der Zählt einfach pro Impuls +1.

counter++;

Aber selbst der counter passt irgendwann nicht mehr.

Grüße,
nox

Mit welchem Sensor wertest du denn die Impulse aus?

Hi,

B+G
DRT428B - 3x 230/400V 20(80)A

Weiß langsam nicht mehr, wie ich den Fehler eingrenzen soll.

Das war ein versehen meinerseits. Im Startposing hast du ja geschrieben, dass du die S0-Schnittstelle anzapfst. Ich hatte noch ein vergleichbares projekt im Hinterkopf, wo jemand das Blinken der LED mit einem Fotowiderstand oder -transistor ausgewertet hat.

Hab mal nach deinem Stromzähler gegoogelt: http://www.debnar-messtechnik.de/DRT428B.pdf Passt es denn mit den angegebenen 800 Impulsen pro kWh besser? :wink:

Hi,

ich prüfe ich später noch mal.

Allerdings steht auf meinem Zähler 1000imp/kWh.

Und das sind auch keine 200 imp Unterschied.

Zählst du eigentlich zu viele Impulse gegenüber der Display-Anzeige oder zu wenige? Für den ersten Fall sollte man mal das Signal untersuchen, ob da irgendwelche Störungen drin sind. Nach den Spezifikationen der S0-Schnittstelle sollte ja eine bestimmte Mindestimpulslänge vorliegen. Eventuell könnte man das in den Code einbauen, dass bspw. nur Impulse gezählt werden, die mindestens 50 ms lang sind. pulseIn() kann das zwar, blockiert aber auch den Programmablauf ähnlich einer delay()-Anweisung, zum Testen reicht das aber im Allgemeinen aus.

Hi,

es werden zu viele Impulse gezählt. Allerdings nicht sofort, sondern erst mit der Zeit.
Habe schon mit Delay rumgespielt, leider ohne erfolg.

Auch Interrupt nutzen hat leider keine Veränderung gebracht.

Ich werte es später genau aus und melde mich noch mal.

Danke!
nox

Du sollst ja auch kein delay benutzen, sondern testweise die pulseIn-Funktion, um ausschließlich entsprechend lange Impulse zu messen. Laut dem von mir verlinkten Datenblatt soll so ein Impuls etwa 90 ms dauert. Somit würde ich alles verwerfen, was kürzer als 50 ms ist - vielleicht gibt es kurze Störungen/Unterbrechungen im Signal, die das Ergebnis verfälschen.