Hallo Forum, ich habe einen Frequenzmesser mit dem ATmega programmiert. Nun mein Problem: Wenn die Frequenz, sagen wir bei 6000 Hz liegt können da ab und an Schnitzer von 30 Hz gemessen werden. Die Geister wissen warum. Ich weiß es nicht. Ich lese immer den Timer nach einem Interrupt aus und da kommt es ab und an vor, daß der Wert eklatant vom eigentliche erwarteten abweicht. Habt ihr eine Lösung wie ich solche Schnitzer (muß ja nicht genau 30 Hz sein kann mehr oder weniger sein) die extrem vom erwarteten abweichen erkennen kann?
anfänger0815 schrieb: > Ich weiß es nicht. Ich habe eine Vermutung. Es könnte an deinem Programm liegen.
Karl Heinz schrieb: > anfänger0815 schrieb: > >> Ich weiß es nicht. > > Ich habe eine Vermutung. > Es könnte an deinem Programm liegen. Ich tippe eher auf Bug im Compiler oder libc. Sein Programm hört sich richtig an, so wie er es beschreibt ;-)
Vieleicht ein mikroskopisch kleines schwarzes Loch, das eine Zeitdilatation verursacht. Wohnst du vieleicht in der Nähe vom Cern? Im Ernst: SOURCECODE, und bitte siehe Netiquette dazu.
Udo Schmitt schrieb: > Vieleicht ein mikroskopisch kleines schwarzes Loch, das eine > Zeitdilatation verursacht. > Wohnst du vieleicht in der Nähe vom Cern Das klingt schlüssig. Raumschiff Enterprise hatte ja öfter mal Probleme mit dem Bordcomputer in der Nähe von Singularitäten. Da kann dann auch mal ganz schnell das Raum-Zeit-Kontinuum instabil werden. Uiuiui.
cyblord ---- schrieb: > Udo Schmitt schrieb: >> Vieleicht ein mikroskopisch kleines schwarzes Loch, das eine >> Zeitdilatation verursacht. >> Wohnst du vieleicht in der Nähe vom Cern > > Das klingt schlüssig. Raumschiff Enterprise hatte ja öfter mal Probleme > mit dem Bordcomputer in der Nähe von Singularitäten. Da kann dann auch > mal ganz schnell das Raum-Zeit-Kontinuum instabil werden. Uiuiui. Ja, schon. Aber spätestens seit Cpt. Piccard ist ja bekannt, wie man das löst: Man weißt den Computer an, die Schilde auf ein Zufallsmuster mit exakt 78.652985% Anteil von weißem Rauschen zu progammieren. Mach es so!
Anbei mein Code für den Kern des Frequenzmessers. Ist aber nicht so ganz mein Problem. Wie bekomme ich diese, nennen wir sie mal Spitzen, weg
1 | ;Hier werden die Voreinstellungen gemacht |
2 | .cseg |
3 | |
4 | zaehler1_messen_vor: |
5 | ldi tmp1,0 |
6 | out TCCR1A,tmp1 |
7 | ;Vorverteiler durch 8 |
8 | ldi tmp1,0b10000010 |
9 | out TCCR1B,tmp1 |
10 | ;Timer Interupt Mask |
11 | in tmp1,TIMSK |
12 | ori tmp1, (1<<TICIE1 | 1<<TOIE1) |
13 | out TIMSK,tmp1 |
14 | ret |
15 | ;------------------------------------------------------------------------------------------------------------- |
16 | zaehler1_ueberlauf_int: |
17 | ;Beim Ueberlauf des Zaehler 1 wird diese Spz um |
18 | ;eins erhoeht. Dadurch koennen sehr kleine Frequenzen |
19 | ;gemessen werden |
20 | push tmp6 |
21 | in tmp6,sreg |
22 | push tmp6 |
23 | lds tmp6,zaehler1_hoch_temp_temp |
24 | inc tmp6 |
25 | sts zaehler1_hoch_temp_temp,tmp6 |
26 | pop tmp6 |
27 | out sreg,tmp6 |
28 | pop tmp6 |
29 | reti |
30 | ;------------------------------------------------------------------------------------------------------------- |
31 | ;Dieser Programmteil wird angesprochen wenn sich am Steuereingang fuer Zaehler 1 der Pegel von Low nach High aendert. |
32 | zaehler1_start_stop: |
33 | push tmp4 |
34 | in tmp4,sreg |
35 | push tmp4 |
36 | push tmp5 |
37 | push tmp6 |
38 | push tmp7 |
39 | push tmp8 |
40 | push tmp9 |
41 | lds tmp5,zaehler1_status |
42 | sbr tmp5,2 |
43 | sts zaehler1_status,tmp5 |
44 | |
45 | ;Der aktuelle Zaehlerstand wird in die Register gespeichert |
46 | in tmp4,TCNT1L |
47 | in tmp5,TCNT1H |
48 | lds tmp6,zaehler1_hoch_temp_temp |
49 | |
50 | ;Der alte Zaehlerstand wird in die Register gespeichert |
51 | lds tmp7,zaehler1_nieder_tmp |
52 | lds tmp8,zaehler1_mittel_tmp |
53 | lds tmp9,zaehler1_hoch_tmp |
54 | |
55 | ;Der aktuelle Zaehlerstand wird gesichert |
56 | sts zaehler1_nieder_tmp,tmp4 |
57 | sts zaehler1_mittel_tmp,tmp5 |
58 | sts zaehler1_hoch_tmp,tmp6 |
59 | |
60 | ;Der Zählerstand (Drei Byte) wird vom vorhergehenden abgezogen. |
61 | sub tmp4,tmp7 |
62 | sbc tmp5,tmp8 |
63 | sbc tmp6,tmp9 |
64 | |
65 | brcc zaehler1_start_stop_10 |
66 | ;Sollte das Ergebnis negativ sein wird noch das Zweierkomplement gebildet. |
67 | clc |
68 | com tmp4 |
69 | com tmp5 |
70 | com tmp6 |
71 | ldi tmp7,1 |
72 | add tmp4,tmp7 |
73 | ldi tmp7,0 |
74 | adc tmp4,tmp7 |
75 | adc tmp5,tmp7 |
76 | |
77 | |
78 | zaehler1_start_stop_10: |
79 | ;Die Differenz des Zählerstanden aktuell zu alt wird abgespeichert. Der ZS ist umgekehrt proportional zur Frequenz |
80 | sts frequenz_nieder_tmp,tmp4 |
81 | sts frequenz_mittel_tmp,tmp5 |
82 | sts frequenz_hoch_tmp,tmp6 |
83 | |
84 | pop tmp9 |
85 | pop tmp8 |
86 | pop tmp7 |
87 | pop tmp6 |
88 | pop tmp5 |
89 | pop tmp4 |
90 | out sreg,tmp4 |
91 | pop tmp4 |
92 | reti |
>exakt 78.652985% Anteil
reicht da ein float normaler Genauigkeit aus?
->
Vielleicht erklärst Du erstmal mit wenigen Worten, wie das Programm
arbeiten soll.
1 | ;Sollte das Ergebnis negativ sein wird noch das Zweierkomplement gebildet. |
2 | clc |
3 | com tmp4 |
4 | com tmp5 |
5 | com tmp6 |
6 | ldi tmp7,1 |
7 | add tmp4,tmp7 |
8 | ldi tmp7,0 |
9 | adc tmp4,tmp7 |
10 | adc tmp5,tmp7 |
Das brauchst du nicht.
Da du unsigned (also nicht vorzeichenbehaftet) rechnest, kannst du die
Werte bedenkenlos einfach voneinander abziehen. Das Ergebnis ist
trotzdem korrekt. Ob die Subtraktion unterläuft oder nicht, interessiert
hier nicht.
> Ist aber nicht so ganz mein Problem.
Doch,
Denn deine 'Spitzen' sind das Symptom, dass irgendwo im Programm etwas
nicht stimmt. Du willst aber das Problem angehen und nicht die Symptome.
Ein weiteres Problem kann dann entstehen, wenn der Input Capture fast
zeitgleich zum Overflow auftritt. Denn dann hängt es von Mykrosekunden
ab, ob der zum Zählerstand gehörende Overflow gezählt wird oder nicht.
Je nachdem ist aber das Ergebnis korrekt oder du hast einen Overflow zu
viel oder zu wenig gerechnet.
:
Bearbeitet durch User
Wenn am Anschluß ICP1 sich der Pegel von Low nach High ändert wird der Programmteil, den ich sinnigerweise "zaehler1_start_stop" genannt habe angesprungen. Dort werden die zwei Zählerbytes und das Byte zaehler1_hoch_temp_temp ausgelesen und für die nächste Unterbrechungsanforderung abgespeichert. Die drei Bytes werden von den, von dem letzten Unterbrechungsanforderung, abgespeicherten Zählerbytes abgezogen. Das Ergebnis ist dann eine Zahl, die im umgekehrten Verhältnis, unter Einbeziehung des Teilers und der akt. Quarzfrequenz, zur gemessenen Frequenz steht.
Karl Heinz schrieb: > Ein weiteres Problem kann dann entstehen, wenn der Input Capture fast > zeitgleich zum Overflow auftritt. Denn dann hängt es von Mykrosekunden > ab, ob der zum Zählerstand gehörende Overflow gezählt wird oder nicht. > Je nachdem ist aber das Ergebnis korrekt oder du hast einen Overflow zu > viel oder zu wenig gerechnet. Das hier schlägt in eine ähnlich Kerbe
1 | ...
|
2 | ;Der aktuelle Zaehlerstand wird in die Register gespeichert |
3 | in tmp4,TCNT1L |
4 | in tmp5,TCNT1H |
5 | ...
|
wenn ich mir den Rest des Codes dazu denke, den du wieder mal nicht gezeigt hast, dann ist das in einer Interrupt Routine, die du an den Input Capture gehängt hast. Dann willst du dir den Zählerstand aber nicht von TCNT1 holen, sondern vom Input Capture Register ICR1. Denn genau dazu ist es da: Tritt eine entsprechende Flanke auf, dann wird der Zählerstand von der Hardware sofort (also ohne Verzögerung) in ICR1 gespeichert. Die Chancen, das dieser Wert dann mit den gezählten Overflows dann auch tatsächlich zusammenpasst steigen dadurch enorm, wenn der Timer gerade von FFFF auf 0000 umspringt, während die Flanke auftritt, bzw. kurz danach.
:
Bearbeitet durch User
anfänger0815 schrieb: > Am besten den Overflow weglassen? Das kommt auf deine zu messenden Frequenzen an. Wenn es sich im dich interessierenden Bereich so ausgeht, dass du nie mehr als 65535 Zählertakte zu verrechnen hast, dann brauchst du den Overflow nicht berücksichtigen. Einfach Zählerstand_am_Ende weniger Zählerstand_am_Anfang rechnen, und es kommt das richtige Ergebnis raus (selbst wenn da ein Overflow dazwischen lag). Nur dürfen zur Zeitbestimmung einer Messperiode nicht mehr als 65535 Timer-Takte anfallen, denn dann muss der erste Overflow entsprechend berücksichtigt werden.
:
Bearbeitet durch User
Bitte verstehe wenn ich den Rest des Codes mit angeben würde, würde ich den Rahmen sprengen. In der Zwischenzeit habe ich in dem Programm 5558 Bytes, sagt der Assembler zumidest, geschrieben. Aber dasmit dem Registern muß ich gleich mal testen.
um nur Dein Symptom zu lösen: Wenn Du oft die richtigen Werte bekommst, und ab und zu einen Schnitzer, dann mach 'best of three'
anfänger0815 schrieb: > Bitte verstehe wenn ich den Rest des Codes mit angeben würde Als Anhang geht das schon. Es gibt hier genug Leute, die sich auch in 400 Zeilen Assembler innerhalb kürzester Zeit zurecht finden.
:
Bearbeitet durch User
Soll jetzt nicht abwertend gemeind gewesen sein. Tschuldigung. Ich dachte wegen der Länge.
Die Sache mit den zwei Registern scheint zu funktionieren. Ich bastel jetzt noch a weng rum und melde mich demnächst wieder. Vielen Dank für die Hilfe.
anfänger0815 schrieb: > Hallo Forum, ich habe einen Frequenzmesser mit dem ATmega programmiert. und Karl Heinz schrieb: > Ich habe eine Vermutung. > Es könnte an deinem Programm liegen. Na klasse. Tolles Vorhaben und dazu passende Antwort vom Mod. Ich lese in diesem Forum immer wieder, daß gerade Atmel-Fans ganz extrem dazu neigen, für solche Vorhaben wie Zählfrequenzmesser irgendwelche Software-Akrobatik mit ihrem ATmega und dessen internen Timern nebst Capture-Registern zu betreiben - OHNE zuvor die Sache gründlich durchdacht zu haben. Man zähle z.B. mal die Anzahl von Firmware-Versionen vom Axel Schwenke zu seinem Projekt. Ja, ja, man kriegt es nach langer Odyssee schon hin, daß es irgendwie zu funktionieren beginnt, aber weil eben diese grandiosen Software-Kunststücke immer wieder sowas wie Sampling-Zeitpunkte, nicht erfaßte Überläufe, Vorrang zwischen verschiedenen Interrupts usw. nicht WIRKLICH berücksichtigen, funktioniert das Produkt eben nur meistens und nicht immer. Der Teufel liegt eben im Detail, das sollten Eleven sich mal gut einprägen. Das Schlimme an all diesen scheinbaren Steilvorlagen ist, daß sie von Neulingen blind nachgebaut werden und selbige sich nie fragen, ob das verwendete Konzept überhaupt tragfähig ist. Stattdessen wird hier gefragt "warum geht es nicht wie erwartet, ich hab doch alles richtig nachgeäfft.." Mein Ratschlag an den TO ist: Mach es anders, spendiere deinem Projekt ein paar IC's mehr - wenn's das Problem vereinfacht, sowas kostet nicht die Welt, aber mach es geradlinig und OHNE Software-Tricks. W.S.
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.