Forum: Mikrocontroller und Digitale Elektronik Gas- und Stromzählerprojekt ATmega32 - Reedkontakt Problem


von prinzmi (Gast)


Angehängte Dateien:

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.

von Gasmann (Gast)


Lesenswert?

Bei mir hat ein C mit 100n parallel zum Reedschalter Wunder bewirkt.
Oder Du versuchst es mit Softwaredebouncing.

von J. W. (jw-lighting)


Lesenswert?

Der Reedkontakt ist in der richtigen Lage zum Magnetfeld ausgerichtet?
Hast du den Kontakt im Programm entprellt?

Kannst du mit einem DSO die steigende und fallende Flanke des 
Reedkontaktes ansehen, um ein längeres Prellen auszuschließen?

von prinzmi (Gast)


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?

von prinzmi (Gast)


Lesenswert?


von Micha (Gast)


Lesenswert?

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.

von Micha (Gast)


Lesenswert?

Sorry, hatte den angehängten code nicht gesehen...

von Michael L. (michaelx)


Lesenswert?

Mögliche Ursachen:
- Prellen des Reed-Kontakts
- Einstreuung von Störsignalen in die Leitung des Reed-Kontakts
- Zählen bzw. Rechnen mit ungeeigneten Datentypen

Was fehlt:
- Eingangsschaltung am ATmega
- Leitungslänge zum Reed-Kontakt

: Bearbeitet durch User
von H.Joachim S. (crazyhorse)


Lesenswert?

Michael L. schrieb:
> Mögliche Ursachen:

> - Einstreuung von Störsignalen in die Leitung des Reed-Kontakts

Das wird wohl der springende Punkt sein.
Schau nach einer Minimallänge des Signals und schmeiss alles andere als 
Störung weg.

von Lutz (Gast)


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.

von Michael L. (michaelx)


Lesenswert?

H.Joachim Seifert schrieb:
> Michael L. schrieb:
>> Mögliche Ursachen:
>
>> - Einstreuung von Störsignalen in die Leitung des Reed-Kontakts
>
> Das wird wohl der springende Punkt sein.

Einer von mehreren, ich hab grad noch den Code "entdeckt" ...

Tatsächlich wird mit float Variablen gezählt.
Es wird in der ISR nicht entprellt.

: Bearbeitet durch User
von prinzmi (Gast)


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.

von Lutz (Gast)


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???

von prinzmi (Gast)


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.

von prinzmi (Gast)


Lesenswert?

Lutz schrieb:
> Leider funktioniert dein Link zum Gaszähler nicht.

Der Gaszähler ist ein Metrix 6G4L:
http://www.apator.com/de/produkte/gas-messung/haushaltsgaszaehler/6g4l-einstutzen

Das Datenblatt des Reedkontakts:
http://heathungary.hu/doc/text/metrix_impulzusado.pdf

von Lutz (Gast)


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.

von Michael L. (michaelx)


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.

von prinzmi (Gast)


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
}

von Michael L. (michaelx)


Lesenswert?

Ehe du weiter irgendwelche Experimente zusammenbastelst, schau doch mal 
hier in den Artikel:

http://www.mikrocontroller.net/articles/Entprellung

Unten bei "Timer-Verfahren (nach Peter Dannegger)" findest du ein gutes 
Beispiel in ASM und C.

von prinzmi (Gast)


Lesenswert?

Ich wollte nur noch einmal kurz Bescheid geben, dass es mit der Methode 
den Eingang im Sekundentakt zu überprüfen seit ein paar Tagen ohne 
Probleme funktioniert.
Vielen Dank für eure Hilfe!

Jetzt fehlt mir eigentlich nur mehr der Wasserzähler ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.