Forum: Mikrocontroller und Digitale Elektronik [c][arm m0] atoi & strftime: Fehler bei wiederholten ausführen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Johannes G. (jojo_g)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe gerade ein Problem beim Umrechnen einer Unix-Zeit in die 
normale UTC Zeit (dargestellt im BCD Format für eine RTC).

Problem:
Ich führe den selben Code 7 mal aus, um alle Zeit-Formate zu erhalten, 
die ich möchte.
Die ersten 3 mal klappt es perfekt, doch beim 4 mal (manchmal beim 5 
mal) bricht der Debugger ab - er bleibt dann bei der Funktion "atoi", 
selten aber auch bei "strftime" hängen.
Es macht dabei keinen Unterschied welches Format zu erst ausgelesen wird 
(alle durchgetauscht) oder an welche Stelle des uint8_t Array 
geschrieben wird - immer beim 4 mal bricht es ab.
Weiß jemand, woran dies liegen kann?

Unten befindet sich noch der benutze Code und die Erklärung zur 
Umrechnung.
MC: Dialog Semiconductor DA14680 (ARM M0)

Viele Grüße,
Johannes

------------------------------------------------------------------------
Code:

      #include <stdio.h>
      #include <time.h>
      #include <stdlib.h>

      time_t unix_time = 1264343758;
      uint8_t RTC_Puffer_w[7] = {0, 0, 0, 0, 0, 0, 0};
      struct tm * lt;
      char buf_dec[5] = {0, 0, 0, 0, 0} ;
      uint8_t temp_RTC_w = 0;

      //Umrechnung von Unixzeit zu BCD (Binär)////////////////////////

      lt = localtime(&unix_time);

      //Sekunde///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%S", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[0] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w %10) );

      //Minute///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%M", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[1] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w % 10) );

      //Stunde///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%H", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[2] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w % 10) );

      //Tag///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%d", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[3] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w % 10) );

      //Wochentag///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%w", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[4] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w % 10) );

      //Monat///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%m", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[5] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w % 10) );

      //Jahr///////////////////
      temp_RTC_w = 0;
      strftime(buf_dec, 5, "%y", lt);
      temp_RTC_w = atoi(buf_dec);
      RTC_Puffer_w[6] = ( ((temp_RTC_w/10) << 4) | (temp_RTC_w % 10) );

------------------------------------------------------------------------

Vorgehen der Umrechnung:
Mit Hilfe der Funktion "localtime" wird die Unix-Zeit in die übliche UTC 
Zeit umgerechnet und den Struct "lt" gespeichert.
Um daraus das gewünschte Zeitformat zu erhalten, benutzte ich die 
"strftime" Funktion, der ich im dritten Argument angeben kann, welchen 
Wert ich aus dem Struct möchte (z.B. steht "%M" für Minute als 
zweistellige Zahl von 00 bis 59).
Da der gewünschte Zeit Wert-als Char-Array gespeichert wird, muss er 
noch mithilfe von "atoi" in ein Int umgewandelt werden.

Umrechnen in BCD-Zahl (Binär):
Die zweistellige Int Zahl wird durch 10 dividiert um nur die vordere 
Zahl zu erhalten (zweite Zahl steht hinter dem Komma -> fällt weg bei 
Int). Diese wird dann binär um 4 stellen nach links geschoben und bildet 
die vordere BCD Zahl.
Die hintere BCD Zahl erhält man durch Modulo mit 10.

: Bearbeitet durch User
von Felix U. (ubfx)


Bewertung
0 lesenswert
nicht lesenswert
Deinem Code ist nicht zu entnehmen ob deine Variablen lokal oder global 
sind; auch wenn ich nicht glaube dass es relevant ist, weil ich keinen 
Overflow erkennen kann. Prüfe erst mal den Rückgabewert von strftime, 
eventuell geht ja doch bei der Formatierung was schief und atoi kriegt 
dann einen unterminierten String.

von Jim M. (turboj)


Bewertung
0 lesenswert
nicht lesenswert
Spendir dem buf_dec mal ein 6. Byte für die abschleißende \0.

Wieso machst Du das überhaupt so kompliziert und nicht mit sowas wie der 
gmtime() oder gmtime_r() funktion?

von Jim M. (turboj)


Bewertung
1 lesenswert
nicht lesenswert
Jim M. schrieb:
> Wieso machst Du das überhaupt so kompliziert und nicht mit sowas wie der
> gmtime() oder gmtime_r() funktion?

Quatsch. Du kannst doch direkt auf die Member der *lt Struktur 
zugreifen:
1
RTC_Puffer_w[0] = ( ((lt->tm_sec/10) << 4) | (lt->tm_sec %10) );

Übrigens hat das Jahr zuviele Stellen, es wird ab 1900 gezählt: 
lt->tm_year hat derzeit den Wert 117. Das beachtet Dein Code nicht.

: Bearbeitet durch User
von Johannes G. (jojo_g)


Bewertung
0 lesenswert
nicht lesenswert
Jim M. schrieb:
> Quatsch. Du kannst doch direkt auf die Member der *lt Struktur
> zugreifen:
>
>
1
> RTC_Puffer_w[0] = ( ((lt->tm_sec/10) << 4) | (lt->tm_sec %10) );
2
>

Danke Jim!
Da hast du recht, so ist es wirklich sehr viel einfacher und schneller.
Vielen Dank.

Grüße,
Johannes

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]
  • [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.