Hallo,
ich habe an einem ATMEGA1284 einen Drehgeber per HCTL2016 angeschlossen,
der die Position mit 16 Bit zählt, den Istwert lese ich in den ersten
Zeilen in ra_val ein. Da kommt an, was erwartet wird.
Eine volle Umdrehung der Achse liefert 12000 Inkremente, die sollen auf
0 … 24h umgerechnet werden (Stundenachse am Teleskop). In positiver
Zählrichtung kein Problem, in negativer muss ich einen Offset verrechen,
weil 2 hoch 16 / 12000 nicht ohne Rest aufgeht. Das funktioniert auch.
Dass die Berechnung nur innerhalb von reichlich ±2 Umdrehungen richtig
funktioniert, ist mir klar, da ich soweit gar nicht komme, stört das
nicht.
Ich habe die Zeile unten gekennzeichnet, welche falsch rechnet …
übersehe ich da irgendwas? Ich hab aus der Vermutung heraus, dass eine
interne Umwandlung stattfindet, zur Kontrolle mit / ohne Vorzeichen
ausgeben lassen, da kommen die gleichen Werte raus.
Die Ausgaben auf UART0 sind nur zur Fehlersuche drin. Ich habe dort
jeweils die erwarteten bzw. falschen Werte im Kommentar vermerkt.
encoder_resolution wird mit 12000 aufgerufen, kommt auch richtig an. Ich
habe die deklaration der Encoderauflösung versuchsweise auf uint32_t
geändert - ist wirkungslos. cli() am Anfang und sei() am Ende der
Funktion bringt auch nichts. Hat jemand eine Idee?
Grüße
tg
tg schrieb:> Eine volle Umdrehung der Achse liefert 12000 Inkremente, die sollen auf> 0 … 24h umgerechnet werden (Stundenachse am Teleskop). In positiver> Zählrichtung kein Problem, in negativer muss ich einen Offset verrechen,> weil 2 hoch 16 / 12000 nicht ohne Rest aufgeht.
Häh? Wenn das in positiver Richtung geht, muss es auch in negativer
Richtung gehen. Wenn irgendwelche Teilbarkeiten tatsächlich eine Rolle
spielen würden, täten sie das in beiden Richtungen gleichermaßen. Das
kann man sogar wissen, ohne Programmieren zu können, dazu braucht man
einfach nur bis zur vierten Klasse in Mathe mitgehalten zu haben...
Kurzfassung: du hast keine Ahnung von dem, was du da tust. Lerne.
tg schrieb:> In positiver Zählrichtung kein Problem, [...]
Tatsächlich?
Das Teleskop läuft genau 5 Tage lang vorwärts; dann
steht der Zähler auf 5*12000 = 60'000. Was passiert
im Verlaufe des sechsten Tages?
Ich werfe mal %d in den Raum...
Du verwendest eine 8 Bit CPU ein int ist nur 16 Bit groß. Das gibt
natürlich Probleme wenn du printf auf einmal eine 32bit Zahl vorwirfst.
Thomas
Oliver S. schrieb:> Auch wenn es wie üblich grenzwertig deutlich formuliert ist, hat c-hater> im Prinzip wohl recht.>> Der Wurm steckt nicht im Modulo-Operator.
So ist es. Aber wollen wir ihn mal nicht völlig dumm sterben lassen...
@tg (Gast):
Der Trick ist einfach: zyklische Sachverhalte (nämlich z.B. die
Erdumdrehung bzw. unsere 24h-Abbildung selbiger) auch eben als Zyklus zu
sehen und so im Code umzusetzen.
Du kannst das an zwei Stellen tun. Sinnvoller wird sein, es zu tun,
bevor du die Schritte in deine Funktion einfüllst. Allerdings musst du
dann ggf. einen zusätzlichen Parameter mitschleppen, nämlich einen
Tages-Offset. Nötig wird das, wenn du im Endergebnis nicht nur die
Uhrzeit sehen willst (die es ja jeden Tag gleichermassen gibt), sondern
tatsächlich eine konkrete, eindeutige Zeit.
Egon D. schrieb:> tg schrieb:>>> In positiver Zählrichtung kein Problem, [...]>> Tatsächlich?>> Das Teleskop läuft genau 5 Tage lang vorwärts; dann> steht der Zähler auf 5*12000 = 60'000. Was passiert> im Verlaufe des sechsten Tages?
Das Teleskop soll sich ja nicht tagelang kontinuierlich drehen. Schon um
die Kabel nicht aufzuwickeln, wird das immer wieder zurückgedreht, so
dass ich sicher in dem Limit von ±2 richtig verarbeiteten Umdrehungen
bleibe.
Thomas Z. schrieb:> Ich werfe mal %d in den Raum...> Du verwendest eine 8 Bit CPU ein int ist nur 16 Bit groß. Das gibt> natürlich Probleme wenn du printf auf einmal eine 32bit Zahl vorwirfst.
Vielleicht musst du beim AVR "%ld" schreiben. Wenn du alle Warnungen vom
Compiler einschaltest (-Wall) sollte er sich ggf. dazu melden.
Allerdings: 11753 würde in einen 16bit Integer noch rein passen.
tg schrieb:> Egon D. schrieb:>> tg schrieb:>>>>> In positiver Zählrichtung kein Problem, [...]>>>> Tatsächlich?>>>> Das Teleskop läuft genau 5 Tage lang vorwärts; dann>> steht der Zähler auf 5*12000 = 60'000. Was passiert>> im Verlaufe des sechsten Tages?>> Das Teleskop soll sich ja nicht tagelang kontinuierlich> drehen.
Herrgott. Beantworte doch einfach meine Frage.
Stefanus F. schrieb:> tg schrieb:>> sollte 11753 raus kommen>> Tut es bei mir auch.
Naja, hatte ich auch erwartet ;-)
Ich hab ja die kompletten Berechnungen, die da mal laufen sollen, in
einer Tabellenkalkulation parallel als "normale" Berechnung und in
Ganzzahlarithmetik vorbereitet, da funktioniert auch alles.
Ich hatte wie gesagt die Hoffnung, das jemand was auffällt, was ich
konstant übersehe, z.B. hinsichtlich Deklarationen, implizite Casts
usw., was den Effekt verursacht. Am Modulo-Operator hab ich eigentlich
keine Zweifel.
Danke dir!
Grüße
tg
tg schrieb:> Ich hatte wie gesagt die Hoffnung, das jemand was> auffällt, was ich konstant übersehe, [...]
Ist ja auch geschehen -- aber die Leute ignorierst
Du ja.
Nun gut.
tg schrieb:> übersehe ich da irgendwas?> Die Modulo-Berechnung ergibt in C grundsätzlich nur mit positiven> Werten sinnvolle Ergebnisse. Wenn der zweite Operand negativ ist,> so wird dieses Vorzeichen von C schlichtweg ignoriert. Wenn der erste> Operand negativ ist, so wird die Berechnung ausgeführt, als ob der> Operand positiv wäre und schlussendlich dem Resultat das Vorzeichen> wieder angehängt.http://manderc.com/operators/modoperator/index.php
Man muß also für Fälle, in denen ein negatives Verzeichen vorkommt, eine
Sonderbehandlung einbauen.
MfG Klaus
Müsste man, spielt aber beim TO keine Rolle.
Ansonsten scheint die Aufgabe zu sein, den Wertebereich 0-12000 auf den
Bereich 0-24 abzubilden. Sollte machbar sein ;)
Oliver
Klaus schrieb:> Man muß also für Fälle, in denen ein negatives Verzeichen vorkommt, eine> Sonderbehandlung einbauen.
Die tatsächlich auftretenden Werte schließen aus, dass die nicht
funktionierende Modulo-Operation eine negative Zahl zu sehen bekommt.
Ich habe trotzdem mal
1
if(ra_val<0)
2
uart0_puts(" <0 ");
davor gesetzt - es wird keine Meldung ausgegeben, wenn danach falsche
Werte berechnet werden. Ein impliziter Cast findet also offensichtlich
nicht statt.
Ich habe inzwischen auch unterschiedliche Optimierungseinstellungen
getestet .. macht keinen Unterschied beim Ergebnis. Es ist nach wie vor
diese Zeile
1
ra_val=ra_val%encoder_resolution;
die nicht mitspielt. Wenn ich die Auflösung "hart" eintrage, stimmt das
Ergebnis ebenfalls nicht:
1
ra_val=ra_val%12000;
Beide Fällen führen z.B. zu 59980 % 12000 = 5740. Wenn ich aber die
59980 fest eintrage
1
ra_val=59980%encoder_resolution;
kommen wie zu erwarten 11980 raus. Bei vorangegangenen Tests wurden mir
die Werte von ra_val korrekt angezeigt, irgendwas geht daneben, wenn
diese Zeile losarbeitet ...
Grüße
tg
Oliver S. schrieb:> Ansonsten scheint die Aufgabe zu sein, den Wertebereich 0-12000 auf den> Bereich 0-24 abzubilden. Sollte machbar sein ;)
Ja, das geht gerade noch so ;-). Ich hab das oben vielleicht etwas
unklar beschrieben.
Pro kompletter Umdrehung der Achse bekomme ich 12000 Inkremente. Die
werden von einem 16bit-Zähler-IC erfasst. Der zählt also in die eine
Richtung 0, 1, ... 12000 (nach einer Umdrehung), 24000 (2. Umdr.) ...
36000 ... usw.
In die andere Richtung zählt der 0, 65535, .. 53535 (1. Umdr.) ... usw.
Je nachdem, wie herum ich drehe, bekomme ich also für den gleichen
Winkel unterschiedliche Zählerstände. Deshalb wird die zuletzt genannte
drehrichtung per Offset so korrigiert, dass der Wert richtungsunabhängig
den Winkel eindeutig abbildet (nach der letzten Modulo-12000-Operation).
Mit einem umfangsbegrenzten Ringzähler hätte ich's einfacher, aber da an
dem Controller noch 2 Stepper, 2 Drehgeber und mehrere I²C-Teile (incl.
Display) hängen, wollte ich mir keine Timingproblem einhandeln.
Fehler würden bei meiner Berechnung erst entstehen, wenn ich 2^16 / 2
überschreite, d.h, mehr als ca. 2,7 Umdrehungen in eine Richtung mache.
Das kann ich aber ausschließen.
Aber wie gesagt, das ist alles nicht das Problem .. das besteht "nur"
darin, die Ursache für die eine falsch rechnende Zeile zu finden.
Grüße
Thilo
tg schrieb:> In die andere Richtung zählt der 0, 65535, .. 53535 (1. Umdr.) ... usw.> Je nachdem, wie herum ich drehe, bekomme ich also für den gleichen> Winkel unterschiedliche Zählerstände.
Je nun, eigentlich bekommst du 0, -1, -2, usw. (bei positiver und
negativer Drehrichtung ist ein signed integer ganz passend), was durch
Addition von 12000 bei negativen Werten dann dazu führt, daß du doch
die selben Werte für eine Winkelstellung erhältst, unabhängig von der
Drehrichtung.
Oliver
Thomas Z. schrieb:> Was passiert bei>> ra_val = ra_val % 12000L;>> Stimmt dann der Wert?
Nein, bleibt falsch. Ich hatte die Deklaration für encoder_resolution
schon versuchsweise auf uint32_t geändert, ebenfalls ohne Erfolg.
Ich versuchs morgen mal mit dem Vorschlag von Oliver, scheint so, als
könnte man damit die Modulo-Rechnerei ganz vermeiden ... ich melde mich
wieder.
tg
Dein Fehler ist, daß 65536 (uint16_t) nicht ohne Rest durch 12000
teilbar ist.
Bilde daher die Differenz zu einer Variable, die Du nachführst, sobald
der Wert außerhalb 0..11999 ist.
Differenzen stimmen immer, auch über einen Überlauf hinweg.
Ich würde gar nicht versuchen direkt auf der 16 Bit Variable des Zählers
zu arbeiten. Stattdessen würde ich mir in der MCU den letzten 16 Bit
Zählerstand merken.
Mit der Differenz des aktuellen Stand lässts sich das problemlos auf
jede beliebige Darstellung, also auch zyklisch mit 12000 Schritten
abbilden. Und zwar ganz ohne Modulo. (Ist vermutlich sogar schneller)
ra_val=(ra_enc*(uint32_t)86400)/encoder_resolution;//auf 24h umskaliert in Sekunden
22
23
returnra_val;
24
}
Funktioniert wie geplant. Die Unterscheidung zwischen positiven und
negativen Zählerständen habe ich mir gespart, da ja die kopfgesteuerten
Schleifen eigentlich die selbe Funktion erfüllen, d.h., satt if oder
else wird hier nur die zutreffende while-Schleife abgearbeitet. Ich
nehem mal an, dass in der Bearbeitungszeit kein relevanter Unterschied
besteht.
Ich danke euch nochmal für eure Mühe und Vorschläge!
Grüße
Thilo