Forum: Mikrocontroller und Digitale Elektronik Frequenzzähler 8Mhz ohne Vorteiler - Atmega8


von Swen S. (swen1)


Lesenswert?

Hallo,

auch wenn ich denke das schon viele Counter Codes hier so rumgekommen 
sind, will ich euch meinen nicht vorenthalten, da ich den einen oder 
anderen Tip von hier erhalten habe. Er ist nach einem Softwareabgleich 
der Schwingungsfrequenz des Quarzes sehr genau, so genau wie das 
Quarztempverhalten hergibt. Vielleicht kann der eine oder andere damit 
was anfangen.

mfg

Swen
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
}

von Swen S. (swen1)


Angehängte Dateien:

Lesenswert?

der Code als Datei

von Swen S. (swen1)


Angehängte Dateien:

Lesenswert?

foto :) eh ich wieder alles einstampfe

von Matze (Gast)


Lesenswert?

guten morgen swen,

möchte gerne deinen frequenzzähler nachbauen, leider bin ich totaler 
Laie   so das ich fragen wollte ob ich einen schaltplan für die LED - 
Variante und das hex-file bekommen könnte.

Vielen Dank!
Matze

von Wolfgang (Gast)


Lesenswert?

Matze schrieb:
> einen schaltplan für die LED-Variante ...

Die LED-Variante auf dem Photo ist die Referenz und hat nichts mit dem 
vorgestellten Projekt zu tun ;-)

von m.n. (Gast)


Lesenswert?

Matze schrieb:
> möchte gerne deinen frequenzzähler nachbauen,

Vielleicht ließt Du hier weiter und stellst fest, dass ein Vorteiler 
nicht Böses ist. Beitrag "Vorteiler Frequenzzähler"

von W.S. (Gast)


Lesenswert?

Swen S. schrieb:
> Vielleicht kann der eine oder andere damit
> was anfangen.

Und wie reagiert er auf asymmetrisches Tastverhältnis?
Wie reagiert er bei Input-Frequenzen über 8 MHz?
Wie hast du das Eingangsteil gestaltet? Oder ist sowas außerhalb deines 
Interessenbereiches?

W.S.

von Kilo (Gast)


Lesenswert?

Versuche seit Stunden das auf einen Atmega644 zu portieren aber ich 
bekomme das mit den Timern einfach nicht hin :((((((((
Hiiiilfe

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Kilo schrieb:
> Versuche seit Stunden das auf einen Atmega644 zu portieren aber ich
> bekomme das mit den Timern einfach nicht hin :((((((((
> Hiiiilfe

Hallo! Ok, vielleicht ist meine Frage doof, aber warum nimmst du nicht 
einfach einen ATmega8?

Falls es wirklich so ein Brummer wie der 644 sein muss, hast du die 
verwendeten Timer-Register per Datenblatt miteinander verglichen? Was 
genau "geht nicht"? Vielleicht ist der Fehler in Zeile 42? ;-)

von Peter R. (pnu)


Lesenswert?

Skeptische Frage:

Die Eingänge des atmega8 werden ja vom Kontroller im sampling-Verfahren 
eingelesen.

Sample-Takt ist dabei die Frequenz des Taktquarzes.(16MHz)

Gibt es da nicht um die 8 MHz herum nicht üble Fehlanzeigen, bedingt 
durch Abtastfehler, so nahe an der Nyquist-Grenze? Wird also z.B. eine 
Frequenz von 8,2000000 MHz nicht krottenfalsch angezeigt?

von Kilo (Gast)


Lesenswert?

@Markus

Puh, gut das jemand schreibt, ich dachte schon der Thread ist zu alt :))

Aaaalso: Ich bastel gerade an einem Tricorder. Siehe:
Atmega Tricorder Projekt Star Trek

Deshalb habe ich schon einen Atmega644 verbaut und kann nicht mehr 
wechseln.
Ich bin ein totaler Laie was Timer betrifft. Bzw. kapiere ich einfach 
die Register nicht. Warum gibt es beim Atmega644 zum Beispiel TCCR0A und 
TCCR0B und beim Atmega 8 NUR TCCR0 ???
Von daher ist es für mich schwierig das umzuschreiben und zu vergleichen 
laut Datenblätter...

Als Test habe ich mir die Variable 's', welche im Interrupt hochgezählt 
wird im LCD anzeigen lassen. s wird zwar hochgezählt aber im 
Sekundentakt und nicht in 8ms. Lasse ich die Variable 'freq' anzeigen, 
so passiert gar nichts. Nichts wird angezeigt. Als ob die Variable s die 
125 gar nicht erreicht. Ganz komisch.
An T0 also PinB0 liegt eine Frequenz an. Takt des µC ist 16MHz. Ich 
denke mal das ich die Timer falsch initalisiert habe. Deswegen: 
HIIIIILFE :)

von Kilo (Gast)


Lesenswert?

PS: wenn ich alle Register mit 42 fülle, müsste es doch klappen oder? 
lach

von Karl H. (kbuchegg)


Lesenswert?

Kilo schrieb:

> Ich bin ein totaler Laie was Timer betrifft. Bzw. kapiere ich einfach
> die Register nicht. Warum gibt es beim Atmega644 zum Beispiel TCCR0A und
> TCCR0B und beim Atmega 8 NUR TCCR0 ???

Weil der Timer 0 des M644 nun mal eine ganze Dinge mehr kann als der 
Timer 0 des M8.

> Von daher ist es für mich schwierig das umzuschreiben und zu vergleichen
> laut Datenblätter...

Wo liegt das Problem?
Du hast Code für einen M8. Aus dem suchst du dir raus, welche Bits im 
Konfigurationsregister gesetzt werden.
Dann gehst du ins Datenblatt des M8 und siehst dir dort in der Register 
Summary beim Timer 0 an, was diese Bits bedeuten.
Nachdem du dann weißt, was da eingestellt wird, gehts du ins Datenblatt 
des M644, wieder in die Register Summary beim Timer 0 und siehst in den 
dort vorhandenen Beschreibungen erst mal nach, wo du die gleiche 
FUnktionalität wieder findest. Aus dieser Beschreibung ergibt sich dann, 
wie die zu setzenden Bits beim M644 heissen und in welchem der beiden 
Konfigurationsregister das jeweilige Bit beheimatet ist.

Sehr wahrscheinlich werden die Bits beim M644 sogar gleich heissen, wie 
die beim M8. Aber verlassen würde ich mich nicht darauf. LIeber anhand 
der Funktionalität den Port vom M8 zum M644 machen.

Ist doch nicht weiter wild.

Und nein. Einen Kommentar im Programm würde ich bestenfalls als Hinweis 
nehmen und keinesfalls als bare Münze. Kommentare sind schon auch mal 
falsch. Im Zweifel gilt immer das Datenblatt.

> wird im LCD anzeigen lassen. s wird zwar hochgezählt aber im
> Sekundentakt und nicht in 8ms.

Da kann zb der Takt des Prozessors ein anderer sein, oder eben dieselben 
Vorteiler Bits stellen beim M8 einen anderen Vorteiler als beim M644 
ein.

> Takt des µC ist 16MHz.
Das haben schon viele gesagt. Hast du es kontrolliert?

: Bearbeitet durch User
von Kilo (Gast)


Lesenswert?

Hallo Karl Heinz,

ok, du hast Recht.. das sollte eigentlich einfach sein! Ich werde es 
versuchen!!
Aber versuch du mal einen journalistischen Text vom arabischen ins 
deutsche zu übersetzen mit nur einem Wörterbuch! So in etwa geht es mir 
dabei! :)

von Purzel H. (hacky)


Lesenswert?

Dann sollte man den Tricorder vielleicht auf eine Plasticbuechse mit ein 
paar LED reduzieren ...

:-) :-) :-)

: Bearbeitet durch User
von Kilo (Gast)


Lesenswert?

So, meiner Meinung nach habe ich alles so eingestellt wie es eigentlich 
sein sollte:
1
ISR(TIMER2_COMPA_vect) // Löst aus alle (16Mhz/1024/125) 8ms
2
{
3
s++;
4
}
5
6
ISR(TIMER0_OVF_vect) // Eingangsignal Overflow Zähler Timer 0
7
{
8
z++;
9
TIFR0 = (1<<TOV0); //ov flag timer 0 zurücksetzen
10
}
11
12
13
int main (void)
14
{
15
TCCR2B |= (1<<WGM21); // CTC Mode Aktivierung Timer2
16
TCCR2A |= (1<<COM2A0) | (1<<COM2A1); // set OCR Flag bei "Compare Match"
17
TCCR0B |= (1<<CS02) | (1<<CS01) | (1<<CS00); //  Ext Flanke Interrupt (T0)
18
TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20); //  Prescaler Timer2 auf 1024 setzen
19
20
OCR2A  |= 124; // Output Compare register Timer2 auf 124 (für Loop 0-124 => 125)
21
TIMSK2 |= (1<<OCIE2A); // Enable comp match flag interrupt Timer 2 
22
TIMSK0 |= (1<<TOIE2); // Enable overflow flag interrupt Timer 0
23
24
sei();
25
26
...

Aber es tut sich nix bei der Anzeige für Frequenz!

von Lutz (Gast)


Lesenswert?

Kilo schrieb:
> TIMSK0 |= (1<<TOIE2); // Enable overflow flag interrupt Timer 0

Zumindest zum Schluß hast du wohl beim Portieren mit der Konzentration 
nachgelassen.

von Lutz (Gast)


Lesenswert?

Kilo schrieb:
> TCCR2B |= (1<<WGM21); // CTC Mode Aktivierung Timer2

dito

von Sdjelano w GDR (Gast)


Lesenswert?

Hacky ätzte:
>Dann sollte man den Tricorder vielleicht auf eine Plasticbuechse mit ein
>paar LED reduzieren ...

>:-) :-) :-)

Du bist einer der größten Komiker, die ich hier erlebt habe.
:-( :-( :-(

von spess53 (Gast)


Lesenswert?

Hi

>> TIMSK0 |= (1<<TOIE2); // Enable overflow flag interrupt Timer 0

>Zumindest zum Schluß hast du wohl beim Portieren mit der Konzentration
>nachgelassen.

Da passiert nichts. TOIE2 ist genau wie TOIE0 Bit0.

MfG Spess

von Lutz (Gast)


Lesenswert?

Kann schon sein; ich klappere nun nicht jedes Register ab.
Und stimmen sollten die defines ja prinzipiell, sonst kann man ja 
einfach magische Zahlen reinkodieren ...

Viel wichtiger ist, daß er, wie von Karl Heinz beschrieben, die 
Register durchgeht und versteht. Das ist die erforderliche Investition 
in die Zukunft.

von Kilo (Gast)


Lesenswert?

Also ich hab jetzt nochmal ein paar Änderungen gemacht und versucht 
anzupassen.. mh..

Wenn ich mir die variable s anzeigen lasse dann zählt die irgendwo im 
Hunderterbereich hoch und hört gar nicht mehr auf.. also nix von 
0-125... ach keine ahnung.. ich blicks nicht :(

von spess53 (Gast)


Lesenswert?

Hi

>hört gar nicht mehr auf.. also nix von
>0-125... ach keine ahnung.. ich blicks nicht :(

Dann ersetze doch mal

if (s==125)

durch

if (s>=125)

MfG Spess

von Kilo (Gast)


Lesenswert?

Hatte ich auch schon mal versucht!

So, ich bekomme nun endlich eine Anzeige der Frequenz.. Juhu!!!
Jetzt muss ich erstmal checken ob der wert auch stimmt!

Danke erstmal an Euch!!!!

von Kilo (Gast)


Lesenswert?

Also es funktioniert jetzt! JUHU
Bekomme eine Frequenz angezeigt mit angeschlossenem 
Luftfeuchtigkeitssensor. Diese lag heute zwar bei ca. 107kHz was laut 
Referenz Wetterstation 49% Luftfeuchtigkeit bedeuten müsste.

Hab mir den Sensor aus einer Wetterstation ausgebaut. Keine 
Beschriftung, von daher keine Ahnung welche Marke... Muss ich also mal 
ein bißchen rumtüfteln an meiner Formel!

von Kilo (Gast)


Lesenswert?

also der wert stimmt nicht...
Der µC läuft mit 16MHz, nachgemessen und auch ausgegeben mit CKOUT.
Frequenzmesser zeigt mir ca. 80KHz an... der Atmega gibt aber nur ca. 
20KHz an...grummel...

von Ulrich (Gast)


Lesenswert?

Im Programm sind noch so einige Schwächen drin. Einmal bei der 
Festlegung der Torzeit, und dann noch einmal beim Auslesen der 
Zählerwerte. Mit etwas größeren Fehler (bis etwa 256 Hz + ca. 0.01%) ist 
dabei also zu rechnen. Wegen der Abtastung geht der Zähler auch nur 
gerade so bis zum halben µC Takt, realistischer wäre eher 1/4-1/3 des 
Taktes je nach Tastverhältnis.

Das Problem beim auslesen des Timers ist, da noch einen ggf. anstehenden 
Overflow Interrrupt abzufangen. Das geht besser indem man den Timer0 
kurz stopt, dann erst ausliest. Der Interrupt kommt dann schon wenn 
nötig.

Das mit der Torzeit ist etwas trickreicher. So geht es jedenfalls nur 
sehr schlecht, weil die Abfrage von s in einer Schleife unterschiedlich 
lange braucht - die Interrupts vom Timer 0 sorgen dann dafür das die 
genaue Zeit von der Frequenz abhängt. Besser wäre es die Abfrage auf das 
Ende der Torzeit schon im Interrupt zu machen, und da den Timer 0 
bereits zu stoppen.

Auch da hat man noch ein kleines Problem: durch einen Interrupt von 
Timer0 kann der Interrupt für das Ende der Torzeit noch etwas verzögert 
werden, wenn auch nicht lange. Eine Abhilfe hierfür ist nicht so einfach 
aber möglich:

Der Overflowinterrupt für timer0 wird kurz vor Ablauf der Torzeit 
abgeschaltet - man muss nur sicher gehen, das in der kurzen Zeit am Ende 
nur maximal 1 Overflow vorkommen kann - beim 8 bit timer0 hat man also 
512 Zyklen zeit am Ende. Sinnvollerweise läuft dafür der timer 1 nicht 
mehr mit so großem Vorteiler und dafür aber deutlich weiter als 125, 
sondern nur noch maximal 64, so dass man den Compare match Interrupt für 
die kurze Zeit von etwa 200 Zyklen nutzen kann. Die Tor-Zeit muss ggf. 
auch nicht genau eine Sekunde sein, wenn man den Abgleich über eine 
Multiplikation am Ende macht - besser wäre da sowieso eine 
Berücksichtigung des µC Taktes über den Zählerstand von Timer1 an Anfang 
der Messung - dann idealerweise ohne Vorteiler oder nur 8. So kann man 
dann auch Rundungsfehler vermeiden und man könnte wirklich die +-1 Hz 
Grenze eines klassischen Zählers erreichen.

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.