Forum: Mikrocontroller und Digitale Elektronik Mit AVR hyd. Messturbine auslesen


von M. W. (mw73)


Angehängte Dateien:

Lesenswert?

Guten Abend,

wie bereits in der Überschrift erwähnt, möchte ich mit einem AVR, genau 
genommen Mega8 eine hydraulische Messturbine auswerten. Die Turbine 
stammt aus einem alten Übungsstand mit eigenem Messsystem (Uralt mit 
7-Segment Anzeige). Da es hierzu kein Datenblatt gibt, habe ich anhnand 
des bestehenden Messsystems eine Kennlinie erstellt. Der Sensor gibt 
rechtecktförmige High-Pegel aus und zwar für einen Liter 16,66 Impulse.

Ich hab mir die Messung so vorgestellt, dass ich per externem Interrupt 
die Impulse zähle (steigende Flanke) und per Timer overflow auswerte ( 
~1000 ms). Der Mega8 läuft einstweilen mit internem Oszillator 8MHz. 
Später, wenn das läuft, soll es in einen Mega2560 migriert werden.

So sieht es z.zt. aus:
Wie beschrieben, Mega8 mit 8MHz getaktet, Signal wird an INT0 eingelesen 
und per Interrupt (rising edge) gezählt.

Zum Zählen der Impulse pro Zeiteinheit, verwende ich Timer1 mit einem 
Vorteiler von 1024 und einem Vorladewert von 57723 um ein Zeitfenster 
von 1000,064 ms zu generieren.

Da mir die Anlage nur sehr selten zur Verfügung steht, erstelle ich mir 
das Signal mittels Funktionsgenerator.

zum Problem:
Soweit funktioniert ja das Auslesen nur mit der Darstellung gibt es 
Probleme. Da ich auf float verzichten möchte, hab ich mir folgende 
Kalkulation überlegt:

Wenn in der Anlage zb. 6l Hydrauliköl fliessen, ergibt das eine Frequenz
von 100Hz. Die Zählervariable wird nach einer Sekunde ausgelesen und der 
Wert mit 10 multipliziert, damit ich durch 166 teilen kann, was dann den 
Wert vor der Kommastelle darstellen soll. Danach dividiere ich den Wert 
der Zählervariable durch 16 und mache über modulo 10 die 
Restwertbestimmung, um auch einen Nachkommanteil zu erhalten. Anbei kurz 
die beschriebene Codestelle (Ich hab auch die ganze main angehängt).
1
b_flow_count = einer/166; // Berechnung des Wertes vor der Kommastelle
2
s_flow_count = einer/16 % 10; // Berechnung des Wertes nach der Kommastelle

Das funktioniert auch größtenteils bis auf folgendes Szenario.
Wenn ich die Frequenz des Funktionsgenerators erhöhe, erhöht sich zu 
beginn wie gewünscht auch der Nachkommaanteil zb. 0,7l, 0,8l, 0,9l
An dieser Stelle würde ich 1,0l erwarten, erhalte aber 0,0, bei weiterem 
Erhöhen 0,1, und dann auf einmal bei weiterem Erhöhen 1,2 und dann geht 
es wieder normal weiter bis 1,9l.

Vielleicht könnte sich jemand den Code kurz ansehen und mir etwas auf 
die Sprünge helfen.

Danke erstmal und ich freue mich auf Rückmeldung!
mw73

von void (Gast)


Lesenswert?

Markus W. schrieb:
> Vielleicht könnte sich jemand den Code kurz ansehen und mir etwas auf
> die Sprünge helfen.

Das von dir beschriebene Problem sehe ich leider nicht.
Für die Nachkommastelle hast du aber einen leichten Rundungsfehler
> s_flow_count = einer/16 % 10; // Berechnung des Wertes nach der Kommastelle

Beispiel:
21 Hz => entspricht 1.26 Liter

einer = 21 Hz * 10 = 210
einer = 210 / 16 = 13
einer = 13 % 10 = 3
=> Angezeigter Wert "1.3 Liter"

Wenn du folgendes Rechnest wird es besser.
s_flow_count = (einer * 10/166) % 10;

Aber Achtung uint16 läuft dann auch eher über.

Beitrag #5896879 wurde vom Autor gelöscht.
von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Markus W. schrieb:

> des bestehenden Messsystems eine Kennlinie erstellt. Der Sensor gibt
> rechtecktförmige High-Pegel aus und zwar für einen Liter 16,66 Impulse.

Also ein Frequenz bzw. Periodendauerzähler.

> Ich hab mir die Messung so vorgestellt, dass ich per externem Interrupt
> die Impulse zähle (steigende Flanke) und per Timer overflow auswerte (
> ~1000 ms). Der Mega8 läuft einstweilen mit internem Oszillator 8MHz.
> Später, wenn das läuft, soll es in einen Mega2560 migriert werden.

Kann man machen. Man kann aber auch die Periodendauer messen, das geht 
schneller, vor allem bei  sehr niedrigen Frequenzen wie hier.

> Zum Zählen der Impulse pro Zeiteinheit, verwende ich Timer1 mit einem
> Vorteiler von 1024 und einem Vorladewert von 57723 um ein Zeitfenster
> von 1000,064 ms zu generieren.

Beim AVR nimmt man keinen Vorladewert sondern den CTC-Modus! Siehe 
Datenblatt.

> Soweit funktioniert ja das Auslesen nur mit der Darstellung gibt es
> Probleme. Da ich auf float verzichten möchte, hab ich mir folgende
> Kalkulation überlegt:

Siehe Festkommaarithmetik.

> Wenn in der Anlage zb. 6l Hydrauliköl fliessen, ergibt das eine Frequenz
> von 100Hz.

Nö, da fehlt die Zeit. Bitte mal nicht Durchflußmenge mit 
Durchflußgeschwindigkeit vermischen.

> Die Zählervariable wird nach einer Sekunde ausgelesen und der
> Wert mit 10 multipliziert, damit ich durch 166 teilen kann, was dann den
> Wert vor der Kommastelle darstellen soll. Danach dividiere ich den Wert
> der Zählervariable durch 16 und mache über modulo 10 die
> Restwertbestimmung, um auch einen Nachkommanteil zu erhalten.

Da muss man gar nichts /16 teilen, nur durch 10!

> Vielleicht könnte sich jemand den Code kurz ansehen und mir etwas auf
> die Sprünge helfen.

Das hier ist Unsinn

ISR (TIMER1_OVF_vect){

  //t_oilflow = oilflow;
  //oilflow = 0.0;

  // preload value
  TCNT1 = 57723;  // timer vorladen
  cli();
  zehntel *= 10; // um für die Berechnung nachher ganzzahlig durch 166 
dividieren zu können
  einer = zehntel; // sofortige Übergabe des Wertes
  zehntel = 0;  // und zurücksetzen
  sei();
}

1. nimmt man den CTC-Modus und 2. macht man kein cli() / sei() in einer 
ISR. Denn 1. sind die Interrupts beim Eintritt schon gesperrt und 2. 
werden sie am Ende der ISR automatisch wieder freigegeben. Und 3. macht 
man keine unnötigen Rechnungen in der ISR. Das einzige was dort 
passieren muss, ist die Übergabe des Meßergebnisses. Die Umrechnung 
macht dann die Anzeige im Hauptprogramm, siehe Interrupt.

Du braucht den Faktor 100 da drin! Denn du willst ja am Ende 1/10 Liter 
berechnen, nicht nur 1/10 Hz!

Dann kann man nämlich die Vor- und Nachkommastellen einfach ausrechnen, 
ohne sich zu verhaspeln. Siehe Anhang.

Übrigend, globale Variablen muss man nicht mit 0 initialisieren, das 
passiert garantiert automatisch.

Wobei man hier auch problemlos Fließkommazahlen nehmen kann, denn die 
Berechnung und Anzeige erfolgt sehr langsam, das rechnet der AVR 1000 
mal  durch und langweilt sich immer noch.

von void (Gast)


Lesenswert?

Falk B. schrieb:
> Dann kann man nämlich die Vor- und Nachkommastellen einfach ausrechnen,
> ohne sich zu verhaspeln. Siehe Anhang.
1
      zlps = (uint32_t)pps_main*100 / 166;
2
3
      b_flow_count = zlps / 10;  // Vorkommastelle
4
      s_flow_count = zlps % 10;   // Nachkommastelle

Kann ich Falk nur zustimmen. So ist eleganter und vermeidet sicher 
unterschiedlich genau gerundete Vor- und Nachkommastellen.

von mw73 (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

Wow, vielen Dank für eure Hilfe! Ich werde das nachher gleich testen.

@Falk
in einer Sache habe ich mich wohl falsch ausgedrückt. Ich habe ja eine 
Kennlinie mit dem bestehenden Messsystem erstellt. Durch schrittweises 
erhöhen der Ölmenge hab ich mittels Oszi die Pulse gemessen. Bei 6l/min 
waren das 100Hz. Ich hänge hierzu noch ein Bild an.

Ich melde mich heute noch zurück

von mw73 (Gast)


Lesenswert?

so da bin ich wieder.

Test soweit abgeschlossen und ich bin voll begeistert. Danke Falk noch 
mal für Deine kompetente und umfangreiche Hilfe!!!!

Ich hab mir auch Deinen Link "Festkommaarithmetik" angesehen und hätte 
da eine Frage dazu. Im Link steht ja, dass ich float mit sprintf 
verwenden kann. Bei mir hat das aber nur unter dtostrf funktioniert. 
Ansonsten gab es ein Fragezeichen bei der Ausgabe. ist aber nicht so 
schlimm, da ich float ohnehin nict verwenden wollte.

andere Frage:
eine Entprellung werde ich wahrscheinlich nicht benötigen, oder?

und kann ich zum Pulse zählen auch den Pin-Change interrupt verwenden, 
da ich am Mega2560 nur noch einen weiteren ExtInt frei habe. Ich würde 
ingesamt bis zu fünf Messturbinen gleichzeitig einlesen.

und noch eine Frage zur Eingangsbeschaltung. Da die Turbine mit 24 Volt 
gespeist wird, wäre da ein Spannungsteiler mit Eingangsschutzbeschaltung 
ok?

Grüße Markus

von Gerhard O. (gerhard_)


Lesenswert?

mw73 schrieb:
> so da bin ich wieder.
>
> Test soweit abgeschlossen und ich bin voll begeistert. Danke Falk noch
> mal für Deine kompetente und umfangreiche Hilfe!!!!
>
> Ich hab mir auch Deinen Link "Festkommaarithmetik" angesehen und hätte
> da eine Frage dazu. Im Link steht ja, dass ich float mit sprintf
> verwenden kann. Bei mir hat das aber nur unter dtostrf funktioniert.
> Ansonsten gab es ein Fragezeichen bei der Ausgabe. ist aber nicht so
> schlimm, da ich float ohnehin nict verwenden wollte.
>
> andere Frage:
> eine Entprellung werde ich wahrscheinlich nicht benötigen, oder?
>
> und kann ich zum Pulse zählen auch den Pin-Change interrupt verwenden,
> da ich am Mega2560 nur noch einen weiteren ExtInt frei habe. Ich würde
> ingesamt bis zu fünf Messturbinen gleichzeitig einlesen.
>
> und noch eine Frage zur Eingangsbeschaltung. Da die Turbine mit 24 Volt
> gespeist wird, wäre da ein Spannungsteiler mit Eingangsschutzbeschaltung
> ok?
>
> Grüße Markus

Sieh mal in den Einstellungen Deines Entwicklungssystem nach. Manchmal 
ist der Funktionsumfang von sprintf() und printf() konfigurierbar um die 
eingebunden Bibliotheken je nach Bedarf kleinhalten zu können.

...

von Falk B. (falk)


Lesenswert?

mw73 schrieb:
> da eine Frage dazu. Im Link steht ja, dass ich float mit sprintf
> verwenden kann. Bei mir hat das aber nur unter dtostrf funktioniert.
> Ansonsten gab es ein Fragezeichen bei der Ausgabe.

Man muss für die Verwendung von float in sprintf & Co die passende 
Bibliothek zum Linken verwenden. Das muss man irgendwo in den 
Linkeroptionen einstellen. Dann werden aber auch die Funktionen von 
sprintf() etwas größer.

> eine Entprellung werde ich wahrscheinlich nicht benötigen, oder?

Wenn dein Sensor saubere Signale liefert, dann nein. Aber da du eher 
niedrige Frequenzen von max. 1kHz mißt, würde ich schon einen kleinen 
RC-Tiefpass mit vielleicht 1k + 10nF (~15 kHz Bandbreite) verwenden. 
Denn dein externer Interrupt reagier auf SEHR kleine Pulse, die nur 1-2 
CPU-Takte lang sein müssen, um erkannt zu werden.

> und kann ich zum Pulse zählen auch den Pin-Change interrupt verwenden,

Sicher. Mußt dann halt den Zählwert halbieren, denn der zählt steigende 
und fallende Flanken.

> und noch eine Frage zur Eingangsbeschaltung. Da die Turbine mit 24 Volt
> gespeist wird, wäre da ein Spannungsteiler mit Eingangsschutzbeschaltung
> ok?

Kommt drauf an. Wie sieht der Ausgang des Sensor denn elektrisch aus? 
Ist das ein Open Kollektor? Dann braucht man einen Pull-Up nach 5V aber 
keine Schutzschaltung. Wenn der aber aktiv 24V ausgibt, braucht man 
mindestens einen Spannungsteiler.

von mw73 (Gast)


Lesenswert?

Alles klar,

Noch einmal recht herzlichen Dank!!
Hab da auch wieder viel dazu gelernt.

Danke und LG
Markus

von Minimalist (Gast)


Lesenswert?

Falk B. schrieb:
> 1. nimmt man den CTC-Modus

Hmm, ich würde das mit dem Input Capture machen. Da brauch ich nix 
vorladen, nix zu zählen, sondern kam im IC Interrupt die Periodendauer 
bequem aus den IC buffer Registern lesen. Aus der Periodendauer würde 
ich dann direkt den Durchfluss berechnen. Ggf noch vorher schnell per 
gleitendem/exponentiellen Mittelwert glätten.

von Wolfgang (Gast)


Lesenswert?

Falk B. schrieb:
> Wobei man hier auch problemlos Fließkommazahlen nehmen kann, denn die
> Berechnung und Anzeige erfolgt sehr langsam, das rechnet der AVR 1000
> mal  durch und langweilt sich immer noch.

Genauso gut könnte man den AVR nebenher Primzahlen berechnen lassen, 
wenn es darum geht, ihn irgendwie zu beschäftigen.

Die Dynamik von float braucht man hier definitiv nicht.

von PittyJ (Gast)


Lesenswert?

Ich verstehe den Sinn den 'Float-Verzichts' nicht.
Auch die 8-Bitter sind für Float schnell genug. Wenn man eine Anzeige 
damit betreibt, und 2 mal die Sekunde das Ergebnis mit den Floats 
berechnet, dann ist das OK. Man sollte die Floats nur nicht in die 
Interrupts mit rein packen.
Entkoppeln von Anzeige un Steuerung, und gut ist es.

In den 80er wurden 100te Spiele in Basic auf dem C64 geschrieben. 
Oftmals mit Float-Berechnungen, weil das der Default war. Und die CPU 
war eine 8-Bitter mit 1MHz.

von Wolfgang (Gast)


Lesenswert?

PittyJ schrieb:
> Ich verstehe den Sinn den 'Float-Verzichts' nicht.

Ich verstehe nicht, was du an der Stelle unbedingt mit Float willst und 
was das für Vorteile bringen soll.
Von der Dynamik des Wertebereichs (1E-38 bis 3.4E+38) hast du hier 
überhaupt nichts, i.e. die 8 Bit des Exponenten beim Float gehen dir für 
größtenteils bei der Genauigkeit verloren ;-)

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.