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
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.
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.
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
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
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.
...
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.
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.
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.
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.
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 ;-)