Forum: Mikrocontroller und Digitale Elektronik STM32 Uhrzeit des RTC Umrechnen


von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Hallo,

Der STM32 liefert eine Uhrzeit als 32-Bit Zähler, der jede Sekunde eine 
Zahl hoch zählt.

Es wurde schon einige male erwähnt, die Umrechnungsroutinen in D.M.Y 
h:n:s und zurück gibt es zu hauf im Netz.
Jetzt hab ich mal danach gesucht weil ich sowas brauche, aber nichts 
gefunden.

Könnt Ihr mir helfen wo ich sowas finden kann?
Oder mir ein Demo Posten?

Vielen Dank im Voraus.

von (prx) A. K. (prx)


Lesenswert?

Für timestamp => DD.MM.YY/HH.MM.DD nach Sourcecode der in C üblichen 
Libfunktionen localtime() oder gmtime() suchen (mal basiert localtime 
auf gmtime, mal ist es andersrum).

Beispielsweise (ggf. auf © achten) 
http://www.raspberryginger.com/jbailey/minix/html/gmtime_8c-source.html

von (prx) A. K. (prx)


Lesenswert?

Für die umgekehrte Richtung siehe mktime(), diesmal aus dem Linux 
Kernel:
http://www.linuxhq.com/kernel/v1.0/0/kernel/mktime.c

Beides sollte man aber auch ganz gut selber zustande kriegen. Jedenfalls 
wenn man sich das Leben nicht mit UTC und Sommerzeit erschwert.

von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Jedenfalls
> wenn man sich das Leben nicht mit UTC und Sommerzeit erschwert.

Sag bloß, Deine Uhren gehen jetzt alle eine Stunde nach.

Was ist denn an Sommerzeit so schwierig?

Beitrag "Berechnung Datum + Uhrzeit + Sommerzeit"


Peter

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:

> Was ist denn an Sommerzeit so schwierig?

Die Politik. Die Definition davon ändert sich ab und zu und dann darfst 
du alle Steuerungen ohne Funkuhr mit neuer Firmware versehen. Vor allem 
wenn das auch international funktionieren soll.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Nein, meine Uhr hab ich schon richtig gerechnet, das tut.
Nur läuft die noch mit dem System-Timer und ich habe heute die Hardware 
umgebaut mit einem Goldcap und einem 32KHz Quarz. Denn bei kurzem 
Stromausfall würde das ja einige Zeit weiter laufen. Ich speichere 
derzeit jede Minutenänderung in das EEPROM und nutze dafür 24 
Speicheradresse. Ist aber eine lästig rechnerei. (20 Jahre würde das gut 
gehen)

Ich habe von ST das AN2821 gefunden, aber die nutzen den RTC Timer nur 
für 86400 Sekunden (1 Tag) der Rest wird als feste Zahl "Manuell" 
gerechnet. Ist nicht ganz das was ich wollte.

@A. K. (prx)
Das ist genau das was ich suchte, vielen Dank!

Sommer/Winterzeit finde ich auch Quatsch. Ich stehe auf, wanns mir 
passt, gehe schlafen wanns mir passt und arbeiten wanns passt 
(Stempeluhr).
(Ich habe auch nie eine Uhr bei mir, ausser der PC ist an.)

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Ich habe mal was zusammen gebastelt, sollte tun:

als FIRSTYEAR kann eine Zahl rein geschrieben werden, wie man mag. Die 
Linux-Berechnung war starr auf 1970, ich musste noch einiges anpassen.
1
#define   FIRSTYEAR  2010
2
3
typedef struct
4
{
5
  u8  Sec;       // Sekunde
6
  u8  Min;       // Minute
7
  u8  Hour;      // Stunde
8
  u8  Day;       // Tag
9
  u8  Month;     // Monat
10
  u16 Year;      // Jahr
11
  u16 YDay;      // Tage im Jahr (0 = 1.1.xxxx)
12
  u8  WDay;      // Wochentag (0 = Montag)
13
  u8  IsLeapYear;// Schaltjahr
14
} time_st;
15
16
////////////////////////////////
17
18
u8 IsLeapYear(u16 year)
19
{
20
  if ((year % 100) == 0)
21
  {
22
    if ((year % 400) == 0)
23
      return 1;
24
    else return 0;
25
  }
26
  if ((year % 4) == 0)
27
    return 1;
28
  return 0;
29
}
30
31
time_st Uhr_GetTime(u32 clockval)
32
{
33
  const u8 _ytab[2][12] = {{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }};
34
  time_st ret;
35
  ret.Sec = clockval % 60;
36
  ret.Min = (clockval % 3600) / 60;
37
  ret.Hour = (clockval % 86400) / 3600;
38
  u32 dayno = clockval / 86400; // Ganzer Tag
39
  ret.WDay = (dayno + 4) % 7;  // Korrektur bis Montag
40
  u32 year = FIRSTYEAR;
41
  while (dayno >= (IsLeapYear(year) ? 366 : 365))
42
  {
43
    dayno -= (IsLeapYear(year) ? 366 : 365);
44
    year++;
45
  }
46
  ret.Year = year;
47
  ret.YDay = dayno;
48
  ret.IsLeapYear = IsLeapYear(year);
49
  ret.Month = 0;
50
  while (dayno >= _ytab[ret.IsLeapYear][ret.Month])
51
  {
52
    dayno -= _ytab[ret.IsLeapYear][ret.Month];
53
    ret.Month++;
54
  }
55
  ret.Month++;
56
  ret.Day = dayno + 1;
57
  return ret;
58
}
59
60
// Errechnet aus Jahr, Monat, Tag, Stunde, Minute, Sekunde die aktuelle Sekunden-Ticks
61
u32 Uhr_GetClock(time_st * timeval)
62
{
63
#define MINUTE 60
64
#define HOUR (60*MINUTE)
65
#define DAY (24*HOUR)
66
#define YEAR (365*DAY)
67
  const u32 month[12] = {
68
     0,
69
     DAY*(31),
70
     DAY*(31+28),
71
     DAY*(31+28+31),
72
     DAY*(31+28+31+30),
73
     DAY*(31+28+31+30+31),
74
     DAY*(31+28+31+30+31+30),
75
     DAY*(31+28+31+30+31+30+31),
76
     DAY*(31+28+31+30+31+30+31+31),
77
     DAY*(31+28+31+30+31+30+31+31+30),
78
     DAY*(31+28+31+30+31+30+31+31+30+31),
79
     DAY*(31+28+31+30+31+30+31+31+30+31+30)
80
  };
81
  u32 res;
82
  u16 year;
83
  res = YEAR * (timeval->Year - FIRSTYEAR);
84
  year = FIRSTYEAR;
85
  while (year < timeval->Year)  // Korrektur Schaltjahre
86
  {
87
    res += (DAY * IsLeapYear(year));
88
    year++;
89
  }
90
  if (timeval->Month > 2)  // aktuelles Jahr ist Schaltjahr
91
    res += (DAY * IsLeapYear(timeval->Year));
92
  res += month[(timeval->Month - 1)];
93
  res += DAY * (timeval->Day - 1);
94
  res += HOUR * timeval->Hour;
95
  res += MINUTE * timeval->Min;
96
  res += timeval->Sec;
97
  return res;
98
}

(Ich weiß, ich hätte auch Code anhängen können, der ist aber nicht sooo 
riesig.)

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Ich glaube die Zeile
"ret.WDay = (dayno + 4) % 7;  // Korrektur bis Montag"
tut nur richtig wenn als Jahr 2010 parametriert ist. Bei einem anderen 
Jahr muss der Offset "4" angepasst werden.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Noch was fehlt:

Sommer-/Winterzeitumschaltung.
Die beiden Funktionen sollten so arbeiten, dass der RTC-Clock immer mit 
der "Normalzeit" == Winterzeit zählt. Aber die Umwandlung in/von 
Tag/Mon/J Stunde usw. sollte automatisch die Zeit korrigieren. Einzige: 
Wenn Sommer auf Winterzeit umschaltet, während 2:00..3:00 ist die 
Wandlung nicht so einfach möglich, da die Routine nicht erkennen kann ob 
Sommer oder Winterzeit gemeint ist.

Vorteil: - Bei Protokollierung wird der Zeitstempel immer als 32-Bit 
Integer mit "Normalzeit" gesetzt. Also auch bei Zeitumschaltung wird der 
Zeitstempel korrekt gesetzt.
- Niemand muss den RTC Counter manipulieren.

Nachteil: Jeder Zeile einer Protokollierung muss für die 
Bildschirmdarstellung gewandelt werden. Aber das ist ja ohnehin egal.

Ich finde das RTC Prinzip von STM32 genial, weil ich nur noch eine 
32-Bit-Variable behandeln muss...

von Karl H. (kbuchegg)


Lesenswert?

Auf welchem Compiler/Rechner bist du genau?

Das hier wird auf den meisten 16 Bit Compilern in die Hose gehen

#define MINUTE 60
#define HOUR (60*MINUTE)
#define DAY (24*HOUR)

     DAY*(31+28+31+30+31+30+31+31+30+31+30)

Nach dem Präprozessor steht da

    24*(60*(60))*(31+28+31+30+31+30+31+31+30+31+30)

Lauter int.
Die Berechnung wird daher als int-Multiplikation gemacht und bei 16-Bit 
int läuft das über.
24*60*60 ergibt bereits 86400, also viel zu viel für einen int.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

WinXP/GCC/Coudesourcery

Die Definition ist "u32". Dies ist in der STM FW-Lib garantiert 32 Bit 
groß.

Dieses Codefragment wurde von "A. K. (prx)" gepostet und existiert 
bereits seit 1993 in den Linux-Sourcen.

Bei mir klappt das richtig, ich habe das getestet bis Dez. 2027. Beide 
Funktionen im Wechsel aufgerufen und die Zahlen bleiben gleich.

von (prx) A. K. (prx)


Lesenswert?

Karl heinz Buchegger schrieb:

> Auf welchem Compiler/Rechner bist du genau?

Der STM32, um den es laut Betreff-Zeile geht, ist ein 32-Bitter. Das 
kann dir eigentlich in den letzten Monaten kaum verborgen geblieben 
sein. ;-)

von (prx) A. K. (prx)


Lesenswert?

Markus Müller schrieb:

> Die Definition ist "u32". Dies ist in der STM FW-Lib garantiert 32 Bit
> groß.

Schon, aber
  u32 var = 1000*1000;
geht bei einem 16-Bit Prozessor trotzdem in die Hose. Weil 1000*1000 
auch auch dann als "int" gerechnet wird, wenn u32 1024 Bit breit sein 
sollte.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Zum Glück mache ich um 8/16-Bitter einen weiten Bogen :)

von Rainer K. (Gast)


Lesenswert?

Hi! Also erst mal danke für die Bereitstellung des Codes, ich versuche 
mich quasi gerade an der selben Thematik. Bin deinen Code mal 
durchgegangen, ich steige aber Teilweise nicht dahinter.

Diese Condition:

if (timeval->Month > 2)  // aktuelles Jahr ist Schaltjahr

Wieso gibt Month > 2 Aufschluß darüber ob es sich beim Datum um ein 
Schaltjahr handelt?

von (prx) A. K. (prx)


Lesenswert?

Tut es nicht. Code/Kommentar-Schere. Es gibt Auskunft, ob es mindestens 
März ist. Für die Korrektur wg. Schaltjahr sorgt die Zeile danach.

von Matthias K. (matthiask)


Lesenswert?

Bei STM gibt es eine gute AppNote zum RTC:
RTC AN2821 Clock/calendar implementation on the STM32F10xxx 
microcontroller
http://www.st.com/mcu/familiesdocs-110.html#Application%20Note

Auch in den EVAL Beispielen findet sich einiges.

von Rainer K. (Gast)


Lesenswert?

@ A.K. Stimmt... ich persönlich würde erst prüfen ob es ein Schaltjahr 
ist und dann ob es März ist, finde ich verständlicher und spart in der 
Mehrheit der fälle einen funktionsaufruf. Aber ja... man sollte den code 
genau lesen bevor man sich hier beschwert. Danke für den Hinweis.

@ Matthis K.
Danke für den Hinweis, ich hatte in der Driver Lib keine direkten 
Funktionen dazu gefunden und bin davon ausgegangen dass es zu dem Thema 
von ST nichts gibt. Das einzige Beispiel, dass in den Lib examples 
enthalten war Rechnet nur mit jeweils einem Tag... Und das bekommt man 
auch noch so hin.

von Peter D. (peda)


Lesenswert?

Markus Müller schrieb:
> Zum Glück mache ich um 8/16-Bitter einen weiten Bogen :)

Das läuft doch prima auf nem 8-Bitter:

Beitrag "Berechnung Datum + Uhrzeit + Sommerzeit"

Mir reicht es, einen 8-Bitter zu 99% zu langweilen, als nen 32-Bitter zu 
99,9%.

Hauptsache, ich muß nicht so viele Beinchen löten und externen Krams 
(Spannungsregler usw.).


Peter

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Evtl. hilfreich: Die von Peter Dannegger und "LalaDumm" im o.g. Thread 
bereitgestellten Codes sind in den RTC-Routinen einer meiner STM32 
Beispielanwendungen enthalten:
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/arm_memcards/index.html#chanfat_stm32

von ARi (Gast)


Lesenswert?

Hallo

beim Ausprobieren des Bsp.-Codes jetzt im Februar hatte ich beim Wandeln 
mit "struct_to_counter" und zurück mit "counter_to_struct" eine 
Differenz von einem Tag. Beim Durchsehen der Quellen ist mir dann ein 
"Verschönerungs"-Fehler aufgefallen.

Ausschnitt aus "struct_to_counter"

/* Make month an array index */
  idx = t->month - 1;

  /* Loop thru each month, adding the days */
  for (i = 0; i < idx; i++) {
    result += DaysInMonth[i];
  }

  /* Leap year? adjust february */
  if (!isLeapYear(year)) {
    if (t->month > 1) {
    result--;
    }
  }

in der Abfrage "if (t->month > 1)" weiterhin den "idx" verwenden, so 
wars vermutlich mal, oder den Wert auf "2"(für Februar) erhöhen.

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
Noch kein Account? Hier anmelden.