Pages: [1]   Go Down
Author Topic: Impulsmessung für Durchflussmesser  (Read 1920 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Sr. Member
****
Karma: 2
Posts: 381
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

hab mir wieder was Neues ausgesucht :-)
Ich will einen Durchflussmesser an meinen Arduino hängen. Der bringt wohl so max 1000 Impulse / Minute.
Da jetzt mit der millis() Funktion rumzuspielen, glaub ich ist nicht der Burner.
Hab mir mal die PulseIn-Funktion angeschaut, aber die bringt ja nur die Länge des High bzw. Low-Anteils zurück.
Ich bräuchte aber die Zeitspanne zwischen 2 gleichen Flanken.
Da wär was Interrupt gesteuertes eher zu gebrauchen.

Kann mir da jemand einen Schubs in die richtige Richtung geben?

gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hänge das Ding an Pin 2 oder 3 (INT 0 oder 1), mit attachInterrupt() kannst Du einen entsprechenden Handler einrichten, dort kriegst Du mit micros() eine höher auflösende Zeitmessung.
Logged

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 260
Posts: 21566
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Du kannst ka mal den H Teil und dann den L Teil des Impulses messen. Du mißt zwar einige Impulse später aber so schnell ändert sich die Frequenz nicht. Es ist zu kontrollieren wie sich die Impulse mit der Änderung der Frequenz ändern. Wenn sie sich proportional zur frequenz ändern dann kannst Du auch nur den H oder L Teil messen.
Grüße Uwe
Logged

Germany
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3030
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hänge das Ding an Pin 2 oder 3 (INT 0 oder 1), mit attachInterrupt() kannst Du einen entsprechenden Handler einrichten
Du brauchst nur entweder die kommende oder die gehende Flanke.
Statt micros kannst du im Handler auch nur die Anzahl Impulse zählen.
Und in loop dann alle (paar) Sekunden die neue Impulsdifferenz als Durchfluss ermitteln. (So kriegst du auch gleich eine 0, wenn keine Impulse kommen)

Allerdings muss in loop kurzzeitig noInterrupts(); gesetzt werden, während eine Aktion mit einer volatile unsigned long Variablen  gemacht wird, da Operationen mit Werten > 1 byte unterbrochen werden könnten... 
Logged

Offline Offline
Sr. Member
****
Karma: 2
Posts: 381
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hänge das Ding an Pin 2 oder 3 (INT 0 oder 1), mit attachInterrupt() kannst Du einen entsprechenden Handler einrichten, dort kriegst Du mit micros() eine höher auflösende Zeitmessung.

Glaube, dass wird die beste Methode sein, da ich nebenbei noch andere Sachen am laufen habe, wie z.B. einen Webserver.
Läuft das dann so?
Code:
attachInterrupt("PIN", "SUB", RISING)
Für PIN trage ich die 2 oder 3 ein, SUB ist der name meines Unterprogrammes, und RISING bedeutet, daß er bei jeder positiven Flanke ins Unterprogramm springt.
Im Unterprogramm kann ich dann das Delta von micros() auswerten und habe so meine Zeit zwischen 2 Impulsen. Der Rest ist dann reine Mathematik.
Richtig so?
Muss wohl aufpassen, daß ich alle 70 Minuten den Overflow rausfiltere. Oder ich mach das so, wie im Playground, wo der Overflow von millis() abgefangen wird.

Das mit dem Interrupt macht er doch hoffentlich so, wie man es landüblich gewohnt ist:
Beim Interrupt bricht er das laufende Anwenderprogramm ab, rettet die Speicherinhalte, läuft durch die Interrupt-Routine, und springt dann wieder zur Abbruchstelle mit den vorher geretteten Speicherinhalten zurück? Oder muss ich mich da um irgendwas kümmern?

gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Germany
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3030
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


attachInterrupt( 0, irhandler, RISING);

Nicht Pin 2 / 3, sondern Interrupt 0 / 1 !
Und der Funktionsname natürlich nicht als String ( für alle Fälle, sorry falls dir das klar war )

Oder muss ich mich da um irgendwas kümmern?
Nein, das stimmt schon so.

Kümmern musst du dich um Variable, die gemeinsam vom Interrupt-Handler und der Hauptroutine verwendet werden:
s. Schlüsselwort "volatile", um falsche Compiler-Optimierungen zu vermeiden.

Und bedenke, dass im Zugriff auf solche Variable die Hauptroutine "mittendrin" unterbrochen werden kann, da wir auf einem 8bit Prozessor arbeiten.
Ich würde die IR Routine so einfach wie möglich halten :

Code:
volatile unsigned long pulses;
void irhandler() { pulses++;}

const unsigned int CYCLE = 1000;  // z.B. je Sekunde, oder so oft, dass die Anzahl Pulse genau eine Durchfluss-Einheit ist
unsigned long lastpulses;
unsigned long lastmillis;
void loop ()
{
  unsigned long now=millis();
  if (now - lastmillis >= CYCLE)  
  {
    noInterrupts();
    unsigned long pcount = pulses - lastpulses;
    lastpulses = pulses;
    interrupts();
    lastmillis += CYCLE;
    Serial.print (pcount); Serial.println ( " pulse/s ");
  }
}

Die Implementierung von setup() überlasse ich dir smiley-wink

edit: Syntax verbessert, aber immer noch ungeprüft
« Last Edit: October 28, 2012, 05:34:27 am by michael_x » Logged

Offline Offline
Sr. Member
****
Karma: 2
Posts: 381
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi michael_x
THX  smiley-cool


attachInterrupt( 0, irhandler, RISING);

Nicht Pin 2 / 3, sondern Interrupt 0 / 1 !
Und der Funktionsname natürlich nicht als String ( für alle Fälle, sorry falls dir das klar war )
Ne ne schon klar, hab den Befehl nur "angedeutet". Aber das mit dem Pin<->INT hätte ich wohl falsch gemacht.

Aber so ist der Ansatz vllt. besser: Impulse/pro Zeit zählen, und nicht die Zeit zwischen Impulsen messen.
Ich hab sowieso eine Sub, die ich alle Sekunden aufrufe, da kann ich dann die Impulse verarbeiten :-)
Evtl. noch untersetzen, falls es zu wenig Impulse sind.

Das mit "volatile" hab ich noch nie gebraucht.... Muss ich mich mal einlesen, was das für eine Sinn hat.
Aber du meinst, es wäre wichtig, beim Zugriff auf die "pulses"-Variable die Interrupts zu disablen, damit ich nicht zufällig beim Schreiben der long-Variable einen Interrupt bekomme und dann die Variable "verbogen" ist?

 
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Germany
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3030
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Aber du meinst, es wäre wichtig, beim Zugriff auf die "pulses"-Variable die Interrupts zu disablen, damit ich nicht zufällig beim Schreiben der long-Variable einen Interrupt bekomme und dann die Variable "verbogen" ist?
Was ist schon wichtig? Wenn du es nicht machst, wird nur sehr, sehr selten ein Fehler auftreten. Und wenn du das Ergebnis nur irgendwo anzeigst, wird das "nie" jemand merken.
In der Automatisierungstechnik sind allerdings Fehler, die ganz sporadisch auftreten und nicht reproduziert werden können, sehr unangenehm.
Das ist die 2 Machinenbefehle sei und cli , die zusätzlich erzeugt werden, immer wert.

"volatile" ist ein anderer Fall: das sagt dem Compiler nur, dass die Variable sich irgendwie ändern kann, obwohl der Compiler nichts davon weiss.
Nimm an, dein Interrupt-Handler ist in einer anderen Datei, die separat übersetzt wird:
pulses++;  // könnte einfach weggelassen werden, weil es nie gelesen wird smiley-wink
oder der Compiler meint, die Variable braucht er nicht aus dem RAM zu laden, weil er sie noch in einem Register hat ...

Nachdem du die 8 Buchstaben einmal eingetippt hast, ist alles klar: kein zusätzlicher Code, der eigentlich nicht gebraucht wird, aber auch keine falsche Optimierung.

Quote
Evtl. noch untersetzen, falls es zu wenig Impulse sind.
Ja. Hängt alles auch davon ab, was ein Puls bedeutet, ab wann du 0 anzeigen willst, und wie du möglichst ohne float Division auskommst.
Logged

Pages: [1]   Go Up
Jump to: