Hallo zusammen, bin Anfänger also alles ganz langsam. Ich programmiere eine Frequenzmessung in C (Atmel Studio 7, GCC). Dazu muss ich das ICF1-Flag abfragen ob dieses innerhalb 40ms gesetzt wurde. Ist dies nicht der Fall, Ausgabe "A" Ist dies der Fall, ICR1-Wert in eine Variable und auf das nächste ICF1-Flag warten. Leider habe ich keine Ahnung wie ich die "Warteschleife" umsetzen soll. An sich müsste es Sinngemäß so funktionieren: if (TIFR1 == 0x27 && Zeit<40ms) {Anweisung} Ich kann da auch keine for-Schleife nehmen die 1ms pro Durchlauf dauert, das verfälscht mein Ergebnis. Und es darf keine ISR benutzt werden...soll eben alles in der Hautschleife passieren. Danke für eure Hilfe AC
AC schrieb: > Und es darf keine ISR benutzt werden...soll eben alles in der > Hautschleife passieren. Wer verbietet das?
Da das ganze Programm sehr Zeitkritisch wird soll dort keine ISR benutzt werden. Die Frequenzmessung soll in der Hauptschleife geschehen. Dieser jemand der das "verbietet" hat das ganze, wie oben beschrieben, in BASCOM programmiert und ich muss jetzt diesen Teil aber in C umsetzen.
AC schrieb: > Da das ganze Programm sehr Zeitkritisch wird Das kann nicht sein, wenn es erlaubt ist mehrere Millisekunden in der Hauptschleife auf ein Flag aktiv zu warten.
tja, was soll ich sagen...ich habe die frequenzmessung schon mit der ISr Timer1 Capt gemacht und da zittert der Wert etwas (bei eingestellten 55Hz zwischen 55,018Hz und 54,863Hz). Und ich soll es jetzt wie oben geschrieben programmieren...also nochmal: Leider habe ich keine Ahnung wie ich die "Warteschleife" umsetzen soll. An sich müsste es Sinngemäß so funktionieren: if (TIFR1 == 0x27 && Zeit<40ms) {Anweisung} Jemand eine Idee?
AC schrieb: > tja, was soll ich sagen...ich habe die frequenzmessung schon mit der ISr > Timer1 Capt gemacht und da zittert der Wert etwas (bei eingestellten > 55Hz zwischen 55,018Hz und 54,863Hz). > Und ich soll es jetzt wie oben geschrieben programmieren...also nochmal: > > Leider habe ich keine Ahnung wie ich die "Warteschleife" umsetzen soll. > An sich müsste es Sinngemäß so funktionieren: > > if (TIFR1 == 0x27 && Zeit<40ms) > {Anweisung} > > Jemand eine Idee? Suche dir eine andere Aufgabe.
AC schrieb: > Und ich soll es jetzt wie oben geschrieben programmieren Es ist völliger Unsinn das nicht mit einer ISR zu machen. Dagegen spricht auch eine Zeitkritikalität des restlichen Programms nicht. Wenn eine Interrupt-Unterbrechung von wenigen Mikrosekunden dein Programm stört, dann ist es falsch.
AC schrieb: > tja, was soll ich sagen...ich habe die frequenzmessung schon mit der ISr > Timer1 Capt gemacht und da zittert der Wert etwas (bei eingestellten > 55Hz zwischen 55,018Hz und 54,863Hz). Dann rechne mal nach, wie hoch Dein Quantisierungsfehler überhaupt ist. Der Witz am Cature ist nämlich, daß es von der Interruptlatenz unabhängig ist. Aber besser als ein Timertakt kann es nicht auflösen. Wenn das nicht reicht, mußt Du den Timertakt erhöhen oder über mehrere Perioden messen.
Bevor ich die Aufgabe bekommen habe, habe ich es, wie folgt umgesetzt wobei der Wert z.B bei eingestellter frequenz vonn 55Hz zwischen 55,018Hz und 54,863Hz zittert:
1 | Timer Initialisierung: |
2 | TCCR1A = 0x00; //Timer1 Normal Mode |
3 | TCCR1B = 0x45; //Input Capture Edge (Positive Flanke); Kein Vorteiler |
4 | TIMSK1 |= (1<<ICIE1); //Input Capture Interrupt aktiviert |
5 | //TIMSK1 |= (1<<TOIE1); //Timer Overflow Interrupt aktiviert
|
6 | |
7 | ISR: |
8 | ISR(TIMER1_CAPT_vect) //Interrupt Service Routine Timer1 - Capture |
9 | {
|
10 | if (messflag ==1) |
11 | return; |
12 | |
13 | if (flanke_nr == 0) |
14 | {
|
15 | start_wert = ICR1; |
16 | flanke_nr = 1; |
17 | }
|
18 | |
19 | else if (flanke_nr == 1) |
20 | {
|
21 | end_wert = ICR1; |
22 | flanke_nr = 0; |
23 | messflag = 1; |
24 | }
|
25 | }
|
26 | |
27 | Schleife: |
28 | float frequenz = 0.0; //Ergebnis Frequenzmessung |
29 | char buffer[20]; //Buffer für die Page 2 Ausgabe |
30 | |
31 | if (messflag == 1) //Messung durchgeführt und bereit zur Ausgabe |
32 | {
|
33 | |
34 | //*****************Berechnung Frequenz************************
|
35 | if (end_wert <= start_wert) |
36 | {
|
37 | frequenz = ( 65536 + end_wert ) - start_wert; |
38 | frequenz = 20000000 / frequenz; |
39 | frequenz = frequenz / 1024; |
40 | }
|
41 | else
|
42 | {
|
43 | frequenz = end_wert - start_wert; |
44 | frequenz = 20000000 / frequenz; |
45 | frequenz = frequenz / 1024; |
46 | }
|
47 | //_delay_ms(500);
|
48 | //**********Ausgabe Frequenz***************
|
49 | if (frequenz < 45 || frequenz > 65) |
50 | {
|
51 | char_x=2;//0-128 |
52 | char_y=7; //0-8 |
53 | display_write("Out of Range"); |
54 | }
|
55 | |
56 | else
|
57 | {
|
58 | display_clear(); |
59 | char_x=2;//0-128 |
60 | char_y=7; //0-8 |
61 | sprintf (buffer, "Frequenz: %4.3f Hz",frequenz); //Ausgabe Frequenz |
62 | display_write_str(buffer); |
63 | }
|
64 | |
65 | messflag =0; //Messung ausgegeben |
66 | }
|
Controller ist ein Atmega1284P mit 20Mhz Takt. Die Frequenz wird von einem FreqGen (Velleman) der per USB angeschlossen wird eingespeist. Ist der Code so in Ordnung oder könnte das Zittern der Werte irgendwo im Code verursacht werden?
Sehe gerade bei TCCR1B = 0x45; habe ich noch den alten Kommentar gelassen. Vorteiler ist 1024.
Peter D. schrieb: > Dann rechne mal nach, wie hoch Dein Quantisierungsfehler überhaupt ist. Das sollte er tatsächlich dringend mal tun, völlig klar. > Der Witz am Cature ist nämlich, daß es von der Interruptlatenz > unabhängig ist. Nein, leider natürlich nicht wirklich. Klar, das Capture selber passiert unabhängig von allen Aktivitäten der MCU. Aber: Der Code muss auf ein ICP-Ereignis reagieren, bevor das nächste eintritt, sonst ist der Capturewert schlicht verloren und es wird Müll bei der Messung herauskommen, weil erst der nächste (oder übernachste...u.s.w.) Capturewert zur Messung verwendet wird. Das gilt übrigens völlig unabhängig davon, ob der Code zur Messung in einer ISR agiert oder in main(), da sowohl die Antwortzeit in main() als auch in einer ISR unmittelbar von den Sperrzeiten aller anderen Interrupts im System abhängt. Deswegen ist es natürlich sehr vermessen, zu sagen, das Capture wäre von der Interruptlatenz unabhängig...
AC schrieb: > Die Frequenz wird von einem FreqGen (Velleman) der per USB > angeschlossen wird eingespeist. Und wieviel Jitter hat der?
AC schrieb: > Bevor ich die Aufgabe bekommen habe, habe ich es, wie folgt umgesetzt > wobei der Wert z.B bei eingestellter frequenz vonn 55Hz zwischen > 55,018Hz und 54,863Hz zittert: > frequenz = frequenz / 1024; Soll man daraus die nicht ganz unwichtige Erkenntnis ziehen, dass der Timer womöglich mit einem Prescaler von 1024 läuft? Das hieße, er läuft mit einer Frequenz von ca. 19,5 kHz und kann damit die Periodendauer in Schritten von ca. 51 µs ermitteln. Deine 55 Hz haben eine Periodendauer von ca. 18 ms, was etwa 355 mal so viel ist. Das heißt, wenn deine Messung nur um einen Timer-Tick schwankt, reicht das schon aus, um deinen angezeigten Wert um etwa 0,15 Hz schwanken zu lassen, was ziemlich genau deiner Beobachtung entspricht. Mit anderen Worten: Die Auflösung deiner Messung ist einfach nicht höher.
Der Vorteiler ist mit 1024 zu groß, folglich der Zählwert zu klein: er wird derzeit 355 oder 356, und daraus werden nach obiger Rechnung eben 55.0176 bzw. 54.8631.
Mal ganz davon abgesehen kümmert sich der Code nicht um atomare Zugriffe oder darum, was passiert, wenn während der Ausgabe ein Interrupt auftritt. Da kommt dann in manchen Fällen vermutlich auch mal zwischendrin irgendein Unsinn raus.
AC schrieb: > Schleife: Du nutzt nicht zufällig die Arduino-Umgebung? Da werden Timer durchaus auch mit anderen Aufgaben betraut - ohne das Du es siehst. Falls nicht - was macht Dein Programm denn sonst noch so?
S. Landolt schrieb: > er wird derzeit 355 oder 356, und daraus werden nach obiger Rechnung eben > 55.0176 bzw. 54.8631. Wie einfach man es doch schreiben kann. ;-) Meins wirkt dagegen so kompliziert...
Ein Vorteiler von 8 wäre optimal, wenn nur diese 55 Hz gemessen werden sollen.
Danke für die Erklärung das es schon mal mit der Auflösung zu tun haben kann. Wenn ich jetzt den Vorteiler auf 1 setze und die Zeile
1 | frequenz = frequenz / 1024; |
in der Berechnung rausnehme, dann werden bei 50Hz, 2932,121 Hz angezeigt. Die erste Stelle vor dem Komma und die Nachkomma stellen zittern etwas. Hab ich einen Fehler in der Berechnung? Dann würde ich Timer1 ohne Vorteiler laufen lassen. Auf dieser "seite" (Display) wird nur die Frequenz ausgegeben und auf einer anderen "seite" 2 ADC Werte. Die Display Seiten schalte ich mit einem Taster um.
Die Frequenzrange ist von 45Hz bis 65Hz. davor und danach wird Out of Range ausgegeben.
Der Timer1 hat 16 bit: 2^16=65536; mit Vorteiler=1 und 50 Hz ergibt sich bei 20 MHz aber ein Zählwert von 400000.
c-hater schrieb: > Der Code muss auf ein > ICP-Ereignis reagieren, bevor das nächste eintritt Das habe ich bei 55Hz einfach mal als gegeben vorausgesetzt.
d.h bei 400000 Zählschritten macht er über 6 Overflows und ich addiere nur 1? Wenn ich den Vorteiler auf 8 setze dann dauert ein zählschritt 400ns, also bei 20ms (50Hz) sind es 50000. Schlimmstenfalls bei 45Hz 55555,56 zähltakte...wäre dann ein overflow?
Solange du sicher weniger als die 65536 brauchst, die der Zähler an Schritten hat, passt alles.
Yeah...danke euch! Habe jetzt den Vorteiler auf gesetzt und bei 45Hz werden 44,996Hz und bei 65Hz werden 64,994Hz angezeigt. Und wenn überhaupt dann zuckt nur die letzte Nachkommastelle. das ist dann ne Abweichung von nichtmal 0,01% das muss reichen...anstatt das bereits programmierte zu optimieren habe ich mich verrückt machen lassen. Danke nochmal
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.