Hallo, ich habe ein Problem mit einem Projekt. Ich sollte eine Frequenz messen (zwischen 100Hz bis 5000Hz). Ich habe es bis jetzt so versucht: bei einer steigenden Flanke wird ein Zähler gestartet (200kHz) und wird bei jeder steigenden Flanke wieder zurückgesetzt. Der Zählerstand wird an einem Display ausgegeben (die Mathematik um dies wieder in eine Frequenz umzurechnen brauch ich nicht, da ich einige Abtastwerte speichere und diese dann Vergleiche...es sollte übrigens ein Stimmgerät werden). Nun mein Problem, ich habe bei eine Frequenz von 440Hz einen Abtastwert von 454 berechnet. Ich komme aber nur auf einen Wert von 423. Der Schaltplan liegt im Anhang :) Mein Code sieht bisher so aus: volatile unsigned long wert = 0; volatile unsigned long wert1 = 0; SIGNAL(SIG_OUTPUT_COMPARE0) { wert++; } SIGNAL(SIG_INTERRUPT1) { wert1=wert; wert=0; } int main(void) { DDRD=0x00; TCCR0 = 0b00001001; TIMSK = 0x02; OCR0=12; MCUCR = 0x0C; GICR = 0x80; sei(); lcd_init(); while(1) { lcd_pos(0,0); printf("Wert: %8d",wert1); } } Ich hoffe mir kann jemand helfen!
Mir leuchtet nicht ein, warum dein Komparator bei einem um 0 symmetrischen Audiosignal nicht mit 0V vergleicht, sondern mit halbem Maximum. > es sollte übrigens ein Stimmgerät werden). Dazu reicht das Verfahren natürlich vorne und hinten nicht. Schlag nach was eine FFT ist. Zudem ist den LM358 als Komparator mit vollem output swing nicht mehr so richtig tauglich für hohe Töne.
Mit der analogen Schaltung habe ich kein Problem, diese funktioniert ohne Probleme! Nur die Messung mit dem Atmega16. Mit dem Komparator "filtere" ich die Obertöne heraus, da die Nulldurchgänge nicht die Grundfrequenz ist. Im Anhang siehst du warum ich es mit 90% des maximal wertes vergleiche.
Grundsätzlich mast du es ja richtig, nur das mit dem Timer durchblicke ich nicht. Irgendwas stimmt da nicht. Also erstmal kannst du den Timer ruhig auf Vollgas laufen lassen, dass erhöht deine Auflösung. Dann triggerst du bei steigender Flanke die Messung indem du dir dein aktuellen Zählerstand merkst. Bei der nächsten steigenden Flanke guckst du dir wieder den Zählerstand an, nebenbei zählst du noch die Timerüberläufe mit. Danach berechnest du die Timerincremente: Incremente = Überläufe * (2^Bits Timer)- neuer Wert+ alter Wert mit den Incrementen bestimmst du die Frequenz: F_Timer/Incremente * (gewünschte Auflösung [10 für 10tel Hz, 100 für 100tel Hz]) fertig ist die Laube... Es ist sinnvoll über ein Paar Perioden zu mittel bevor man die Frequenz ausrechnet... Aber dein Komparator sieht in der Tat etwas seltsam aus. Ingo
alex schrieb: > Im Anhang siehst du warum ich es mit 90% des maximal wertes vergleiche. Äh, tust du nicht, du vergleichst mit 99%, denn 1,2/1,21 = 0,9917 Ingo
Oszillographier doch mal am Komparatorausgang, dass ist ja der interessante Teil!
> Äh, tust du nicht, du vergleichst mit 99%, denn
Sorry mein Fehler!
Danke Ingo, ich werde es einmal so versuchen.
Leider habe ich erst am Montag wieder ein Oszilloskop in der Hand
(Schüler ^^).
Aber das Ausgangssignal am Ausgang des Komparators kommen "Nadeln" mit
der Grundfrequenz heraus.
alex schrieb: > Aber das Ausgangssignal am Ausgang des Komparators kommen "Nadeln" mit > der Grundfrequenz heraus. Wenn dem so ist, ist da ja gut. Jedoch wäre mal interessant wie es aussieht. Was noch auffällt, dass der Komparator absolut keine Hysterese hat, ohne die es jedoch relativ schnell zu Schwingungen führt, gerade beim Umschalten. Ingo
Ich werde gleich am Montag, falls ich dazu komme, das Signal aufnehmen! Ingo: Ich sollte bei jeder Steigenden Flanke ein Interrupt auslösen und dann die Überläufe, den End- bzw den Anfangsstand speichern. Ich glaube, für dies muss ich mich noch ein wenig einlesen, bin eben noch Neuling ;-)
alex schrieb: > Ich sollte bei jeder Steigenden Flanke ein Interrupt auslösen und dann > die Überläufe, den End- bzw den Anfangsstand speichern. > Ich glaube, für dies muss ich mich noch ein wenig einlesen, bin eben > noch Neuling ;-) So ist es, aber man wächst mit seinen Aufgaben... Is aber recht trivial Ingo
alex schrieb: > Ich sollte eine Frequenz messen... Und warum nimmst Du nicht ein fertiges Frequenzmeßgerät?
Dirk J. schrieb: > Und warum nimmst Du nicht ein fertiges Frequenzmeßgerät? alex schrieb: > Leider habe ich erst am Montag wieder ein Oszilloskop in der Hand > (Schüler ^^) alex schrieb: > es sollte übrigens ein Stimmgerät > werden Noch Fragen??? Ingo
alex schrieb: > wird ein Zähler gestartet (200kHz) > OCR0=12; Du weist, dass Die Formel für die Aufrufrate bei CTC
lautet ? Bzw. dass der Timer0 damit 13 Takte für 'ne Runde braucht. Deine Taktfrequenz wäre dann bei 200kHz x 13 = 2,6MHz, sehr ungewöhnlicher Takt. Außerdem mit dem hier: > TCCR0 = 0b00001001; > OCR0=12; > TIMSK = 0x02 hast Du eben nur 13 Takte zur Verfügung um in der ISR einen volatile Long zu inkrementieren, das ist völlig illusorisch. Tatsächlich benötigt das um die 60 Takte. Womit wiederum Dein vermeintliches Ergebnis: > Ich komme aber nur auf einen Wert von 423. Makulatur ist. Also zurück auf Start und ziehe keine 1000 Mark ein. Außerdem würd' ich mir das Das Konfigurieren der Register per Binär- oder Hex-Konstanten abgewöhnen, das ist ein Unding.
Ich habe das OCR Register nun auf 60 geändert (200kHz wenn ich mich nicht täusche) jedoch habe ich immer noch fast den gleichen Fehler.
Die 60 Zyklen für die ISR waren nur ein Schätzwert, das können auch noch ein paar mehr sein. 200 kHz könnte schon etwas zu schnell sein für den µC. Die logischere Lösung hat Ingo oben schon genannt: einfach einen Timer laufen lassen, und die Timerregister auslesen. Das Hochzählen einer Variable in einer Timer ISR ist fast immer eine suboptimale Lösung zur Zeitmessung. Das Hochzählen der "Zeit" ist eigentlich genau das was die timer Hardware macht. Falls es zu schnell geht, gibt es dafür den Vorteiler. Das wird vor allem dann einfacher, wenn man timer 1 nimmt, der hat mit 16 Bit genügend Auflösung und man muss sich nicht groß um Überläufe von Hand kümmern - das ist nämlich nicht ganz so trivial wie es scheint.
Ulrich schrieb: > Die 60 Zyklen für die ISR waren nur ein Schätzwert Es waren 58 Zyklen ab Resetvektor. Je nach gerade ausgeführtem Befehl dauert es 1,2 oder 3 Zyklen, bis dieser zu Ende ausgeführt wurde. > wenn man timer 1 nimmt, der hat mit 16 Bit genügend Auflösung Und man kann den Input Capture nutzen, der das Ganze schon viel entspannter werden lässt. alex schrieb: > Ich habe das OCR Register nun auf 60 geändert (200kHz wenn ich mich > nicht täusche) jedoch habe ich immer noch fast den gleichen Fehler. Bei 60 (61 Durchläufe) hast Du immer noch ~100% Prozessorlast, erst wenn Du drüber gehst, wird der Timer das zeitbestimmende Element und Du wirst Unterschiede merken. Wie hoch ist denn die Taktfrequenz ? Außerdem, die ISR ist auch deshalb so lang, weil der Compiler 4 Prozessorregister für den Long benutzt, er diese sichern muss und auch weil dann 4 Byte aus dem SRam geholt und dorthin wieder gesichert werden müssen. Wenn's schon der Ansatz mit Timer0 sein soll, dann nimm ein Word, das geht schneller und reicht auch.
Ja, MWS (Gast) hat recht ! Frequenzmessungen macht man mit dem "Input Capture Mode" , ich hoffe mal dieser uC hat sowas auch. GOOGLE: Frequenzmessung "input capure mode"
MWS und Erich, hätte ich den ICP Pin am ATMEGA verwenden sollen? oder geht das mit jedem beliebigen?
alex schrieb: > MWS und Erich, hätte ich den ICP Pin am ATMEGA verwenden sollen? oder > geht das mit jedem beliebigen Das geht nur mit dem.
Also müsste ich den Schaltplan ändern und ein neues Layout erstellen - neuer Print! Gibt es keine andere Lösung?
alex schrieb: > hätte ich den ICP Pin am ATMEGA verwenden sollen? oder Alternativ kann der Input Capture über den Analog Comparator getriggert werden, der AC kann wiederum über den Multiplexer gefüttert werden. Da hast Du dann zwar mehr Pins zur Auswahl, auf Deinen Int1-Pin kommst Du damit immer noch nicht. > ein neues Layout erstellen - neuer Print! Gibt es keine andere Lösung? Doch da fiele mir schon was ein, musst halt ausprobieren, ob das geht. Im Datenblatt findest Du unter "Alternate Functions of Port D" den ICP1 auf Pin6. In manchen Fällen "überfährt" eine alternative Portfunktion die originale Funktion vollständig, in anderen Fällen bleiben sie zumindest teilweise intakt. Bei den ext. Int's ist's so, dass man die auf Ausgang schalten und damit den Interrupt per Software auslösen kann. Das könnte hier auch gehen, wenn der ICP1-Pin nicht anders verwendet wird. Dann schaltest Du den auf Ausgang und triggerst ihn in der Int1-ISR. Das kostet Dich nicht viel Rechenzeit und solange keine weiteren ISR's (außer der Capture-ISR) aktiv sind, wird das zwar 'ne kleine Verzögerung erzeugen, aber immer annähernd dieselbe. Du hast natürlich eine Unsicherheit zwischen 1-3 Takten, die es dauert um aus dem aktuellen Befehl raus in eine ISR zu springen, das verschlechtert Deine Auflösung. Damit genau das nicht passiert, nimmt man eigentlich Input Capture, aber kannst es ja mal als Notlösung versuchen. Du hast immer noch nicht beantwortet nach was ich gefragt hab', nämlich die Taktfrequenz, aber gehen wir mal aus, dass Dein Code mit 200kHz hochzählen konnte, mal 60 Takte hättest Du einen 12MHz Quarz dran. Bei 440Hz entspräche eine vollständige Periode dann 27272 Takten, bei einem Prescaler von 1 wäre das gleichzeitig das Ergebnis der Capture. Bei einer Unsicherheit von 1 bis 3 Zyklen käme dann bei exakt gleicher Eingangsfrequenz von 440 Hz ein Zählwert von 27270 bis 27272 raus, was 440,04 bis 440,01 Hz als Ergebnis entspricht, also sollte der Fehler aus dieser Int1-Lösung für Deinen Zweck unerheblich sein. Bei 10kHz ist der Fehler Prinzip-bedingt größer, da ist das Ergebnis dann 10000 bis 9983 Hz. Hinzu käme noch +-2 Takte wenn der Trigger ungünstig zwischen 2 Prozessortakte fällt. Das Capture Verfahren wird beiläufig immer ungenauer, je kleiner das Capture-Ergebnis wird. So, und jetzt darfst Du mal weitermachen, ist ja nicht meine Aufgabe ;D
MWS schrieb: > Das könnte hier auch gehen, > wenn der ICP1-Pin nicht anders verwendet wird. Grad' gesehen, dass ICP1 auf JP1 raus geht, dürfte das LCD sein. Wenn Du Glück hast und dort nur ein Datenpin dran hängt, stört das nicht weiter, Du darfst halt dann nur messen, wenn Du nichts auf dem LCD ausgibst und vice-versa.
Timer1 kann man auch ohne ICP nutzen. ICP wäre zwar die Ideale Lösung, aber so viel schlechter ist es mit Interrupt und dann auslesen des Timers auch nicht. Der Umweg über Interrupt und dann künstlich den ICP auszulösen ist nur umständlich, das auslesen des Timers braucht auch nicht länger und ist einfacher. Vor allem stört eine feste Verzögerung nicht, sondern nur eine Variabel. Für die Anwendung hier reicht die Genauigkeit mit dem Interrupt auch aus. So lange kein anderer Interrupt aktiv ist, hat man eine unbekannte Verzögerung von maximal 6 Zyklen - so genau wird das Signal vom Mikrofon nicht sein.
Ulrich schrieb: > Der Umweg über Interrupt und dann künstlich den ICP > auszulösen ist nur umständlich, das auslesen des Timers braucht auch > nicht länger und ist einfacher. Dafür kann der TE bei neuer geeigneter Platine problemlos die bessere Methode nutzen, nur Int1 deaktivieren und ICP1 als Eingang. > Vor allem stört eine feste Verzögerung nicht, sondern nur eine Variabel. Eine variable Verzögerung ergibt sich bereits aus der ungewissen Zahl an Zyklen von Interrupt-Auslösung bis Ausführung, ist aber in beiden Fällen gering.
Kann mir jemand beim programmieren helfen? Ich habe bis jetzt immer nur mit dem Timer0 gearbeitet und weiß eigentlich nicht wie ich beginnen sollte. Hier ist noch das Ausgangssignal des Komparators:
Ingo schrieb: > Incremente = Überläufe * (2^Bits Timer)- neuer Wert+ alter Wert Sicher? Ich hätte gesagt so: Incremente = Überläufe * (2^Bits Timer)+ neuer Wert - alter Wert
Die Programmierung ist mit Timer 1 auch nicht so viel anders. Das extra Zählen von Überläufen bei timer 0 ist deutlich komplizierter - das kommen nämlich noch Tücken und zusätzliche Fehler dazu, wenn das Signal fast gleichzeitig mit dem Überlauf auftritt. Der wesentliche Unterschied bei timer1 ist, das man da gleich einen 16 Bit Wert hat, und deshalb ohne den Interrupt für die Überläufe auskommt. Die Zeit ließt man im Interrupt vom Signal (z.B. int1) einfach direkt aus dem Timerregister TCNT1 aus. Dank C Compiler geht das gleich als 16 Bit wert. Damit die Zeit reicht, braucht man ggf. einen Prescaler beim konfigurieren des Timers - ein Wert von 8 sollte reichen, bei hohen µC Takt ggf. besser :64. Die Periodenlänge bekommt man dann aus der Differenz neuer Wert - alter Wert. Dabei sollten die Variablen 16 Bit unsigned sein, dann hat man auch keine Probleme falls dazwischen 1 Überlauf des Timers vorkommt. Erst wenn die Zeit über 2^16 Timer Ticks liegt gibt es Probleme - das sollte aber schon bei sehr niedriger Frequenz liegen (z.B. unter 10 Hz). Das Abfangen ist da allerdings nicht so einfach ohne einen 2. Interrupts der ggf. kleine Fehler in der Messung verursachen kann.
Kann mir jemand sagen wie ich die Register setzten muss, um diesen Modus den ich benötige zu erhalten? Und wie kann ich die Werte dann herauslesen? Ich wäre über einen Programmcode sehr dankbar (:
GOOGLE fragen: "frequency measurement" "<Prozessortyp genaue Bezeichnung>" "source code" Die Gänsefüßchen dran lassen !
Naja, allzu viel findet man nicht! Bis auf das habe ich nichts gefunden: http://www.hackchina.com/en/r/53443/1602_main.c__html jedoch werde ich aus dem Code nicht wirklich schlau....
alex schrieb: > Naja, allzu viel findet man nicht! http://www.mino-elektronik.de/fmeter/fm_software.htm
Ich habe es nun mal versucht zu schreiben. Jedoch habe ich ein Problem mit der Ausgabe, wenn ich ein Ton spiele, und gleich aufhöre wird ein Wert angezeigt (ich glaube sogar richtig) und wenn ich dauerhaft spiele bleibt 0 stehen... SIGNAL(SIG_INTERRUPT1) { altwert=wert; wert=ICR1; } int main(void) { DDRA=0x00; DDRD=0x00; TCCR1B=0b00000010; MCUCR = 0x0C; GICR = 0x80; sei(); lcd_init(); while(1) { old=new; new=65536-altwert+wert; if(old==new) { lcd_pos(0,0); printf("Wert: %8d",new); } } }
Erich schrieb: > Ja, du machst bei Änderungen auch keine Ausgabe. Ich mache dann eine Änderung wenn 2 Werte hintereinander gleich sind?
Der Programm-ausschnitt hat schon mal das Problem, dass nicht richtig auf das Ende einer Messung gewartet wird. Die Abfrage auf (old==new) wird damit fast wirkungslos - einen Durchlauf der While-schleife später ist die dann erfüllt, falls nicht zufällig gerade ein neuer Messwert kommt. Ein weiters Problem könnte sein, dass die ISR für INT1 ist, ausgelesen wird aber ICR1, was dazu passen würde das das Signal am ICP Pin ist. Wenn das Signal an INT1 anliegt, so wie zuvor, dann müsste man da den Timer auslesen, also TCNT1.
Danke für die Antwort, ich lese nun mit dem TCNT1 aus! Dabei komme ich auf einen extrem schwankenden Wert, eine völlig sinnlose Messung also! Und außerdem ist er etwa um den Faktor 10 zu klein, als wie er sein sollte.
Ich habe den angezeigten Wert zurückgerechnet, dieser würde ca. bei einer Abtastung von 1,5 Mhz stimmen, allerdings taste ich mit 12Mhz ab, wo bleiben die anderen 10,5?
Hi >Ich habe den angezeigten Wert zurückgerechnet, dieser würde ca. bei >einer Abtastung von 1,5 Mhz stimmen, allerdings taste ich mit 12Mhz ab, >wo bleiben die anderen 10,5? CKDIV8 Fuse gesetzt? MfG Spess
Hi
>Ich habe nur diese gesetzt.
Und weshalb sollte dein Controller mit 12MHz laufen. Du hast 1MHz
interner RC-Oszillator eingestellt.
MfG Spess
Hi >Welche Fuses müsste ich setzten? Datenblatt? >Ich habe einen 12Mhz Quarz.... Hoffentlich richtig angeschlossen. MfG Spess
@alex Wie wäre es wenn du mal endlich anfängst zu begreifen was du da machst?! Beschäftige dich doch erstmal mit den Basics anstatt hier Hals über Kopf was lostreten zu wollen. Ingo
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.