Gas- und Stromzählerprojekt ATmega32 - Reedkontakt Problem

Gast #3965166
Lesenswert?

Ich habe vor kurzem damit angefangen mich mit der Programmierung des 
ATmega32 zu beschäftigen. Ich wollte nun mein erstes "richtiges Projekt" 
starten und habe mir vorgenommen meinen Strom- und Gaszähler zu 
überwachen.
Die Überwachung des Stromzählers funktioniert soweit. Es ist ein 
elektronischer Stromzähler, bei dem eine LED 1000 mal pro KWh blinkt. 
Ich überwache das Blinken mit einer Fotodiode - das funktioniert 
einwandfrei.

Das Problem ist mein Gaszähler. Es handelt sich um folgenden:
http://www.cd-k.de/2012/11/installation-nf-impulsnehmer-ni-3-fur-metrik-gaszahler/
Von meinem Gasversorger habe ich den passenden Reedkontakt bekommen. 
Eigentlich dachte ich, das wird einfach, aber der Reedkontakt macht mich 
wahnsinnig. Ich weiss nicht genau woran es liegt. (Prellen ?) Der 
Reedkontakt schließt, wenn die letzte Stelle am Gaszähler in etwa bei 
der 8 ist und öffnet ca. bei der 2 (das dauer ca. 5 Sekunden). Eine 
ganze Umdrehung dauert ca. 13 Sekunden.

Ich habe folgendes bisher versucht:
1. interner Pullup: mein Programm erhöht den Zählerstand um 0,003 pro 
Umdrehung der letzten Ziffer des Gaszähler
2. externer Pullup mit 100KOhm: +0.002 pro Umdrehung
3. externer Pullup mit 400kOhm: +0.001 pro Umdrehung. Ich dachte mit 
schon, dass es nun passen würde, ABER mein Zähler hat sich um 0.020 in 1 
Stunde erhöht, obwohl die Gastherme ausgeschaltet war ?!?!?
4. ich habe Versuche mit RC- Gliedern gemacht (100KOhm + 100nF, 10KOhm + 
100nF): meine Anzeige steigt ca. 0.010 pro Umdrehung.

Da mir das Equipmet fehlt, habe ich versucht mit dem Eingag meiner 
Soundkarte das Ein- und Ausschaltsignal des Reedkontaktes zu analysieren 
um etwaiges Prellen zu erkennen (siehe Anhang). Keine Ahnung ob dies 
geeignet ist, aber ich kann kein Prellen erkennen.

Jedenfalls bin ich mit meinem Latein jetzt am Ende.

Vielleicht kann mir von euch jemand weiter helfen.
Vielen Dank.

PS: ich weiß es gibt fertige Sachen wie zB den volkszaehler, aber ich 
wollte ja etwas lernen.
Angehängte Dateien:
Gast #3965388
Lesenswert?

Also ein C parallel hat es eigentlich verschlechtert.

Der Reedkontakt ist in der dafür vorgesehenen Einkerbung und es ist auch 
der, welcher für den Gaszähler vorgesehen ist.

DSO? Da ich nicht weiss was das ist, denke ich nicht, dass ich das habe.

Wenn es das Prellen ist, warum wird dann in einer Stunde ca. 20mal 
gezählt ohne das sich der Gaszähler auch nur einen Millimeter gedreht 
hat?
Gast #3965528
Lesenswert?

Liegt wohl am anstrengenden Tag, aber irgendwie verstehe ich überhaupt 
nicht, was du mit dem Code bezwecken willst.

if (PIND & (1<<PD3)) PORTD |= (1<<PD5);
if (!(PIND & (1<<PD3))) PORTD &= ~(1<<PD5);
=> Ich weiß nicht welche Zeiten da wirken, aber das sollte man mit einem 
'else' lösen. Wer weiß (gerade bei Blitzen), wie lange sie dauern und 
nachher beide Bedingungen hintereinander erfüllt sind.

ISR(INT0_vect){ //INT0 Interrup Stromzähler PD2 - Fotodiode
  i_start = i_ende;
  i_ende = (sekunde * 1000) + ms;
  kwh_gesamt = kwh_gesamt + 0.001;
}
=> Verstehe ich auch nicht.
Und um vom verschwenderischen float wegzukommen, kann man ja z.B. 
erstmal bis 1.000 zählen. Generell ist einfaches Zählen der Blitze wohl 
sinnvoll(er).

ISR(INT1_vect){ //INT1 Interrupt Gaszähler PD3 - Reedkontakt
        gasstand = gasstand + 0.01;
    }
=> Wenn du so ungefähr deine elend lahme "Drehgeschwindigkeit" kennst...
Interrupt wird ausgelöst. Die ISR ist wohl extrem flott abgearbeitet. 
Rückkehr zum Hauptprogramm. Was passiert wohl dann (immer noch)?
Datenblatt des Impulsnehmers: • Impulsdauer min.: 0,3s
Ich glaube nicht, daß das was mit der externen Beschaltung zu tun hat. 
Zumal der ja extra dafür gemacht ist.
Gast #3966876
Lesenswert?

Micha schrieb:
> Wenn du + 0.001etwas schreibst, rechnest Du mit floats? Gibt es da
> eventuell Rundungsfehler? Zahl einfach mal die Impulse in Int und
> Entprellen (hard oder Software). Am besten zeige mal den source-code.

Dachte ich Anfangs auch. Ich habe zur Überwachung schon mal eine 
Int-Variable mitzählen lassen. Diese wird genauso oft hochgezählt wie um 
0,001 erhöht wird. Also kein Rundungsfehler.



Michael L. schrieb:
> Was fehlt:
> - Eingangsschaltung am ATmega
> - Leitungslänge zum Reed-Kontakt

Zur Eingangsschaltung gibts nicht viel zu sagen. Bei internem Pullup ein 
Kontakt auf PD3 und einer auf Masse. Bei externem Pullup habe ich einen 
Kontakt auf PD3 und einen auf Masse wobei eben noch ein Widerstand gegen 
5V hängt.
Leitungslänge sind ca. 2 Meter. Vom Gaszähler durch die Aussenwand 
direkt zum AVR. Dort sind keine anderen elektrischen Leitungen.



Lutz schrieb:
> Liegt wohl am anstrengenden Tag, aber irgendwie verstehe ich überhaupt
> nicht, was du mit dem Code bezwecken willst.
>
> if (PIND & (1<<PD3)) PORTD |= (1<<PD5);
> if (!(PIND & (1<<PD3))) PORTD &= ~(1<<PD5);
> => Ich weiß nicht welche Zeiten da wirken, aber das sollte man mit einem
> 'else' lösen. Wer weiß (gerade bei Blitzen), wie lange sie dauern und
> nachher beide Bedingungen hintereinander erfüllt sind.

Es hängt nur eine LED an PD5. Sollte nur eine optische Anzeige zum Test 
sein, ob der Reedkontakt offen oder geschlossen ist.

Lutz schrieb:
> ISR(INT0_vect){ //INT0 Interrup Stromzähler PD2 - Fotodiode
>   i_start = i_ende;
>   i_ende = (sekunde * 1000) + ms;
>   kwh_gesamt = kwh_gesamt + 0.001;
> }
> => Verstehe ich auch nicht.
> Und um vom verschwenderischen float wegzukommen, kann man ja z.B.
> erstmal bis 1.000 zählen. Generell ist einfaches Zählen der Blitze wohl
> sinnvoll(er).

Hat nichts mit dem Gaszähler zu tun, sondern mit dem Stromzähler. Ich 
zähle die Zeit zwischen 2 Impulsen der LED am Stromzähler und berechne 
damit den momentanen KWh Verbrauch. Das funktioniert eigentlich.


Es stimmt, dass der Reed nicht entprellt wird. Was ich aber trotzdem 
nicht verstehe ist:
Wenn der Gaszähler ein paar Stunden still steht, dann wird trotzdem ein 
paar mal hochgezählt. Und warum verschlechtert sich das Ganze noch, wenn 
ich parallel einen Kondensator anschliesse.
Ich habe heute nochmals ein wenig getestet und werde einfach nicht 
schlau daraus.
Gast #3966916
Lesenswert?

prinzmi schrieb:
> Hat nichts mit dem Gaszähler zu tun, sondern mit dem Stromzähler.
Weiß ich, war auch nur ein Hinweis.

prinzmi schrieb:
> Ich
> zähle die Zeit zwischen 2 Impulsen der LED am Stromzähler und berechne
> damit den momentanen KWh Verbrauch. Das funktioniert eigentlich.
Nö. Oder ich habe es falsch verstanden.
1.000 Blitze entsprechen 1 kWh. Wenn du also Blitze zählst, zählst du 
Arbeit. Also, wieviel Arbeit du verbraucht hast. Ob jetzt die 1.000 
Blitze in einer Minute oder in einer Stunde gezählt wurden, ist egal: Du 
hast 1 kWh verbraucht.
Wenn du die Zeit zwischen 2 Blitzen zählst, dann mißt du die momentane 
Leistung ("den momentanen Stromverbrauch in Watt").

prinzmi schrieb:
> Es stimmt, dass der Reed nicht entprellt wird.
Ich glaube, daß er wegen des konkret bestimmten Anwendungsfalls schon 
von Haus aus entprellt ist.
Du kannst ja spaßeshalber mal die Zeit zwischen den Flanken messen. Laut 
deinem Link muß sie > 0,3 s sein.

prinzmi schrieb:
> Wenn der Gaszähler ein paar Stunden still steht, dann wird trotzdem ein
> paar mal hochgezählt.
Das ist in der Tat merkwürdig. Stromversorgung o.k?

Leider funktioniert dein Link zum Gaszähler nicht.
Was ich aber (schon wieder) gar nicht verstehe:
ISR(INT1_vect){ //INT1 Interrupt Gaszähler PD3 - Reedkontakt
        gasstand = gasstand + 0.01;
    }
Wie können da Steigerungen von 0.001 und 0.002 entstehen???
Gast #3967019
Lesenswert?

Lutz schrieb:
> Wenn du die Zeit zwischen 2 Blitzen zählst, dann mißt du die momentane
> Leistung ("den momentanen Stromverbrauch in Watt").

Stimmt natürlich - mein Fehler. Ich messe damit die Watt.

Lutz schrieb:
> Du kannst ja spaßeshalber mal die Zeit zwischen den Flanken messen. Laut
> deinem Link muß sie > 0,3 s sein.

Wenn du mit Flanken die Zeit zwischen dem Schließen und dem wieder 
Öffnen des Reedkontaktes meinst, dann beträgt diese im 
"Rauchfangkehrbetrieb" (ich glaube das heisst so. Die Therme läuft dabei 
mit voller Leistung.) meiner Gastherme ca. 5 Sekunden. Die offene Zeit 
beträgt ca. 8 Sekunden, dh eine Umdrehung der letzten Stelle des 
Gaszähler dauert ca. 13 Sekunden. Im "normalen" Betrieb kann das auch 
länger dauern, da die Therme nicht immer mit voller Leistung läuft.



Lutz schrieb:
> Das ist in der Tat merkwürdig. Stromversorgung o.k?

Ich habe das Ganze auf einem Pollin Evaluationsboard laufen. Netzteil 
hat 8V mit 1.2A.



Lutz schrieb:
> Wie können da Steigerungen von 0.001 und 0.002 entstehen???

Wieder mein Fehler. Ich habe mich verschrieben. Natürlich meinte ich 
0.01.
Gast #3967080
Lesenswert?

In der main:
DDRD = 0b1110000;
DDRA = 0b0000000;
Wohl hier egal, aber sind das absichtlich jeweils nur 7 statt 8 bit?

Das Entprellen (obwohl ich das hier nicht als Problem erwarte) kannst du 
auch quick&dirty so machen: Wenn Vollgas (im wahrsten Sinne des Wortes) 
13 Sekunden sind (schneller geht nicht), kannst du in der ISR den 
Interrupt ja die nächsten z.B. 11 Sekunden sperren. Sollte in der Zeit 
ein Impuls kommen, muß er falsch sein und kann nichts anrichten.
Das ändert aber nichts an dem Problem, daß er zählt, wenn der Gaszähler 
steht. Und da vermute ich auch das Problem.

Wie hast du den Sensor denn angeschlossen? Er hat ja 2 Kontakte. Wenn du 
beide gleichzeitig überwachst (ist ja der Sinn), hast du eine höhere 
Sicherheit: Wenn der eine geschlossen ist, muß der andere offen sein. 
Und umgekehrt. Nur dann ist es ein gültiger Impuls. Kann ja auch in der 
ISR überprüft werden.
#3967242
Lesenswert?

prinzmi schrieb:
> Es stimmt, dass der Reed nicht entprellt wird. Was ich aber trotzdem
> nicht verstehe ist:
> Wenn der Gaszähler ein paar Stunden still steht, dann wird trotzdem ein
> paar mal hochgezählt. Und warum verschlechtert sich das Ganze noch, wenn
> ich parallel einen Kondensator anschliesse.

Ein Kondensator allein ist kein Tiefpass. Es kann eher sein, dass du in 
Verbindung mit der Leitungslänge (Induktivität) einen Empfänger für 
Störsignale gebastelt hast.

> Ich habe heute nochmals ein wenig getestet und werde einfach nicht
> schlau daraus.

Blindes Probieren bringt dich nicht weiter. Was hilft, ist eine 
vernünftige Entprellung in Software. Aber nicht den Vorschlag 
(quick&dirty) 11 Sekunden die ISR sperren. Statt dessen solltest du nur 
dann einen Impuls zählen, wenn der Reed-Kontakt mindestens 0,5 Sekunden 
geschlossen war. Öffnet er vor Ablauf der Zeit, ist der Impuls zu 
ignorieren. Das sollte alle beschriebenen Problemfälle abdecken.
Gast #3968503
Lesenswert?

Lutz schrieb:
> In der main:
> DDRD = 0b1110000;
> DDRA = 0b0000000;
> Wohl hier egal, aber sind das absichtlich jeweils nur 7 statt 8 bit?
Keine Absicht. Ist ein Fehler. Danke.


Lutz schrieb:
> Wie hast du den Sensor denn angeschlossen? Er hat ja 2 Kontakte.
Ich habe nur braun/grün angeschlossen. Weiss/geld dachte ich eigentlich, 
dass ich nicht brauche (Sabotagekontakte).


Michael L. schrieb:
> Ein Kondensator allein ist kein Tiefpass.
Hatte ich immer in Verbindung mit einem Widerstand als RC Glied.


Michael L. schrieb:
> Statt dessen solltest du nur
> dann einen Impuls zählen, wenn der Reed-Kontakt mindestens 0,5 Sekunden
> geschlossen war.
An sowas in der Art habe ich auch schon gedacht und habe darum vorhin 
den Code etwas verändert.

Ich dachte mir folgendes. Ich frage einfach im Sekundentakt den Zustand 
des Reedkontaktes ab, und speichere den Zustand der letzten 5 Sekunden 
in einem Array reed_ist. Steht in dem Array dann 0,0,1,1,1 (0=Reed 
geschlossen, 1=Reed offen), dann zähle ich meinen Zähler um 0,01 hoch.
Beim einschalten des AVR wird ebenfals einmal der Zustand des 
Reedkontaktes überprüft. Wenn dieser geschlossen ist wird reed_ist mit 
{0,0,0,0,0} und wenn er offen ist mit {1,1,1,1,1} befüllt.
Das ist die ISR Routine, die im Sekundentakt den Zustand überprüft. Was 
meint ihr dazu? Mit einem Taster funktioniert das Ganze gut. Ich werde 
es morgen oder übermorgen mit dem Reedkontakt testen.

1
ISR(TIMER1_OVF_vect) { //TIMER1 Overflow einmal pro s Eingang PD3 abfragen
2
  TCNT1 = 49911; //Zählregister mit Vorladewert
3
  
4
  for (i=0; i<5; i++) reed_ist[i] = reed_ist[i+1]; //Werte des Array nach links verschieben
5
  
6
  if (PIND & (1<<PD3)) reed_ist[4] = 1; //aktuellen Status in die letzte Stelle des Array schreiben
7
    else reed_ist[4] = 0;
8
  
9
  if (memcmp(reed_ist, reed_soll, 5) == 0) gasstand = gasstand + 0.01; //Arrays vergleichen
10
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren