Pulserfassung per Interrupt - Irgendwas mach ich falsch :-)

Uwe H.

Neues Mitglied
27. Juli 2011
264
0
0
Hinter die Grenze :-)
Sprachen
  1. BascomAVR
  2. ANSI C
  3. Assembler
Gruesst euch Jungs :)

Ich sitz grad mal wieder an einer kleinen Herausforderung, die so simpel ist, dass meine komplexe Denkweise die Loesung uebersieht *lol*
In einem aktuellen Projekt soll ich ein paar Zaehler ablesen (Gas, Wasser). Das Ganze soll interruptgesteuert laufen, damit mir kein Puls entwischt, die Signalgeber sind Reedkontakte, die ich leider nicht gegen Hallsensoren austauschen kann. Interrupt ist ueber int. Pullup auf 1 und soll auf fallende Flanke reagieren. Die "0" wird je nach Zaehler fuer mehrere Sekunden gehalten oder sogar laenger, wenn der Zaehlermagnet unter dem Reed anhaelt. Routine sieht so aus:


Code:
Hauptroutine:

             'Programmroutine

   If Pind.3 = 1 And Isrflag = &HFF Then   'Wenn der INT-Pin wieder auf 1 ist"
     Isrflag = &H00                                   'Flag loeschen
     Waitms 100                                      'Einflattern des Reeds
     Enable Int1                                    
   End If


  Loop
 End
.............................................................................................
Code:
ISR:

    Waitms 25                               'Einflattern des Reeds
    Disable Int1                              
    Isrflag = &HFF                          'Flag dient zum Reaktivieren des Interrupts nachdem der Pin in den Zustand "1" zurueckgekehrt ist
    Incr Impulsecounter                  'zaehlt den Impulszaehler hoch
    Gasmeter = Gasmeter + 0.1     'zaehlt den internen Zaehlerstand hoch (zur kontrolle, vom Master wird nur der Impulsecounter ausgelesen und im Master addiert)
 Return
'------------------------------------------------------------------------------

Problem in der Routine ist, dass zuviele Impulse gelesen werden. Innerhalb einer Woche Testlauf wurden 100 Impulse zuviel erfasst, was 10m3 Gas entspricht. Wenn ich danebenstehe und die Zaehlervariabeln am Laptop checke, laeuft alles tadellos. Vielleicht hat jemand ne bessere Loesung?

Gruesse aus Polen

Uwe
 
Hi Uwe,

was mir als erstes auffällt ... In einer ISR nen Waitms25 zu nehmen ist nicht so dolle. Da muß ne andere Lösung her.
Wenn der Impuls für mehrere Sekunden anhält, dann benötigt man normalerweise keinen Interrupt. Das geht wunderbar über Polling. Nur wenn der Impuls im µs/ms-Bereich ist würde ich nen Interrupt verwenden.

So ein Zähler (zB Wasserzähler) hat auch die unangenehme Eigenschaft wieder ein wenig zurückzulaufen wenn man das Wasser abdreht. Das hab ich bei unserem schonmal bemerkt. Das kleine rote Rädchen was einem anzeigt das was durchfließt dreht sich ein wenig zurück.

Ich würde das mit nem Polling und entsprechender Logik machen.

Wie lange bleibt dieser Reed-Kontakt im Normalfall mindestens geschlossen? Diese Zeit würde ich als Sperrzeit nehmen.

Wenn der Impuls anfängt, dann würde ich nen Flag setzen (Impuls) und für diese Sperrzeit nichts mehr am Eingang annehmen. Erst nach dieser Sperrzeit würde ich ein Ende des Impulses annehmen und das Impulsflag zurücksetzen. Damit hast du eventuelles Zurücklaufen schonmal erledigt. Erst wenn das Impulsflag wieder zurückgesetzt ist, nimmt er einen neuen Impulsanfang an.

Die Sperrzeit würde ich irgendwie über nen Timer erzeugen (notfalls mit ner Zählervariable für ne längere Zeit).

Gruß
Dino
 
Hi Dino,

die 25ms Wartezeit sind die Entprellung des Reeds, wie bei Debounce. Der Interrupt setzt ein Flag, zaehlt die Zaehler hoch und kehrt umgehend in die Hauptroutine zurueck, um das Programm nicht bis zum "reseten" des Pegels zu blockieren. Dort wird per Polling der Pegel weiter abgefragt und das Flag zurueckgesetzt und der Interrupt reaktiviert, wenn der Pegel wieder auf "1" steigt. Das geht auch ohne weiteres.

Die Pulslaenge haengt vom Verbrauch und vom Zaehler ab. Die Heizsektionen laufen langsam, Hauptwasserzaehler dreht extrem schnell, Gaszaehler irgendwo dazwischen. Aber alle Zaehler haben eine extra Ruecklaufsperre, die einen erneuten Pulse verhindert. Ich will die fallende Flanke (sprich den Ausloeser) per INT erfassen, weil das Hauptprogramm pro Durchlauf mehrere Sekunden braucht und mit Wartezeiten und viel Kommunikation arbeitet. Per Polling verliere ich je nach Zaehlerdrehzahl den einen oder anderen Impuls, da ich waehrend den Kommunikationsvorgaengen nicht Pollen kann. Deshalb via INT.
 
Hi Uwe
weil das Hauptprogramm pro Durchlauf mehrere Sekunden braucht und mit Wartezeiten und viel Kommunikation arbeitet
Eine Antwort auf deine Frage "was mache ich falsch"
Wartezeiten im Hauptprogramm ! Also, Zykluszeiten von mehreren Sekunden ist in etwa so, als würdest du zu Fuss von Hamburg nach München laufen. Kommunikation, gut, das kann etwas Zeit kosten, aber doch keine Sekunden einen Zyklus blockieren.
Ich hab es nicht mit BASCOM, aber ich denke, einen Timer kannst du dort auch einrichten. Daher: Wartezeiten von Timer ableiten. Ich mach das in Assembler auch so. Ich habe einen Timer, der jede mSek. einen Interrupt auslöst. Ein Zähler bis 100 in der ISR hochgezählt liefert Zehntelsekunden. Dazu setze ich ein Zeitflag, ein Bit oder auch mehrere für verschiedene Zeitabschnitte, welches ich im Hauptprogramm abfrage und wenn gesetzt, weitere Schritte einleite. Dann wird das Zeitflag wieder gelöscht. So bekommt dein Programm nur für die kurze Zeit etwas zu tun. Das belastet den Zyklus kaum.
Punkt 2 Kommunikation:
Wenn eine Erhöhung der Baudrate nicht möglich ist, dann die Pakete kleiner schnüren, ja zur Not halt pro Zyklus nur ein Zeichen senden. Oder das Senden eines Zeichens per Interrupt einrichten. Dann hat der Controller auch Zeit, sich um sein Programm zu kümmern. Es macht keinen Sinn einen Datentransfer über mehrere Sekunden aufzubauen und dann eine halbe Stunde später das gleiche Spiel. Das macht deinen Controller nicht berechenbar, denn du musst so arbeiten, als wäre jeder Zyklus so lang.
Das du Signale mit Interrupt erfasst, ist ja nicht verwerflich, aber wenn du in der ISR Wartezeiten einbaust, um die Signale zu entprellen, ist in dieser Zeit der Rest abgemeldet. Auch andere Interrupts werden ignoriert. Daher ist der Interrupt lediglich geeignet, das Signal zu erfassen, abarbeiten solltest du dann wieder in einer optimierten Programmschleife, deren Zyklus vielleicht ein paar mSek. dauert.
Ich kann dir nur Empfehlen, löse dich von Programmteilen, die den Zyklus ausbremsen und prüfe, ob du nicht mehr auf Ereignisse programmieren kannst. Ich bin auch der festen Überzeugung, ein richtig aufgebautes Programm kann mech. Kontakte, und nichts anderes ist ein Reedkontakt fast immer Pollen. erst wenn du mir sagst, deine Zykluszeit liegt oberhalb 10 mSek und dein Signal liegt unterhalb dieser Zeit, dann geht nur Interrupt. Aber 10 mSek sind bei 8 MHz rd. 40000 Befehle.
Also, denk da noch mal über dein Programmkonzept nach. Da ist sicherlich noch Potential.
Gruß oldmax
 
Code:
ISR:

    Waitms 25                               'Einflattern des Reeds
    Disable Int1                              
    Isrflag = &HFF                          'Flag dient zum Reaktivieren des Interrupts nachdem der Pin in den Zustand "1" zurueckgekehrt ist
    Incr Impulsecounter                  'zaehlt den Impulszaehler hoch
    Gasmeter = Gasmeter + 0.1     'zaehlt den internen Zaehlerstand hoch (zur kontrolle, vom Master wird nur der Impulsecounter ausgelesen und im Master addiert)
 Return
'------------------------------------------------------------------------------

Hallo Uwe,
da Gasmeter eine Floating Point Variable zu sein scheint, hast du daran gedacht, die zusätzlichen Register R12-R15 zu sichern?
Die werden standardmäßig nicht gesichert, wodurch ganz seltsame Effekte entstehen können.
Geht z.B. so:
On Int1 ISR SaveAll

Siehe auch in der Hilfe unter "On Interrupt".
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)