' reziproke Frequenzmessung mit ATmega48/88 und BASCOM ' typische Daten: ' Eingangsfrequenz ca. 0,005 Hz - 100 kHz ohne Vorteiler, mit Vorteiler 74VHC4040 - 100 MHz ' mit 6-stelliger Ausgabe ' Messrate ca. 3 Messungen/s als Frequenz, Periode oder Drehzahl ' Die Beschreibung der Funktion und weitere Programme (allerdings in C) ' finden sich hier: http://www.mino-elektronik.de/fmeter/fm_software.htm ' und das Schaltbild dazu: http://www.mino-elektronik.de/download/AVR_FMETER.png ' 2015-03-05 ' Alle Angaben ohne Gewähr ' www.mino-elektronik.de ' für Bezeichner Frequenz/Periode Dim Dim_string(15) As String * 6 Dim I As Byte $crystal = 20000000 $baud = 19200 $swstack = 100 ' nicht zu knapp bemessen $hwstack = 100 ' dto. Const F_clock = 20000000 Const T1_ovfl_pro_sekunde = 305 ' Vorteiler 74HC393 %256 oder 74VHC4040 %1024 einstellen Const Vorteiler_faktor = 1024 ' stellen um 1 zu niedrig angeben Const Stellen = 6 Const Minimale_messzeit = 102 ' ca. 3 Messungen/s Const Maximale_messzeit = 30500 ' ca. 100 Sekunden Const Teiler_100ms = 30 ' alle 100 ms Const Messen = 0 Const Auslesen = 1 Const Auswerten = 2 ' Zur Anwahl der Ergebnisses Const Zeige_f = 0 Const Zeige_p = 1 Const Zeige_upm = 2 Dim Frequenz As Single ' float-Ergebnis Dim Ergebnis_str As String * 20 ' als String Dim Sync_flag As Byte , Temp As Byte , Vorteiler_aktiv As Byte , Teiler As Byte Dim Messwert_vorhanden As Byte , Mess_status As Byte , Led_cnt As Byte Dim Zeitpunkt As Dword , Messdauer As Word , Ueberlauf As Word ' Zeitmessung Dim Start_ereignis As Dword , End_ereignis As Dword , Start_zeit As Dword Dim End_zeit As Dword , Mess_zeit As Dword , Mess_ereignisse As Dword Dim Eingangsimpulse As Dword ' Zaehler für die Eingangsimpulse ' zur Ausgabe eines fomatierten Meßwertes Declare Sub Frequenz_ausgeben(byval X As Single , Byval Ausgabe_wert As Byte) ' Hier beginnt das Hauptprogramm mit der Initialisierung von Daten und Timer-Interrupts ' init der Dim_Strings, liegen ganz am Ende Restore Dta ' auf ersten Wert zurücksetzen For I = 0 To 14 Read Dim_string(i) ' und dann Wert für Wert einlesen Next ' Timer1 aktivieren Config Timer1 = Counter , Capture_edge = Falling , Prescale = 1 ' freilaufend mit fallender Flanke an ICP1 Enable Timer1 On Timer1 Timer1_int ' für Timer1 Überläufe Enable Icp1 On Icp1 Timer1_capt_int ' Zählung der Eingangsimpulse und Zeitmessung ' abschließend Interrupts freigeben Enable Interrupts Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portc.1 , Rs = Portc.0 Config Lcd = 16 * 2 'configure lcd screen Cursor Off Cls Ddrd.5 = 1 Acsr.2 = 1 ' analog Komparator verwenden Tccr0b = 7 ' T0 zaehlt Impulse des Vorteilers Vorteiler_aktiv = 0 Messwert_vorhanden = 0 ' erstes Ergebnis verwerfen Locate 1 , 1 Lcd "F:" Locate 2 , 1 Lcd "P:" ' Hauptprogramm zum messen der Frequenz ' Auswertung erfolgt, wenn minimale_messzeit erreicht ist Do If Sync_flag = 1 Then ' alle 0,1sek. Frequenz an T0 bewerten Sync_flag = 0 ' wieder loeschen Temp = Tcnt0 ' T0 lesen If Tifr0.0 = 1 Then ' bei Ueberlauf Tifr0.0 = 1 ' flag loeschen Temp = 255 ' und max. Wert nehmen End If Tcnt0 = 0 ' Messung am Vorteiler neu starten If Vorteiler_aktiv = 1 Then ' If Temp < 3 Then ' Vorteiler wieder abschalten Acsr.2 = 1 ' analog Komparator verwenden Mess_status = Auslesen ' aktuelle Ergebnisse lesen Messwert_vorhanden = 0 ' aber nicht anzeigen Vorteiler_aktiv = 0 ' wieder auf ANA-COMP umschalten ' Cursor Off End If Elseif Temp > 5 Then ' Vorteiler zuschalten Vorteiler_aktiv = 1 ' Cursor On Acsr.2 = 0 ' ICP aktivieren Mess_status = Auslesen ' Aktuelle Ergebnisse Lesen Messwert_vorhanden = 0 ' aber nicht anzeigen End If End If Timsk1.0 = 0 ' t1-overflow interrupt sperren If Mess_status = Messen And Messdauer >= Minimale_messzeit Then Mess_status = Auslesen ' Auswertung starten Messdauer = 0 ' wieder Messzeit abwarten End If If Messdauer > Maximale_messzeit Then ' timeout Mess_status = Auslesen ' aktuelle Messung abschließen Messwert_vorhanden = 0 ' aber nicht auswerten End If Timsk1.0 = 1 ' t1-overflow interrupt freigeben If Mess_status = Auswerten Then ' minimale Meßzeit abgelaufen, dann auswerten End_zeit = Zeitpunkt Mess_zeit = End_zeit - Start_zeit ' Zeit-Differenz bilden Start_zeit = End_zeit ' neue startzeit merken Mess_ereignisse = End_ereignis - Start_ereignis ' Impuls-Differenz Start_ereignis = End_ereignis ' fuers naechste Intervall Mess_status = Messen ' wieder warten If Messwert_vorhanden = 1 Then ' gueltige Messung Led_cnt = 31 ' ca. 0,1 s Frequenz = Mess_ereignisse Frequenz = Frequenz / Mess_zeit ' Frequenz Berechnen Frequenz = Frequenz * F_clock If Vorteiler_aktiv = 1 Then Frequenz = Frequenz * Vorteiler_faktor End If Call Frequenz_ausgeben(frequenz , Zeige_f) ' Frequenz wandeln Locate 1 , 5 Lcd Ergebnis_str Print Ergebnis_str ' Beispiel: Ausgabe per ser. Schnittstelle Call Frequenz_ausgeben(frequenz , Zeige_p) ' Periode wandeln ' Call Frequenz_ausgeben(frequenz , Zeige_upm) ' Drehzahl wandeln Locate 2 , 5 ' und anzeigen Lcd Ergebnis_str Else Messwert_vorhanden = 1 ' falls gesperrt wieder aufheben End If End If Loop ' endlosschleife ' der übergebene Frequenzwert "x" wird in eine Zeichenkette mit Dez.-Punkt und Dimension gewandelt ' mit "ausgabe_wert" wird zuvor der Kehrwert gebildet und die Periodendauer ermittelt ' Das Ergebnis findet sich in "Ergebnis_str" und kann beliebig ausgegeben werden Sub Frequenz_ausgeben(byval X As Single , Byval Ausgabe_wert As Byte) 'Wandlung von Frequenz oder Periode Local I As Byte , J As Byte , Dez_punkt As Byte , Dimension As Byte Dez_punkt = 1 ' Vorgabe für "1.xxxxx" Dimension = 3 ' vorgabe für "Hz" If X < 0.01 Then ' 10 mHz Ist Untergrenze X = 0.0 ' falls zu tiefe Frequenz "0.0 Hz" ausgeben Else If Ausgabe_wert = Zeige_p Then ' falls Periode gewandelt werden soll X = 1 / X ' Kehrwert Bilden Dimension = 5 ' und in Sekunden als Dimension Elseif Ausgabe_wert = Zeige_upm Then X = X * 60 Dimension = 13 End If While X < 1.0 X = X * 1000.0 Incr Dimension ' in den Hz-Bereich bringen Wend While X >= 1000.0 X = X * 0.001 Decr Dimension Wend While X >= 10.0 X = X * 0.1 Incr Dez_punkt Wend X = X + 5e-6 ' runden If X >= 10.0 Then ' Ueberlauf bei Rundung X = X * 0.1 Incr Dez_punkt If Dez_punkt > 3 Then ' Ueberlauf der Dimension Decr Dimension Dez_punkt = 1 End If End If End If Ergebnis_str = "" For I = 1 To Stellen ' ab hier Datenausgabe J = X ' nur eine Dezimalstelle Ergebnis_str = Ergebnis_str + Str(j) ' ans Ergebnis anhängen If I = Dez_punkt Then Ergebnis_str = Ergebnis_str + "." ' Dez-Punkt einfügen End If X = X - J X = X * 10 Next Ergebnis_str = Ergebnis_str + Dim_string(dimension) ' und Dimension dazu End Sub ' bei jedem Timer1 Überlauf die Überläufe zählen und die grobe Messdauer erhöhen Timer1_int: ' bei jedem Überlauf von Timer1 Incr Ueberlauf Enable Interrupts Incr Messdauer If Led_cnt > 0 Then Portd.5 = 1 ' Messung fertig: LED für 100 ms blinken lassen Decr Led_cnt Else Portd.5 = 0 End If Incr Teiler ' sync-flag alle 100 ms setzen If Teiler > Teiler_100ms Then Teiler = 0 Sync_flag = 1 End If Return ' Hier werden die Eingangsimpulse und ihr genauer Zeitpunkt erfasst Timer1_capt_int: Incr Eingangsimpulse If Mess_status = Auslesen Then ' Ergebnisse synchron zum Eingangsimpuls auslesen+ablegen Zeitpunkt = Ueberlauf * &H10000 ' ueberlauf in die oberen 16bit schreiben Zeitpunkt = Zeitpunkt + Capture1 ' und Capture-Wert dazu If Tifr1.0 = 1 And Capture1 < 32768 Then ' evtl. Ueberlauf T1 noch offen? Zeitpunkt = Zeitpunkt + 65536 ' nur, wenn capture-int + overflow-int gleichzeitig ! End If End_ereignis = Eingangsimpulse ' Anzahl der Impulse lesen Mess_status = Auswerten ' Daten fertig fuer Auswertung End If If Tifr1.5 = 1 Then ' weiteren Eingangsimpuls gleich hier verwerten Incr Eingangsimpulse Tifr1.5 = 1 ' und Flag loeschen End If Return End Dta: Data " GHz" , " MHz" , " kHz" , " Hz " , " mHz" , " sek" , " ms " , " us " , " ns " , " ps " , " Grpm" , " Mrpm" , " krpm" , " rpm" , " mrpm"