mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Uhrzeit - Denkfehler oder Datentyp?


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, Leute!

Ein kleines Problem plagt mich seit zwei Tagen: Man stelle sich vor, ich 
hätte ein IC, das ich um Mitternacht mit Spannung versorge und ab dann 
jede sekunde ein internes Register von Null an um eins erhöht. Jetzt sei 
es zwei Uhr mittags und ich lese das Register mal aus und habe somit die 
Zahl der vergangenen Sekunden (Das Ding sendet 4 Bytes mit LSByte first 
- muss also die 4 Einzelbytes noch "zusammenkleben".). Mit ein bisschen 
Rumrechnen lässt sich doch jetzt sagen, wie spät es ist. Und das soll 
ein AVR programmiert in GCC tun. Er tut es auch. Allerdings läuft 
irgendwas schief bei manchen Uhrzeiten. Der Fehler müsste so um 17:00 
rum auftreten. Ich hab mal ein Codesnippet angehängt und wäre dankbar, 
wenn Ihr mal drüberschauen könntet...

Die Kommunikation ist übrigens okay, d.h., die empfangenen Variablen 
entsprechen den Registerinhalten in der RTC.


uint8_t erstesbyte  = empfangen();   //LS Byte empfangen
uint8_t zweitesbyte = empfangen();   //..
uint8_t drittesbyte = empfangen();   //..
uint8_t viertesbyte = empfangen();   //MS Byte empfangen

uint32_t sekunden;      // 
sekunden = viertesbyte;      //  
sekunden = (sekunden<<8)+drittesbyte;  // hier sollen die 4 bytes zu
sekunden = (sekunden<<8)+zweitesbyte;  // einer 4-bt-integer zusammen
sekunden = (sekunden<<8)+erstesbyte;  // gefasst werden

uint8_t hh = sekunden/3600;    // hier sollen die vergangenen
uint8_t mm = (sekunden-(hh*3600))/60  // sekunden in die aktuelle 
uint8_t ss = sekunden-(hh*3600)-(mm*60)  // uhrzeit umgerechnet werden.
          // Bezugspunkt sei 00:00:00 uhr



Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ungefähr 17:00? Nicht vielleicht 18:12:16? (18*3600+12*60+16 == 65536) 
-- riecht nach einem Überlauf.
Außerdem wird dir der Modulo-Operator (%) sehr weiterhelfen.
Ich würde deine Berechnung ein bisschen umstellen:
/* Prototyp */
uint8_t empfangen(void);    //Besser einen sprechnederen Namen nehmen
                            // sowas wie get_rtc_byte oder so
uint32_t sekunden;
uint_8 t hh, mm, sec;

/* WENN empfangen() genau ein Byte liefert: */
sekunden = empfangen();                //LS Byte empfangen
sekunden |= (uint32_t)empfangen()<<8;  //..
sekunden |= (uint32_t)empfangen()<<16; //..
sekunden |= (uint32_t)empfangen()<<24; //MS Byte empfangen

hh = sekunden/3600;
sekunden %= 3600 ;      // Rest
mm = (sekunden)/60;
sec = sekunden % 60;

hth. Jörg

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich Depp... Natürlich "|" statt "+"... Okay, das ist besser, 
funktioniert aber immer noch nicht wirklich. Scheint wohl etwas mit der 
Bereichsüberschreitung zu tun zu haben. Muss irgendwie rauskriegen, wie 
ich aus den 4 einzelnen Bytes, eine 4-Byte-var machte, die der AVR 
arithmetisch beackern kann. Wenn ich Deinen Code mal übertrage, bekomme 
ich jensets von 00:04:15 (das sind 255 (!) sekunden) sozusagen einen 
"Neustart" der Uhr. Aber besten Dank schonmal für den oder-hint!

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das geht schon nach 9 Stunden in die Hose, weil
> (hh*3600))
als "int" berechnet wird und damit bei 32767 Schluss ist.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:
> Ich Depp... Natürlich "|" statt "+"...

Das ist in dem Fall völlig Wurscht.

Entscheidend ist, dass bei
  (uint32_t)empfangen()<<8

das uint8_t Ergebnis von empfangen() zuerst mal auf 32 Bit
aufgeblasen wird, bevor es nach links verschoben wird.


> Okay, das ist besser,
> funktioniert aber immer noch nicht wirklich.#

Zeig noch mal deinen jetzigen Code

Autor: Roland Praml (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein kleiner Tipp: Sowas mach ich immer im Simulator in dem ich mir ein 
entsprechendes Code-snippet zusammenbastle.

Gruß
Roland

Autor: Roland Praml (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
man könnte hier auch gut mit einer union-struct arbeiten:
union
{
  uint8_t b[4];  // 4  Bytes
  uint32_t i;     // belegen den sellben Speicher wie i
} u;

unsignet cnt;

for (cnt = 0; cnt < 4; cnt++) u.b[cnt] = empfangen(); // 4x empfangen

hh = u.i / 3600;
...
(untested)

Gruß
Roland

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okiedo... Hier noch mal der aktuelle Code, der bei 255 sekunden "schlapp 
macht". Danach sagt die Uhr wieder 0:00:00 und fängt von vorne an.
uint8_t ow_rtc_1st=~(_1w_receivebyte());
uint8_t ow_rtc_2nd=~(_1w_receivebyte());
uint8_t ow_rtc_3rd=~(_1w_receivebyte());
uint8_t ow_rtc_4th=~(_1w_receivebyte());


  uint32_t seconds=ow_rtc_4th;      //MSB
  seconds=(seconds>>8)|ow_rtc_3rd;
  seconds=(seconds>>8)|ow_rtc_2nd;
  seconds=(seconds>>8)|ow_rtc_1st;    //LSB
  
  
  uint8_t hh = seconds/3600;
  seconds%=3600 ;      // Rest
  uint8_t mm = seconds/60;
  uint8_t ss = seconds%60;



Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:
>   seconds=(seconds>>8)|ow_rtc_3rd;

Der Unterschied zwischen Links und Rechts ist dir klar?

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du solltest lieber nach links schieben

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich schieb ich auch nach links, hab nur in meiner Verzweiflung 
das mal mit rechts durchgetestet und vergessen, es wieder zu ändern. In 
Echtigkeit schieb ich nach links.

uint8_t ow_rtc_1st=~(_1w_receivebyte());
  uint8_t ow_rtc_2nd=~(_1w_receivebyte());
  uint8_t ow_rtc_3rd=~(_1w_receivebyte());
  uint8_t ow_rtc_4th=~(_1w_receivebyte());
  _1w_detectpresence();

  uint32_t seconds=ow_rtc_4th;      //MSB
  seconds=(seconds<<8)|ow_rtc_3rd;
  seconds=(seconds<<8)|ow_rtc_2nd;
  seconds=(seconds<<8)|ow_rtc_1st;    //LSB
  
  
  uint8_t hh = seconds/3600;
  seconds%=3600 ;      // Rest
  uint8_t mm = seconds/60;
  uint8_t ss = seconds%60;



Autor: Helmi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann es sein das du hier alle bits invertierts (~) ?

uint8_t ow_rtc_1st=~(_1w_receivebyte());
  uint8_t ow_rtc_2nd=~(_1w_receivebyte());
  uint8_t ow_rtc_3rd=~(_1w_receivebyte());
  uint8_t ow_rtc_4th=~(_1w_receivebyte());

versuch es doch mal so

  uint8_t ow_rtc_1st=(_1w_receivebyte());
  uint8_t ow_rtc_2nd=(_1w_receivebyte());
  uint8_t ow_rtc_3rd=(_1w_receivebyte());
  uint8_t ow_rtc_4th=(_1w_receivebyte());


Gruss Helmi

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, ich invertiere alle Bits, aber das ist Absicht. Wie gesagt, an der 
Kommunikation hängts nicht, sondern eher an der "Zusammenführung" oder 
Berechnung...

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die Berechnung ist meiner Meinung nach richtig, also

entweder es kommen andere Daten als du erwartest,
oder die Ausgabe der Ergebnisse ist falsch!

Wie ist denn das genaue Verhalten der Zeitanzeige?

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist das Bei-255-Sekunden-Schlapp-Mach-Problem immer noch da, oder lag
das nur an der verkehrten Schieberichtung? In meinen Augen scheint die
Umrechnung der Sekunden in hh, mm und ss korrekt zu sein.

Ein möglicher Fehler liegt aber im Einlesen der 4 Bytes: Hast du
sichergestellt, dass sich die Werte während des Einlesens nicht
ändern? Bspw. dadurch, dass du die 4 Bytes auf Hardwareseite latchst?
Sonst kann (und wird) es hin und wieder passieren, dass der
Sekundenwechsel genau während des Einlesens der Bytes stattfindet.
Die gelesenen Werte sind dann falsch.

Kontrollieren kannst du dies, indem du die 4 Bytes ein zweites Mal
einliest. Haben sie den gleichen Wert wie beim ersten Mal, sind die
Werte ok. Wenn nicht, hast du einen Sekundensprung erwischt. Die Werte
müssen dann korrigiert oder - und das ist die sicherere Methode - ein
drittes Mal eingelesen werden.

Autor: helmi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann gibt die Daten doch einmal einzeln aus also ow_rtc_1st .. 
ow_rtc_4st und dann die zusammenfassung seconds

wenn in z.B. in ow_rtc_1st = 0x12
                ow_rtc_2st = 0x34
                ow_rtc_3st = 0x56
                ow_rtc_4st = 0x78

dann muss in Seconds = 0x78563412 sein

wenn das dann gleich ist müsste die zusammenfassung ok sein

Gruss helmi

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.