1 | /*********************************************************************
|
2 |
|
3 | Frequenzzähler (Berich: 1Hz bis etwa theor. 8MHz). Mit Vorteiler
|
4 | einfach erweiterbar für höhere Messfrequenzen
|
5 |
|
6 | Dieses Programm stellt die am T0 Eingang (PD4) eines Atmega8 (16Mhz)
|
7 | anliegende Frequenz (TTL Pegel Rechteck) auf einem LCD Hz-genau dar.
|
8 | Weiterhin gibt es die Möglichkeit eines Abgleiches der Frequenz
|
9 | mittels Korrekturfaktor bei Bedarf wegen der unvermeidlichen
|
10 | "Quarz-Schwingfrequenzabweichung"). Die Abweichungen sind
|
11 | ohne Abgleich innerhalb 0,03% Bereich (linear) bei annähernd konstanter
|
12 | Raumtemperatur. Für normale Zwecke völlig ausreichend.
|
13 |
|
14 | Zum Abgleich wird die Variable "korrekturfaktor" anpasst. d.h. es wird
|
15 | eine bekannte, stabile Frequenz (Rechteck, TTL - sollte mindestens
|
16 | 10Khz, besser 1Mhz sein) angelegt und der angezeite Wert ermittelt.
|
17 | Anschließend wird der wahre Wert durch den angezeigten Wert geteilt
|
18 | und sinnvoll auf 5 oder 6 Stellen nach dem Komma gerundent. z.b.
|
19 |
|
20 | 100000Hz/100026Hz=0.99974
|
21 |
|
22 | Dieser Wert wird dann der Variable "korrekturfaktor" zugeteilt.
|
23 | Genauigkeit nach Abgleich 1Hz genau. Zumindestens bei meinen
|
24 | Referenzmessungen. Viel Spass damit!
|
25 |
|
26 | Swen
|
27 |
|
28 | *********************************************************************/
|
29 |
|
30 | #include <avr/io.h>
|
31 | #include "lcd-routines.h"
|
32 | #include "avr/interrupt.h"
|
33 |
|
34 | int count = 0, a = 0;
|
35 | float korrekturfaktor = 1; //hier anpassen für Abgleich (z.b 0.99974)
|
36 | int ztmp = 0;
|
37 | unsigned long freq = 0;
|
38 | char anz[20];
|
39 | volatile int s=0;
|
40 | volatile unsigned short z=0;
|
41 |
|
42 | /*****************************************************************
|
43 | Funktion für Unwandlung Unsigned Long to Char (Für LCD Ausgabe)
|
44 | ******************************************************************/
|
45 |
|
46 | void uLongtoChar(unsigned long u,char* Buffer)
|
47 | {
|
48 | int i = 0;
|
49 | int j;
|
50 | char tmp;
|
51 | // die einzelnen Stellen der Zahl berechnen
|
52 | do {
|
53 | Buffer[i++] = '0' + u % 10; // = String "0" (=48) + Rest von u/10
|
54 | u = u/10;
|
55 | } while( u > 0 );
|
56 | // den String in sich spiegeln (d.h. Reihenfolge umkehren)
|
57 | for( j = 0; j < i / 2; ++j ) {
|
58 | tmp = Buffer[j];
|
59 | Buffer[j] = Buffer[i-j-1];
|
60 | Buffer[i-j-1] = tmp;
|
61 | }
|
62 | Buffer[i] = '\0';
|
63 | }
|
64 |
|
65 | /*********************************
|
66 | Timer 0 und 2 Interruptroutinen
|
67 | **********************************/
|
68 |
|
69 | ISR(TIMER2_COMP_vect) // Löst aus alle (16Mhz/1024/125) 8ms
|
70 | {
|
71 | s++;
|
72 | }
|
73 |
|
74 | ISR(TIMER0_OVF_vect) // Eingangsignal Overflow Zähler Timer 0
|
75 | {
|
76 | z++;
|
77 | TIFR = (1<<TOV0); //ov flag timer 0 zurücksetzen
|
78 | }
|
79 |
|
80 | /*************************
|
81 | Hauptfunktion
|
82 | **************************/
|
83 |
|
84 | int main(){
|
85 | lcd_init(); // LCD init
|
86 | TCCR2 |= (1<<WGM21); // CTC Mode Aktivierung Timer2
|
87 | TCCR2 |= (1<<COM20) | (1<<COM21); // set OCR Flag bei "Compare Match"
|
88 | TCCR0 |= (1<<CS02) | (1<<CS01) | (1<<CS00); // Ext Flanke Interrupt (T0)
|
89 | TCCR2 |= (1<<CS22) | (1<<CS21) | (1<<CS20); // Prescaler Timer2 auf 1024 setzen
|
90 | OCR2 |= 124; // Output Compare register Timer2 auf 124 (für Loop 0-124 => 125)
|
91 | TIMSK |= (1<<OCIE2); // Enable comp match flag interrupt Timer 2
|
92 | TIMSK |= (1<<TOIE0); // Enable overflow flag interrupt Timer 0
|
93 |
|
94 | sei();
|
95 |
|
96 | while(1)
|
97 | {
|
98 | if (s==125){ // "Zähltor": Abarbeitung jede Sekunde (16MHz/1024/125/125)
|
99 | count = TCNT0;
|
100 | s=0;
|
101 | ztmp = z;
|
102 | z= 0;
|
103 | TCNT0 = 0;
|
104 | lcd_clear();
|
105 | freq = 0.5+((256UL*ztmp + count)*korrekturfaktor); //siehe Bemerkung unten
|
106 | /*********************************************************************************
|
107 | - freq: Ermittlung der Frequenz: Anzahl Timer 0 Overflows + aktuellen Timer 0 Count
|
108 | - die + 0,5 sind zum korrektem "Runden" ->Fließkommazahl zu Ganzzahl
|
109 | - "korrekturfaktor" ist die SW-Korrektur zur Kompensation der lin.Quarzungenauigkeit
|
110 | **********************************************************************************/
|
111 |
|
112 | uLongtoChar(freq,anz); // Unwandlung Long zu String für Displayausgabe
|
113 | set_cursor (0,1); // Cursor Pos setzen
|
114 | lcd_string( anz ); // Anzeige der ermittelten Frequenz
|
115 | set_cursor (8,1); // Cursor Pos setzen
|
116 | lcd_string( "Hz" ); // Anzeige Hz
|
117 | }
|
118 | }
|
119 | return 0;
|
120 | }
|