Forum: Mikrocontroller und Digitale Elektronik STM23F10x battery powered RTC reset


von kremsy (Gast)


Lesenswert?

Hallo Leute,

Habe ein STM32F10x Discovery Board mit einer Battery für die dauernde 
fortsetzung der echtzeituhr.

Wie im Beispiel wird so die Zeit bei 25.00 (0Uhr) zureückgesetzt:
1
      /* Reset RTC Counter when Time is 23:59:59 */
2
      if (RTC_GetCounter() == 0x0001517F)
3
      {
4
         RTC_SetCounter(0x0);
5
         /* Wait until last write operation on RTC registers has finished */
6
         RTC_WaitForLastTask();
7
      }

Aber es wird nicht zurückgesetzt während es Batteriebetrieben ist, gibt 
es eine möglichkeit dass das auch zurückgesetzt wird während das system 
im Batterie betrieb läuft?

mfg kremsy

von holger (Gast)


Lesenswert?

>Aber es wird nicht zurückgesetzt während es Batteriebetrieben ist, gibt
>es eine möglichkeit dass das auch zurückgesetzt wird während das system
>im Batterie betrieb läuft?

Wenn wer im Batteriebetrieb läuft? Nur die RTC?
Dann geht das nicht.

von kremsy (Gast)


Lesenswert?

Will einfach dass wenn jetzt 24h Poweroff is die zeit noch stimmt.

Kann man zum Beispiel den Zählwert beim wechsel in den batterymode 
sichern oder sowas?

von holger (Gast)


Lesenswert?

>Will einfach dass wenn jetzt 24h Poweroff is die zeit noch stimmt.

Das tut sie. Die RTC zählt einfach nur weiter als einen Tag.
Wenn du sie ausliest und nur eine 24h Anzeige willst dann machst du
halt:

      time = RTC_GetCounter() % 86400;

von kremsy (Gast)


Lesenswert?

time = RTC_GetCounter() % 86400; kann nicht ganz stimmen.

bsp. 80000%86400=80000

Sinnvoller wäre RTC_GetCounter()/3600 % 86400; das stimmt aber auch nur 
für die ersten 24h.

Man bräuchte irgenteine formel um von RTC_GetCounter() ein vielfaches 
der stunden in 24 rauszubekommen.

von kremsy (Gast)


Lesenswert?

Ah habs verstanden, stunden sind einfach (RTC_GetCounter()%86400)/3600 
;).

von Matthias K. (matthiask)


Lesenswert?

Ich habe es damals so gelöst wie in dem Programmsnip. Man bekommt damit 
die Anzahl der Tage raus, wo der RTC lief und kann auch gleich noch ein 
Datum mitführen. Das ist jedoch nur ein Programmauszug als Denkanstoß. 
Für Datum kommt man an der Nutzung der BKP Register nicht herum.
1
#define RTC_SEKUNDEN_TAG 86400      /* Sekunden pro Tag */
2
3
// ***********************************************************************
4
// RTC Datumskorrektur nach Netzausfall
5
// ***********************************************************************
6
void rtc_datumskorrektur (void) {
7
uint16_t tage;
8
9
  zeit.counter_temp = RTC_GetCounter();   // RTC Sekundenzähler
10
 
11
  if ((zeit.counter_temp / RTC_SEKUNDEN_TAG) != 0) {
12
    // Mindestens 1 Datumsübertrag
13
    for(tage = 0; tage < (zeit.counter_temp / RTC_SEKUNDEN_TAG); tage++) {
14
      rtc_inc_datum(); // Datum um einen Tag erhöhen
15
    }
16
    RTC_SetCounter(zeit.counter_temp % RTC_SEKUNDEN_TAG);
17
  }
18
}
19
20
...
21
22
// ***********************************************************************
23
// RTC Datum um einen Tag erhöhen
24
// Überträge auf Monat und Jahr
25
// Schaltjahr (4-Jahresregel Regel) wird beachtet
26
// ***********************************************************************
27
void rtc_inc_datum(void) {
28
uint8_t temp_tage;
29
30
  // Wochentag aktualisieren
31
  if (zeit.wo_tag < 6) {
32
    // Wochentag erhöhen
33
    zeit.wo_tag++;
34
  } else {
35
    zeit.wo_tag = 0;
36
  }
37
38
  // Anzahl der Tage des Monats
39
  switch (zeit.monat) {
40
    case  2: // Monat Februar mit 28 Tagen ggf. mit Schaltjahr 29
41
             temp_tage = 28;
42
             // Schaltjahr Prüfung
43
             if (!(zeit.jahr % 4)) {
44
               // Schaltjahr (nur 4-Jahres-Zyklus Regel beachtet)
45
               // 400/100 Regel erst wieder im Jahr 2100 von Bedeutung!!!
46
               temp_tage = 29;
47
             }
48
             break;
49
    case  4: // Monate mit 30 Tagen
50
    case  6:
51
    case  9:
52
    case 11: // April, Juni, September, November
53
             temp_tage = 30;
54
             break;
55
    default: // Monate mit 31 Tagen (alle nicht mit case ausselektierten!)
56
             // Januar, März, Mai, Juli, August, Oktober, Dezember
57
             temp_tage = 31;
58
  }
59
60
  // Datum aktualisieren
61
  if (zeit.tag < temp_tage) {
62
    // Tag erhöhen
63
    zeit.tag++;
64
  } else {
65
    // neuer Monat
66
    zeit.tag = 1; // Tag = 1
67
    if (zeit.monat < 12) {
68
      // Monat erhöhen
69
      zeit.monat++;
70
    } else {
71
      // neues Jahr
72
      zeit.monat = 1;
73
      zeit.jahr++;
74
    }
75
  }
76
}

von kremsy (Gast)


Lesenswert?

1
void RTC_Cyclic_1Sec(void)
2
{
3
    char res[2];
4
    uint32_t time;
5
    time = RTC_GetCounter() % 86400;
6
      /* Reset RTC Counter when Time is 23:59:59 */
7
     // if (RTC_GetCounter() == 0x0001517F)
8
      if (time == 0 && RTC_GetCounter()!=0)
9
      {
10
         RTC_SetCounter(0x0);
11
         /* Wait until last write operation on RTC registers has finished */
12
         RTC_WaitForLastTask();
13
      }
14
    if(TimeDisplay==1)
15
    {
16
      lcd_setcursor(2,2);  
17
      UTIL_uint2str(res, (time / 3600) , 2, 0 );  //hour
18
      lcd_string(res);
19
      LCD_Data(':');
20
      UTIL_uint2str(res, (time / 3600) / 60, 2, 1 );  //min
21
      lcd_string(res);
22
      LCD_Data(':');
23
      UTIL_uint2str(res, (time / 3600) % 60, 2, 1 ); //sec
24
      lcd_string(res);
25
      TimeDisplay=0;
26
    }
27
}

liefter 0:0:0 am display seit ich das mit der time so gemacht habe.

Jemand ne ahnung was falsch ist?

von kremsy (Gast)


Lesenswert?

Danke matthias für deinen tollen Denkanstoß, werds mir bei gelegenheit 
näher anschaun. das BKP register nutze ich sowiso schon, von daher kein 
Problem.

Aber versteh grad net wo mein Denkfehler im aktuellen code liegt.

von kremsy (Gast)


Lesenswert?

Ah wahrscheinlich brauchts nur nen typcast.

von kremsy (Gast)


Lesenswert?

1
void RTC_Cyclic_1Sec(void)
2
{
3
    char res[2];
4
      /* Reset RTC Counter when Time is 23:59:59 */
5
      if (RTC_GetCounter() == 0x0001517F)
6
      {
7
         RTC_SetCounter(0x0);
8
         /* Wait until last write operation on RTC registers has finished */
9
         RTC_WaitForLastTask();
10
      }
11
    if(TimeDisplay==1)
12
    {
13
      lcd_setcursor(2,2);  
14
      UTIL_uint2str(res, (RTC_GetCounter() %86400) , 2, 0 );  //hour
15
      lcd_string(res);
16
      LCD_Data(':');
17
      UTIL_uint2str(res, (RTC_GetCounter() %3600) / 60, 2, 1 );  //min
18
      lcd_string(res);
19
      LCD_Data(':');
20
      UTIL_uint2str(res, (RTC_GetCounter() %3600) % 60, 2, 1 ); //sec
21
      lcd_string(res);
22
      TimeDisplay=0;
23
    }
24
}
25
26
Wohl zuviel geändert ;)
27
28
Neue code der funktionieren sollte:
29
void RTC_Cyclic_1Sec(void)
30
{
31
    char res[2];
32
     uint32_t time;
33
      time = RTC_GetCounter() % 86400;
34
        /* Reset RTC Counter when Time is 23:59:59 */
35
       // if (RTC_GetCounter() == 0x0001517F)
36
        if (time == 0 && RTC_GetCounter()!=0)
37
        {
38
           RTC_SetCounter(0x0);
39
           /* Wait until last write operation on RTC registers has finished */
40
           RTC_WaitForLastTask();
41
        }
42
    if(TimeDisplay==1)
43
    {
44
      lcd_setcursor(2,2);  
45
      UTIL_uint2str(res, (time /3600) , 2, 0 );  //hour
46
      lcd_string(res);
47
      LCD_Data(':');
48
      UTIL_uint2str(res, (time %3600) / 60, 2, 1 );  //min
49
      lcd_string(res);
50
      LCD_Data(':');
51
      UTIL_uint2str(res, (time %3600) % 60, 2, 1 ); //sec
52
      lcd_string(res);
53
      TimeDisplay=0;
54
    }
55
}

von Matthias K. (matthiask)


Lesenswert?

Klappt es nun?

Ich mache die Zeit- und Datumaufbereitung generell im Interrupt 
(RTC_IRQHandler) und stelle es alles in einer Struktur dem Hauptprogramm 
zur Verfügung. Dort erfolgt auch die Anzeige auf LCD oder TFT.

etwas so:
1
//***********************************************************************************************
2
// RTC Interrupt-Handler
3
// Laufzeiten: 5us / Sekunde (100us für kompletten Jahreswechsel)
4
// bei 72MHz
5
//***********************************************************************************************
6
void RTC_IRQHandler (void) {
7
unsigned char temp_tage;
8
9
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET) {
10
    // RTC neue Sekunde
11
    RTC_ClearITPendingBit(RTC_IT_SEC);      // Sekunden-Interrupft-Flag löschen
12
    RTC_WaitForLastTask();                  // auf RTC-Bereitschaft warten
13
14
    zeit.counter_temp = RTC_GetCounter();   // RTC Sekundenzähler
15
    RTC_WaitForLastTask();
16
17
    // Prüfung auf Datumswechsel (24:00:00)
18
    if (zeit.counter_temp == RTC_SEKUNDEN_TAG) {
19
      RTC_SetCounter(0x1);                  // RTC Sekundenzähler zurücksetzen
20
      RTC_WaitForLastTask();
21
      zeit.counter_temp = 0;
22
23
      // Wochentag aktualisieren
24
      if (zeit.wo_tag < 6) {
25
        // Wochentag erhöhen
26
        zeit.wo_tag++;
27
      } else {
28
        zeit.wo_tag = 0;
29
      }
30
31
      // Anzahl der Tage des Monats
32
      switch (zeit.monat) {
33
        case  2: // Monat Februar mit 28 Tagen ggf. mit Schaltjahr 29
34
                 temp_tage = 28;
35
                 // Schaltjahr Prüfung
36
                 if (!(zeit.jahr % 4)) {
37
                   // Schaltjahr (nur 4-Jahres-Zyklus Regel beachtet)
38
                   // 400/100 Regel erst wieder im Jahr 2100 von Bedeutung!!!
39
                   temp_tage = 29;
40
                 }
41
                 break;
42
        case  4: // Monate mit 30 Tagen
43
        case  6:
44
        case  9:
45
        case 11: // April, Juni, September, November
46
                 temp_tage = 30;
47
                 break;
48
        default: // Monate mit 31 Tagen (alle nicht mit case ausselektierten!)
49
                 // Januar, März, Mai, Juli, August, Oktober, Dezember
50
                 temp_tage = 31;
51
      }
52
53
      // Datum aktualisieren
54
      if (zeit.tag < temp_tage) {
55
        // Tag erhöhen
56
        zeit.tag++;
57
      } else {
58
        // neuer Monat
59
        zeit.tag = 1; // Tag = 1
60
        if (zeit.monat < 12) {
61
          // Monat erhöhen
62
          zeit.monat++;
63
        } else {
64
          // neues Jahr
65
          zeit.monat = 1;
66
          zeit.jahr++;
67
        }
68
      }
69
    }
70
71
    // Uhrzeit aktualisieren
72
    zeit.stunde  = zeit.counter_temp / 3600;
73
    zeit.minute  = (zeit.counter_temp % 3600) / 60;
74
    zeit.sekunde = (zeit.counter_temp % 3600) % 60;
75
76
    // Backupregister aktualisieren
77
    BKP_WriteBackupRegister(BKP_DR2, zeit.tag);
78
    BKP_WriteBackupRegister(BKP_DR3, zeit.monat);
79
    BKP_WriteBackupRegister(BKP_DR4, zeit.jahr);
80
    BKP_WriteBackupRegister(BKP_DR5, zeit.wo_tag);
81
    BKP_WriteBackupRegister(BKP_DR6, zeit.mesz);
82
83
    // Meldung an das Hauptprogramm, dass neue Zeit vorhanden ist.
84
    zeit.update = 1;
85
  }
86
}
87
88
.....
89
90
// Systemzeit-Struktur
91
struct zeit_struc {
92
  volatile uint32_t counter_temp;   // RTC-Counter (Snap)
93
  volatile uint16_t jahr;           // Jahr 4 stellen
94
  volatile uint8_t  monat;          // Monat 1-12
95
  volatile uint8_t  tag;            // Tag 1-31
96
  volatile uint8_t  stunde;         // 0-23
97
  volatile uint8_t  minute;         // 0-59
98
  volatile uint8_t  sekunde;        // 0-59
99
  volatile uint8_t  wo_tag;         // 0-6
100
  volatile uint8_t  mesz;           // Sommerzeit 1=MESZ(Sommerzeit) 0=MEZ(Winter)
101
  volatile uint8_t  update;         // 1=Neue Sekunde
102
  volatile uint8_t  set;            // 1=Uhrzeit stellen
103
};
104
struct zeit_struc zeit;      // Systemzeit Variablen

von kremsy (Gast)


Lesenswert?

Jap klappt alles, wenn ich Zeit habe werde ich es vielleicht auch so 
Umsetzen wie du ;).

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.