Guten Abend,
ich bastel gerade an nem Frequenzzähler (atmega 8mhz, winavr, t0-pin als
eingang). Läuft soweit so gut. (Abweichung bei 20khz ungefähr 100hz
(zuviel) gegenüber einem Orginal Frequenzzähler, evtl leichtes
Timingproblem der Schleife, ist im moment egal, wird später gemacht)
Das Problem:
Sobald es über 65536Hz geht (freq>65536) ist ja nen u_short am "ende".
kann aber nicht auf long gehen wegen dem UTOA-befehl fürs Display
(short>char). Gut dacht ich mir, machste halt in diesem Fall (wenn
Zähler über 64000): Ergebniss/1000 und Anzeige als kHz. Es will aber
nicht so richtig, es gibt immer nen Überlauf,d.h. die freq-variable
fängt wieder bei 0 an. Hab auch schon mal die freq-variable als long
definiert und das Ergebniss an eine u_short variable übergeben (passt ja
dann rein), geht auch nicht, sobald die Frequenz über 65536Hz ist gibts
nen überlauf.
Hier der Codeausschnitt (Completter Code im Anhang):
1
else//ab 64000hz = anzeige in kHz
2
{
3
lcd_clear();
4
freq=(256*ztmp+count)/1000;// durch 1000 weil freq unsigned short
5
utoa(freq,anz,10);// übergabe freq > anz (anz ist char)
utoa rauswerfen und stattdessen selber was schreiben. Ich hab's mir
einmal angeschaut und gleich wieder gelöscht, hat für mich nicht
getaugt.
Mit der Suche findest Du hier auch was brauchbares.
Nur wegen utoa die Variablenbreite zu beschränken und dann mit
Hilfskonstrukten drumrumlaborieren ist IMHO keine brauchbare Lösung.
swen schrieb:
> (Abweichung bei 20khz ungefähr 100hz> (zuviel) gegenüber einem Orginal Frequenzzähler, evtl leichtes> Timingproblem der Schleife, ist im moment egal, wird später gemacht)
Wenn du per CTC-Mode durch 125 teilen willst, musst du 124 in das
OC-Register laden, nicht 125.
> Hab auch schon mal die freq-variable als long definiert> freq = (256*ztmp + count)/1000; // durch 1000 weil freq unsigned
Der Überlauf passiert auf der rechten Seite in der Klammer. Die Größe
von freq spielt für diesen Überlauf (generell für die Berechnung auf der
rechten Seite) nicht die geringste Rolle. Entweder du machst aus ztmp
ein long, oder du kannst auch aus der "256" ein "256L" machen.
Stefan Ernst schrieb:
> swen schrieb:> Wenn du per CTC-Mode durch 125 teilen willst, musst du 124 in das> OC-Register laden, nicht 125.> Der Überlauf passiert auf der rechten Seite in der Klammer. Die Größe> von freq spielt für diesen Überlauf (generell für die Berechnung auf der> rechten Seite) nicht die geringste Rolle. Entweder du machst aus ztmp> ein long, oder du kannst auch aus der "256" ein "256L" machen.>
Jo danke dir, hat geholfen ztemp als long und schon läufts!
hab auch die schleife auf 124 gesetzt, viel mir dann auch wie schuppen
von den augen. abweichung nun kleiner aber nicht 0. bei 2000khz zeigt er
2015khz an. hmm. ne idee?
hatte noch nen felher gefunden (ein "count = 0;" war zuviel :-))
wenn ich sowohl das comparematch register als auch die schleife auf 124
setzte komme ich auf 1999khz.. hmm näher aber irgenwie "drüber"
Du solltest noch 'runden'
19990 / 1000
ergibt nun mal 19kHz und nicht 20kHz, auch wenn 20kHz der Wahrheit viel
näher kommen würde.
freq = (256L*ztmp + count + 500)/1000; //weil freq unsigned short
Stefan Ernst schrieb:
> Der Überlauf passiert auf der rechten Seite in der Klammer. Die Größe> von freq spielt für diesen Überlauf (generell für die Berechnung auf der> rechten Seite) nicht die geringste Rolle. Entweder du machst aus ztmp> ein long, oder du kannst auch aus der "256" ein "256L" machen.
Da diese Thematik im Forum des öfteren vorkommt, habe ich einen FAQ
dafür begonnen
http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen
Karl heinz Buchegger schrieb:
> Du solltest noch 'runden'>> 19990 / 1000>> ergibt nun mal 19kHz und nicht 20kHz, auch wenn 20kHz der Wahrheit viel> näher kommen würde.>> freq = (256L*ztmp + count + 500)/1000; //weil freq unsigned short
Wie meinst du das mit runden? also wenn ich 19,99kHz runde dann ergibt
das bei mir 20Khz, so wars in der Schule...;-)
du meins sicher, das die nachkommastellen rigoros abgeschitten werden,
wenn sie an "ztmp" übergeben werden, hmm stimmt.
Warum brauche ich 256L (ich denk mal d.h. als Long definiert)? Mit
"normal" 256 läufts, hab doch ztmp als long definiert (steht weiter
oben). ->Wenn ich nun aber 256L nehme und ztmp wieder als unsigned
chart, hab ich trotzdem nen Überlauf, beides zus. geht natürlich auch
Hab die Schleife noch mal angepasst. Nun ist der Fehler: rund 50hz
zuviel bei 200kHz. Nimmt bei geringeren frequenzen stetig ab (4 Hz zu
viel bei 20Khz, 2Hz zuviel bei 10Khz, fehlerfrei bis 2Khz). D.h. die
Schleife ist nenn Tick zu langsam, obwohl mathematisch korrekt
Muss ich da noch ein bissl Handoptimieren, oder sind das
Unzulänglichkeiten/Toleranzen in der Codeababarbeitung? Ist ja kein
Assembler
Schleifenausschnitt
1
while(1)
2
{
3
if(s==125){//schleife mit 1hz 16mhz/1024/125/125 = 1,0000 hz
4
count=TCNT0;
5
s=0;
6
ztmp=z;
7
z=0;
8
TCNT0=0;
9
if(ztmp<250)//1 - 64000Hz (256*250)
10
{
11
lcd_clear();
12
freq=256L*ztmp+count;
13
utoa(freq,anz,10);// übergabe freq > anz
14
set_cursor(0,1);// cursor pos setzen
15
lcd_string(anz);// anzeige frequenz
16
set_cursor(6,1);// cursor pos setzen
17
lcd_string("Hz");// anz. in Hz
18
}
19
else//ab 64000hz = anzeige in kHz
20
{
21
lcd_clear();
22
freq=(256*ztmp+count)/1000;//weil freq unsigned short
Swen schrieb:
> Karl heinz Buchegger schrieb:>> Du solltest noch 'runden'>>>> 19990 / 1000>>>> ergibt nun mal 19kHz und nicht 20kHz, auch wenn 20kHz der Wahrheit viel>> näher kommen würde.>>>> freq = (256L*ztmp + count + 500)/1000; //weil freq unsigned short>> Wie meinst du das mit runden? also wenn ich 19,99kHz runde dann ergibt> das bei mir 20Khz, so wars in der Schule...;-)
Das interessiert aber deine Berechnung nicht.
Eine Integer Division liefert keine Kommastellen.
Wenn du keine Vorkehrungen triffst, um bei einer Integer Division ein
gerundetes Ergebnis zu erhalten, dann wird auch nichts gerundet.
> Hab die Schleife noch mal angepasst. Nun ist der Fehler: rund 50hz> zuviel bei 200kHz. Nimmt bei geringeren frequenzen stetig ab (4 Hz zu> viel bei 20Khz, 2Hz zuviel bei 10Khz, fehlerfrei bis 2Khz). D.h. die> Schleife ist nenn Tick zu langsam, obwohl mathematisch korrekt
Das ist jetz durch deine Messmethode zu erklären.
Für das was du machst, gibt es einen eigenen Timermodus: Input Capture.
Damit kannst du Zyklengenau messen unabhängig davon, wie lange dein
Programm zur Auswertung braucht.
Die nächste Annahme, die du triffst:
Dein Quarz hat exakt 16000000 Hz. Die hat er aber nicht!
OK, aufm quarz steht 16,000 Mhz, da ist natürlich mit Abweichungen
unterhalb 1Khz anzunehmen, wenn man das so deutet, wie es draufsteht. da
muss wohl ein genauers (16,000000 Mhz :) )Quarz her, wenn es denn sowas
gibt.
also mit input capture könnte man es ja mal probieren., was dann aber
die unzulänglicheiten des quartzes aber nicht ausgleichen kann?!
Karl heinz Buchegger schrieb:
> Das ist jetz durch deine Messmethode zu erklären.> Für das was du machst, gibt es einen eigenen Timermodus: Input Capture.> Damit kannst du Zyklengenau messen unabhängig davon, wie lange dein> Programm zur Auswertung braucht.
ich hab da mal nen thread ausgegraben, da gehts genau darum (input
capture)
Beitrag "Input Capture Pin (ICP) auslesen ( Frequenz messen)"
da hast du freundlicherweise mal den code optimiert. nun lese ich aber
was von max 75khz. weil das capture interrupt permanent reinschiesst.
das wäre natürlich blöde.. ich brauch noch bissl cputime für weitere
aufgaben.
mein plan: nen frequenzgenerator (max038 oder sowas) mit dem avr
koppeln, d.h. ich stelle die frequenz mittels tasten am display ein, der
misst dann die permanet die frequenz (darum der freqcounter) und regelt
dann darauf ein und nach. da brauch ich ja noch kapazitäten.
Swen schrieb:
>> Beitrag "Input Capture Pin (ICP) auslesen ( Frequenz messen)">> da hast du freundlicherweise mal den code optimiert. nun lese ich aber> was von max 75khz. weil das capture interrupt permanent reinschiesst.> das wäre natürlich blöde.. ich brauch noch bissl cputime für weitere> aufgaben.
Grundsätzlich gibt es 2 verschiedene Messmethoden
a) Man baut ein 'Tor'
Dieses Tor lässt man zb 1 Sekunde offen stehen, und zählt wieviele
Pulse in dieser Zeit am Tor sichtbar sind.
b) man misst die Zeit von einer steigenden Flanke des Signals bis
zur nächsten steigenden Flanke
Geht man nun davon aus, dass man Zeiten nicht beliebig genau messen
kann, dann kann man sich mal fragen, wie sich eigentlich der Messfehler
in den beiden Methoden verhält.
Und da sieht man etwas Interessantes: In Methode a) wird der Messfehler
mit steigender Frequenz kleiner. Bei Methode b) hingegen wird der
Messfehler mit fallender Frequenz kleiner.
Es gibt daher einen Punkt, über dem man mit Methode a) besser bedient
ist und darunter mit Methode b)
Zudem ist man in beiden Fällen extrem gut beraten, wenn man die Messung
erst dann starten lässt, wenn das Signal gerade eine Flanke macht.