STM32 Uhrzeit des RTC Umrechnen

OP (Firma: EleLa - www.elela.de) #1653269
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.
OP (Firma: EleLa - www.elela.de) #1653317
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.)
OP (Firma: EleLa - www.elela.de) #1653426
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.)
OP (Firma: EleLa - www.elela.de) #1654651
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...
#1654663
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.
OP (Firma: EleLa - www.elela.de) #1654690
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.
#1654723
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.
Gast #1805602
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?
Gast #1805669
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.
Gast #4907089
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren