Kann nicht so schwer sein... Gegeben sind zwei Sekundenwerte im Bereich 0 bis 59. Ein Ziel (es geht um AVR Assembler) soll angesprungen werden, wenn die "Zeit" um >= 3 Sekunden abweicht. Ich kämpfe mit dem Overflow, den es ja leider nicht gibt. Wenn nämlich Wert a = 0 und Wert b = 59 ist, darf das Ziel NICHT angesprungen werden, da die Abweichung nur 1 Sekunde ist.... Wie macht man das am elegantesten ohne Multiplikationen (ausser Bitshifts)? [Mod: Threadtitel versinnvollt]
:
Bearbeitet durch Moderator
Beitrag #6934214 wurde von einem Moderator gelöscht.
Das Ergebnis ist alleine aus den Sekundenwerten nicht eindeutig bestimmbar. a = 0, b =59 kann eine Differenz von 1s, 1m1s, 2m1s, 3m1s, ... und ebenso 59s, 1m59s, 2m59, 3m59, ... sein. Ohne Randbedingungen oder besser noch vollständige Zeitinformation ist die Differenz nicht eindeutig und damit kann keine eindeutige Entscheidung getroffen werden ob die Differenz >= 3s ist. Was eine Multiplikation daran ändern soll erschließt sich mit nicht.
So aus dem Groben. Setz'n Flag bei Überlauf und lösche dies wieder bei der Auswertung auf Dif.
Hannes J. schrieb: > Was eine Multiplikation daran ändern soll erschließt sich mit nicht. Mglw. soll die 'Multiplikation' lediglich das Vorzeichen bearbeiten, resp. den Absolutwert bilden. Das kann man aber auch mit Sortierung vor Differenzbildung hinbekommen. Zum subject des Threads würde ich allerdings zu eine Leukotomie oder 'tiefe Hirnstimulation' raten.
Ereignis 1 triggert einen Timer und wenn dieser >3 sec ist wird die Aktion gestartet. Dann kann es keinen Überlauf geben. Oder verstehe ich da etwas falsch ?
Jan schrieb: > Ich kämpfe mit dem Overflow, den es ja leider nicht gibt. Wenn nämlich > Wert a = 0 und Wert b = 59 ist, darf das Ziel NICHT angesprungen werden, > da die Abweichung nur 1 Sekunde ist. Warum soll da nur 1s Abweichung sein? Woran kann man das erkennen? Wer garantiert, dass hier der Unterschied nicht tatsächlich 59 Sekunden sind? Welche Abweichung hast du, wenn ein Zähler auf 10 und der andere auf 50 ist? Ist die Abweichung dann 20s oder 40s oder kann sie auch 1m20s sein? Welche Abweichung hast du, wenn ein Zähler auf 5 und der andere auf 10 ist? Ist die Abweichung dann 5s oder 55s? Oder andersrum: wie stellst du sicher, dass die Abweichung kleiner als 57s bleibt? Denn sobald die Abweichung größer als 57s wird, ist für dich die Abweichung rechnerisch wieder kleiner als 3. Muss man also die Vergangenheit kennen?
Jan schrieb: > Ein Ziel soll angesprungen werden, wenn die > "Zeit" um >= 3 Sekunden abweicht. > Wert a = 0 und Wert b = 59 Dazwischen liegen aus meiner Sicht 59 Sekunden. Das ist >3, als muss das Ziel angesprungen werden. > Ich kämpfe mit dem Overflow... > da die Abweichung nur 1 Sekunde ist Auch das kann richtig sein. Also darf das Ziel nicht angesprungen werden. Oder anders gesagt: Es fehlt eine nötige Information. Rein mathematisch ist dieses "Problem" unlösbar.
Xerxes schrieb: > Oder verstehe ich da etwas falsch ? Der OT hat 2 Variablen! Das Problem hatte ich mal bei einer Tochteruhrsteuerung. Ist-Zeit und Soll-Zeit, die mit Tasten verstellbar war. Habe dann alles in Sekunden gemacht und - um 24 Uhr - wer stellt dann auch die Zeit um...?! Hilft jetzt dem OP nicht so... Sorry. Gruss Chregu
Wenn ich Zeitspannen messe, dann mache ich das normalerweise mit fortlaufenden Counter als 32 oder 64 Bit unsigned Integer:
1 | starte_etwas(); |
2 | start=systick(); |
3 | |
4 | while (noch_nicht_fertig) |
5 | {
|
6 | now=systick(); |
7 | |
8 | if ((now - start) > limit) |
9 | {
|
10 | print("Die maximale Zeit wurde überschritten"); |
11 | }
|
12 | }
|
Selbstverständlich geht das auch in Assembler. Wichtig ist die Subtraktion, denn dann stimmt die Rechnung auch, wenn der Zähler zwischendurch einmal übergelaufen ist. Er darf aber nicht öfter als 1x überlaufen. Dein Zähler muss entsprechend groß genug sein. Du hast geschrieben, dass deine Aktion auch 3m59 (oder mehr) dauern kann. Mit 0..59 Sekunden geht das nicht, weil das mehrere Überläufe ergeben würde.
Hannes J. schrieb: > Was eine Multiplikation daran ändern soll erschließt sich mit nicht. Minute * 60 + Sekunde
(prx) A. K. schrieb: >> Was eine Multiplikation daran ändern soll erschließt sich mit nicht. > Minute * 60 + Sekunde Er hat aber keine Minuten-Info. Genau die fehlt ihm, da kann auch Mathematik nichts zaubern. Außerdem war seine Bedingung: Jan schrieb: > Wie macht man das am elegantesten ohne Multiplikationen?
Jan schrieb: > Ein Ziel (es geht um AVR Assembler) soll angesprungen werden, wenn die > "Zeit" um >= 3 Sekunden abweicht. Jan schrieb: > Wenn nämlich > Wert a = 0 und Wert b = 59 ist, darf das Ziel NICHT angesprungen werden, > da die Abweichung nur 1 Sekunde ist.... Damit kann niemand was anfangen. Was ist "die Zeit"? Du versuchst, den zweiten Schritt (Code) vor dem ersten Schritt (Funktion) zu machen. Du mußt erst die Funktion eindeutig und vollständig beschreiben, dann kann man auch einfach ein Programm daraus machen.
:
Bearbeitet durch User
Jan schrieb: > Ein Ziel (es geht um AVR Assembler) soll angesprungen werden, wenn die > "Zeit" um >= 3 Sekunden abweicht. Erstmal muss klar sein, wie groß die maximale Abweichung sein kann.
Beitrag #6934345 wurde von einem Moderator gelöscht.
Moby schrieb im Beitrag #6934345: >> Erstmal muss klar sein, wie groß die maximale Abweichung sein kann. > Schreibt er doch. 2 Sekunden für den Nicht-Sprung! > Da sie nicht angegeben wurde nehme ich an das die Differenzen unter 1 > Minute liegen. Hannes J. schrieb: > kann eine Differenz von 1s, 1m1s, 2m1s, 3m1s, ... und > ebenso 59s, 1m59s, 2m59, 3m59, ... sein. Dem hat Jan nicht widersprochen. Im Gegenteil, Jan schrieb dass er mit Überläufen nicht klar kommt. Also müssen wir erstmal davon ausgehen, dass Hannes das korrekt erkannt hat. Mit Variablen die nur bis 59 Sekunden gehen kann man nicht Zeitspannen messen, die ein vielfaches davon dauern.
ohne Minuteninformation ist die Zeitangabe nicht vollständig. Du könntest Berechnungen die eine große Differenz ergeben ignorieren oder hart einen Minutenwechsel annehmen. Habs nur in C++
1 | bool check(byte timeA, byte timeB) |
2 | {
|
3 | int diff = 0; |
4 | byte threas = 30; |
5 | if (timeA > timeB) |
6 | {
|
7 | if (timeA - threas > timeB) |
8 | {
|
9 | //nicht eindeutig feststellbar
|
10 | diff = timeA - timeB - 60; |
11 | }
|
12 | else
|
13 | diff = timeA - timeB; |
14 | }
|
15 | else
|
16 | {
|
17 | if (timeB - threas > timeA ) |
18 | {
|
19 | //nicht eindeutig feststellbar
|
20 | diff = timeB - timeA - 60; |
21 | }
|
22 | else
|
23 | diff = timeB - timeA; |
24 | }
|
25 | diff = abs(diff); |
26 | if (diff >= 3) return true; else return false; |
27 | }
|
Öl ins Assembler Feuer: https://wokwi.com/arduino/projects/320116654014988882
Beitrag #6934367 wurde von einem Moderator gelöscht.
Wäre schön wenn der Jan sich bald mal weider dazu meldet. Da er den Thread aus meiner Sicht in der Nacht begonnen hat, liegt er jetzt vielleicht noch im Bett. Wir müssen uns wohl oder übel gedulden.
1 | {
|
2 | int d=t1-t2; |
3 | |
4 | if(d<0) d=-d; // alternativ abs |
5 | if(d>=3 && d<= 57) ... |
6 | |
7 | }
|
Wobei >= 3 Sekunden auch >3 && <57 bzw. >1 && <59 bedeuten kann: 0 und 59 sind halt nicht 1s sondern [0..2]s. 0, wenn die Abfrage im Takt der Umschaltung erfolgt (59er vorher, der 0er nachher), 2 wenn der 0er grad noch nicht und dann der 59 gerade umgesprungen ist. Oder anders ausgedrückt: selbst 2 exakt parallele Timer (0 Abweichung) werden immer wieder mal 1 Differenz haben.
Wenn die Minute kein Rolle spielt: c=MIN(a,b) d=MAX(a,b) Springe wenn d-c>=3 UND c+60-d>=3
Hi Eine relativ einfache Lösung gibt es, wenn die "Fehlermeldung" nicht sofort erfolgen muss, sondern um die angegebenen 2 Sekunden verzögert werden darf. Da bei einem Überlauf die Vergleichszeit ebenfalls max 1 Sekunde später erfolgen muss,setzt man einfach ein kleines Zeitfenster beim Wechsel von 59 nach 0 und sperrt für 2 Sekunden die Auswertung. Gruß oldmax
Moby schrieb im Beitrag #6934367: > Wolfgang schrieb: >> Erstmal muss klar sein, wie groß die maximale Abweichung sein kann. > > Schreibt er doch. 2 Sekunden für den Nicht-Sprung! Schlaumeier - und wie will er erkennen, ob es sich um eine Abweichung von <=2 Sekunden handelt, wenn seine Eingangsvariablen nicht zwischen 1 und 61 unterscheiden können.
Wolfgang schrieb: > wenn seine Eingangsvariablen nicht zwischen 1 und 61 unterscheiden > können. Das ist doch nicht das Thema. Es geht um Sekunden, nicht Zufallszahlen. Bevor es 50s oder gar 60s Differenz werden, hat er wohl schon einige Sprünge mit entsprechenden Maßnahmen ausgeführt.
Beitrag #6934637 wurde von einem Moderator gelöscht.
Ich gehe jetzt mal davon aus, dass die beiden Uhren nicht innerhalb einer Minute so weit auseinander driften. Dann würde ich alle 60 sec testen u.z. um genau n min.30 sec. Hier kann ich dann ((t1 - t2) && 0b01111111) >= 3 testen, ohne das Problem 57, 58, 59, 0, 1, 2 berücksichtigen zu müssen. (t1 und t2 sind int8_t, ...&& 0b01111111 um den Betrag zu erhalten.) Nächster Schritt ist dann zu prüfen, welche Uhr falsch geht (woher soll man das wissen?). Um den Fall zu berücksichtigen, dass einer der Uhren zwischen sec 27 bis 33 stehen bleibt, muss man dann zusätzlich noch andere Dinge überprüfen. Das ist dann aber ein größerer Systemfehler. Gruß
Hi Ist ja toll, wie schnell aus einer einfachen, zugegeben ein kleines extra Schmankerl gibt's, Aufgabe gleich eine Uhr daraus wird. Und wie schnell Sekunden zu Minuten werden. Also bleibt doch Mal auf dem Teppich. So wie sich die Aufgabe stellt, kann die Differenz gar nicht größer 2 Werden,des sei denn, es gibt einen Überlauf eines der Sekundenzähler. Dann aber ist die Differenz auch weit über der 2. Entweder, man zieht in einem solchen Fall noch Mal von der Differenz 60 ab, oder addiert 60, je nach Ergebnis, um die reale Differenz zu erhalten, oder man setzt die Überwachung für die Überlaufproblematik aus. Möglich: Differenz =0, Compare-Befehl Ergebnis gleich Differenz > oder < 0, aber < 2 und >-2, dann keine Aktion Differenz > oder < 2 dann Differenz =Differenz - oder + 60 Entweder, die Differenz befindet sich nun im erlaubten Bereich, oder aber es darf eine Meldung erfolgen. Sollte nun leicht umsetzbar sein Gruß oldmax
Martin V. schrieb: > Sollte nun leicht umsetzbar sein Lösungen gibt es ja oben, die auch in Assembler ~5 Zeilen wären Als Einzeiler in C ging auch:
1 | if( ((t1-t2+117)%60)<=54) ... |
ist nur nicht intuitiv ;-)
achs schrieb: > Als Einzeiler in C ging auch: >
1 | > if( ((t1-t2+117)%60)<=54) ... |
2 | >
|
> ist nur nicht intuitiv ;-)
Und vor allem: Scheisse-langsam. Das sind halt so Sachen, die man in C
nicht sofort beim Eintippen bemerkt, in Asm aber schon...
c-hater schrieb: > Und vor allem: Scheisse-langsam. Wenn der TO ausdrücklich keine Multiplikation will, dann wohl auch keine Division.
Stefan ⛄ F. schrieb: > Wenn der TO ausdrücklich keine Multiplikation will, dann wohl auch keine > Division. Deshalb habe ich ja auch die (bisher) kürzeste Version zuerst geschrieben: A. S. schrieb: > int d=t1-t2; > if(d<0) d=-d; // alternativ abs > if(d>=3 && d<= 57) ...
Ich würde sagen Jan hat uns einfach verarscht. Ebenso peinlich ist wie einige sich Randbedingungen hinzudichten um die Aufgabe zu "lösen", nur um als Programmier-Helden dazustehen.
So, da bin ich wieder. Ja, es wurde gestern sehr spät und ja, ich hatte in der Tat eine Hirnblockade, nämlich zu erkennen, dass das gar kein triviales Problem ist. Deshalb hier mehr Details zum eigentlichen Problem, weil die Aussage, ich habe nur die Sekunden, falsch ist. Ich hatte es damals schon gedanklich kaputtoptimiert. Sorry. :( Zur Vorgeschichte, falls es wen interessiert: Ich entwerfe grad eine Smart-Home Steuerung. Bisher hängen gut 30 Geräte im Bus. Da das ganze über Funk läuft, muss das Teil kryptographisch abgesichert sein. Dazu benötigt man auch einen Schutz vor Replay-Angriffen. Da kann man zwar das challenge-response Verfahren nehmen, aber da ich auch mit Broadcasts arbeite (quasi 1:n Beziehung), kann man das hier nicht nehmen. Deshalb braucht es eine network time. Dazu gibt es dann einen authoritären time_server, der die Pakete via Broadcast ins Netz sendet. Jetzt zum Problem: Die Geräte erhalten in regelmässigen Abständen die Zeit vom time server via Broadcast. Diese Geräte sollen die Zeit aber nur dann übernehmen, wenn die Abweichung lokale<->remote >= 3 Sekunden ist. Warum? Der Jitter beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. Wenn jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde vor- und zurück springen. Das ist unschön und soll vermieden werden. Dazu habe ich eine datetime-Lib programmiert, die die Zeit in eine struct packt. Das sieht so aus:
1 | .section .bss |
2 | RAM_datetime: |
3 | RAM_datetime_second: .space 1 |
4 | RAM_datetime_minute: .space 1 |
5 | RAM_datetime_hour: .space 1 |
6 | RAM_datetime_day: .space 1 |
7 | RAM_datetime_weekday: .space 1 |
8 | RAM_datetime_month: .space 1 |
9 | RAM_datetime_year: .space 1 |
10 | .text |
Wenn also ein Gerät die Zeit erhält, hat es im RAM zu dieser Zeit zwei structs. Einmal die von sich selbst, und einmal die von remote. Es soll dann passieren: IF Abweichung >= 3s then ramcopy remote to myself. In Assembler gibt es keine structs, aber ich denke, dass ist das passenste Synonym. Die RICHTIGE Lösung wäre, jetzt erstmal eine Funktion datetime_to_big_number zu basteln. Das ist aber extrem aufwändig für einen µC und deshalb möchte ich das gerne vermeiden.
Jan schrieb: > Das ist aber extrem aufwändig für > einen µC und deshalb möchte ich das gerne vermeiden. Die Lösung ist hingegen recht einfach: Verschicke die Uhrzeit nur im Fenster zwischen 4 und 56 Sekunden. Dann ist alles gleich und Du kannst die Sekunden vergleichen. Jan schrieb: > Die Geräte erhalten in regelmässigen Abständen die Zeit vom time server > via Broadcast.
Jan schrieb: > Die Geräte erhalten in regelmässigen Abständen die Zeit vom time server > via Broadcast. Diese Geräte sollen die Zeit aber nur dann übernehmen, > wenn die Abweichung lokale<->remote >= 3 Sekunden ist. Warum? Der Jitter > beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. Wenn > jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde vor- > und zurück springen. Das ist unschön und soll vermieden werden. Warum machst du es nicht wie die Bahnhofsuhren? Das funktioniert seit Jahrzehnten. Der Sekundentakt der Slave ist so eingestellt, dass die Uhren etwas zu schnell laufen. Nach dem 59. Sekundenpuls halten sie an und warten auf den Minutensynchronisationsimpuls vom Master. Mit dem Puls springt der Sekundenzähler auf 0 und die Uhr bekommt ihren Minutenpuls.
Falls Du das Zeitfenster nicht steuern kannst: a) Vergleiche vom Jahr runter bis zur ersten Differenz Wenn es nur die Sekunden anders sind, --> vergleichen und ggf. springen Sonst den kleineren in eine dritte Instanz (ggf. auf dem Stack) kopieren, um 3 Sekunden erhöhen und springen, wenn es noch immer kleiner ist. Ich nehme ja an, dass Du für +1Sekunde Operationen hast. Jedenfalls braucht es dann keine Multiplikation.
achs schrieb: > Jan schrieb: >> Das ist aber extrem aufwändig für >> einen µC und deshalb möchte ich das gerne vermeiden. > > Die Lösung ist hingegen recht einfach: Verschicke die Uhrzeit nur im > Fenster zwischen 4 und 56 Sekunden. > > Dann ist alles gleich und Du kannst die Sekunden vergleichen. Auf sowas ähnliches kam ich auch schon. Allerdings so rum, dass ich Pakete ausserhalb dieses Fensters einfach ignoriere. Wäre wohl die einfachste Variante.
Jan schrieb: > Der Jitter beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. > Wenn jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde > vor- und zurück springen. Das ist unschön und soll vermieden werden. Wenn sie aber gleich 3 Sekunden springt, dann ist das schöner? Warum statt der selbsterfundenen 3 Sekunden nicht gleich 5? Dann wäre noch viel länger "kein Vor- und Zurückspringen" zu sehen. Denn das machst du ja mit deinem Programm: du wartest, bis die Abweichung riesig ist und machst dann einen gewaltigen Schritt damit danach wieder lange "Ruhe" ist. Mich würde eine Uhr kirre machen, wenn die zwischendurch selber Sekunden auslässt oder einfügt. In der Praxis macht man das so, dass man eine Uhr hat, die selbständig "auf die Minute" genau macht, und die Sekunden werden innerhalb dieser Minute "gerecht" verteilt und die Geschwindigkeit der Slave-Uhr so der Geschwindigkeit der Master-Uhr ständig nachregelt. So eine Regelung ist allerdings deutlich mehr Aufwand als die Bastelei mit den springenden Sekunden. Jan schrieb: > Wäre wohl die einfachste Variante. Das erscheint mir das Motto für die Software von heute.
:
Bearbeitet durch Moderator
Lothar M. schrieb: >> Der Jitter beträgt 1 Sekunde, da die Zeit nur auf 1s genau übertragen wird. > > Wenn jetzt z.B. eine Uhr die Zeit anzeigt, könnte sie immer um 1 Sekunde >> vor- und zurück springen. Das ist unschön und soll vermieden werden. > Wenn sie aber gleich 3 Sekunden springt, dann ist das schöner? Warum sollte sie da ständig springen? Oder wie lange dauert es, bis ein 08/15 Quarz >2s abweicht! Die Frage (war schon) ist doch, warum "so oft" die Zeit senden, so dass das irgendwie stören könnte?!
@Lothar: Prinzipiell ist die einfachste Variante immer den komplexeren zu bevorzugen, solange sie die gegebene Aufgabe zufriedenstellend erfüllt. Alleine schon aus Gründen der Wartbarkeit. Dann vermischt du hier Jitter und Drift. Das hat miteinander jedoch nichts zu tun. Der Drift liegt bei +-50ppm und der Grund, warum ich bei 3 Sekunden hart springen will ist, dass es woanders noch eine drift compensation gibt, die nochmal anders (und ganz ohne Sprünge) funktioniert. Durch die drift compensation kommt der harte Sprung in der Praxis auch nur dann vor, wenn man den authoritativen Zeitserver hart einstellt. Auch das kommt in der Praxis nicht vor, jedoch geht es hier um eine self-repair Eigenschaft des Systems. Im Fall eines Bugs will man nämlich nicht zig Geräte von Hand resetten gehen.
Die netzweite Systemzeit als runtergebrochenes lokales Datum+Uhrzeit zu verwalten, hat sich nicht bewährt. Jedes Hantieren damit bereitet Probleme, insb wenn auch noch Zeitzonen/Sommerzeitumschaltungen beteiligt sind. Aber, ähnlich wie bei der Wahl der Programmiersprache, muß Jan wohl diese Erfahrung erst selbst machen ;-)
Hallo, vielleicht ist sowas was für Dich ;R16 =A ;R17 =B sub R16, R17 sbrc R16, 7 neg R16 cpi R16, 3 brcs Ende cpi R16, 57 brcc Ende nop ;>3 Ende: nop ;<3 Gruß Carsten
Beitrag #6935045 wurde von einem Moderator gelöscht.
Hi Nun, nach dem Eingangspost bin ich von einer Schulaufgabe ausgegangen. Da strengt man sich an, eine einfach verständliche Lösung anzubieten, dabei weiß der TO genau, was er will und hat die Lösung sogar schon im Kopf. Vorführen nenn ich sowas, aber wenn du es nötig hast... Gruß oldmax
int d = t1-t2; if( d>3 || d<(-3) ) copy(t1,t2);
Danke für die Hilfen und Ideen. Problem ist zufriedenstellend genug gelöst ;)
Beitrag #6935495 wurde von einem Moderator gelöscht.
Martin V. schrieb: > Hi > Nun, nach dem Eingangspost bin ich von einer Schulaufgabe ausgegangen. > Da strengt man sich an, eine einfach verständliche Lösung anzubieten, > dabei weiß der TO genau, was er will und hat die Lösung sogar schon im > Kopf. > Vorführen nenn ich sowas, aber wenn du es nötig hast... > Gruß oldmax Martin, was hast Du anders erwartet? Sind wir nicht alle - irgendwie - schmale, unbedeutende Zampanos? Immer auf der Suche nach der großen Bühne - nach den Brettern, die die Welt bedeuten? In unserer eigenen, kargen, inferioren Welt? Ertrag‘s mit Fassung! Oder mach‘s wie aller anderen auch: Zerrede jeden Ansatz mit einem eigenen, banalen Gegen-Ansatz. Hauptsache Du bist schnell und sagst was, auch wenn Du nichts zu sagen hast. Und falls Du der Meinung bist, Du hättest was zu sagen - formuliere dieses „Was“ unbedingt als Frage. Alois
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.