Software: RTC DS1302

Die Software für den RTC Chip scheint einfach, da eine bereits vorhandene Bibliothek benutzt werden soll. Allerdings steckt genau da ein handfestes Problem. Die Bibliothek für den DS1302 ist für die Nutzung einer Systemzeit vorgesehen, die ich nicht in meiner Software habe, also brauche ich einen Workaround. Ohne die Systemzeit brauche ich für den RTC nur die zwei Funktionen read() und write().

Der Workaround
Innerhalb der Bibliotheksfunktionen read() und write() werden für die Anpassung an die Systemzeit die Macros

#define tmYearToY2k(Y) ((Y) – 30) // offset is from 2000
#define y2kYearToTm(Y) ((Y) + 30)

benutzt, um das Jahr umzurechnen. Für meinen Zweck brauche ich das nicht. Also muss ich in der Funktion RTCRead() für das Jahr folgendermaßen einlesen:

jahr = (byte)tmYearToY2k(tm.Year);

und in der Funktion RTCWrite() folgendermaßen schreiben:

tm.Year = y2kYearToTm(jahr);

In jahr steht dann der Wert, mit dem ich arbeite. Einen Fehler hat diese Bibliothek damit eingebaut. In Jahren über 69 steht ein Wert im RTC Register, der nicht passt. Denn das Register im RTC DS1302 hat nur einen Bereich von 0 bis 99, siehe Datenblatt.

Ansonsten ist noch zu beachten den Wochentag mit einzulesen und auch wieder wegzuschreiben. Sonst gibt es beim Einlesen immer eine Fehlermeldung, weil er beim Wegschreiben sonst auf 0 gesetzt wird. Gültige Werte für den Wochentag sind 1 = Sonntag bis 7 = Samstag.

Damit sieht die RTC Software so aus:

/****************************************************************************
* Projekt – Messtechnik 1
* (c) 2017 softwareentwicklung-als-prozess.de
* Dokumentation s. Blog
***************************************************************************/

// RTC Pins
// DS1302: CE pin -> Arduino Digital 27
// I/O pin -> Arduino Digital 29
// SCLK pin -> Arduino Digital 31
// GND pin -> Arduino Digital 33
// VCC pin -> Arduino Digital 35
#define DS1302_GND_PIN 33
#define DS1302_VCC_PIN 35

// Init the DS1302
// Set pins: CE, IO,CLK
DS1302RTC RTC(27, 29, 31);

// Funktionen —————————————————————
void setup()
{
DebugPrintInit();
DebugPrint(„Messtechnik1 – Display + Tasten“);

// LCD
lcd.begin(16, 2); // Anzahl Spalten und Zeilen vom Display setzen
lcd.setBacklight(ON); // Beleuchtung einschalten
lcd.clear(); // erstmal alles loeschen
lcd.home(); // Cursor nach links oben
ActualizeDisplay(); // Werte ausgeben

// RTC
RTCActivate(); // RTC aktivieren
RTCCheckStatus(); // RTC Status einlesen
RTCRead(); // RTC einlesen
ActualizeDisplay(); // eingelesene Werte ausgeben
SaveTimeToFallback(); // aktuelle Zeit merken
RTCStart(); // RTC Clock starten

// Sensor Messwerte einlesen
starttime = actualtime = millis(); // Wartezeit starten
DebugPrint(„Setup abgeschlossen“);
}

void loop()
{
uint8_t buttons = (uint8_t)0;

if ((actualtime – starttime) > MINUTE) // Eine Minute ist abgelaufen
{
DebugPrint(„Minute abgelaufen: RTC und Messwerte einlesen“);
RTCRead(); // RTC einlesen
// Messwerte einlesen
CursorBlinkAus(); // Cursor und Blinken aus
ActualizeDisplay(); // Werte ausgeben
buttonpressed = false; // kein Button gedrueckt
starttime = millis(); // Start fuer naechste Minute
RestoreFallbackToTime(); // keine neuen Werte uebernommen
} // Innerhalb der minute
actualtime = millis(); // aktuelle Zeit einlesen
CheckTimeOverrun(); // Ueberlauf von millis() oder Programmfehler
buttons = GetButtons(); // Tasten einlesen
CheckButtons(buttons); // Tasten vorauswerten
if (selectbuttonpressed == true) // Select Taste wurde gedrueckt
{
selectbuttonpressed = false; // Select Taste fertig ausgewertet
RTCWrite(); // RTC mit neuer Zeit setzen
CursorBlinkAus(); // Cursor und Blinken aus
ActualizeDisplay(); // Werte ausgeben
curpos = (byte)CURSORMARGINLEFT; // Cursor auf Startposition
lcd.setCursor(curpos,0); // auf Startposition setzen
}
}

// Software – Ethernet und MQTT ————————————————

// Software – Temperatur- und Luftfeuchte Sensor ——————————-

// Software – RTC ————————————————————–
void RTCActivate(void)
{
digitalWrite(DS1302_GND_PIN, LOW); // GND = 0 Volt
pinMode(DS1302_GND_PIN, OUTPUT);
digitalWrite(DS1302_VCC_PIN, HIGH); // VCC = +5 Volt
pinMode(DS1302_VCC_PIN, OUTPUT);
DebugPrint(„RTC aktiviert“);
delay(500); // Warten auf Chip…
}

void RTCCheckStatus(void)
{
if (RTC.haltRTC()) // Check RTC Clock Oscillator
{
DebugPrint(„RTC Clock steht“);
}
else
DebugPrint(„RTC Clock laeuft“);
if (RTC.writeEN()) // Check RTC Schreibschutz
DebugPrint(„RTC RAM Schreiben erlaubt“);
else
DebugPrint(„RTC RAM Schreibgeschuetzt“);
delay(2000); // Warten auf Chip…
}

void RTCStart(void)
{
RTC.haltRTC((uint8_t)0);
delay(2000);
}

void RTCStop(void)
{
RTC.haltRTC((uint8_t)1);
delay(2000);
}

void RTCSetWriteEnable(void)
{
RTC.writeEN((uint8_t)0);
}

void RTCClearWriteEnable(void)
{
RTC.writeEN((uint8_t)1);
}

void RTCRead(void)
{
tmElements_t tm;
uint8_t ret = (uint8_t)0;

DebugPrint(„RTC Read“);
ret = RTC.read(tm);
delay(2000); // Zeit zum einlesen
if ((uint8_t)0 == ret)
{
DebugPrint(„RTC eingelesen“);
}
else
{
DebugPrint(„RTC Fehler beim Einlesen“);
}
tag = (byte)tm.Day;
monat = (byte)tm.Month;
// tmYearToY2k() wird hier benutzt um die Bibliotheksfunktion zu ueberlisten
// Die Bibliotheksfunktion ist fuer die Verwendung unter Linux geschrieben
// Ein Problem existiert fuer diese Library mit Jahren ueber 69, da intern nur von 0 – 99 funktioniert
jahr = (byte)tmYearToY2k(tm.Year);
stunde = (byte)tm.Hour;
minut = (byte)tm.Minute;
wtag = (byte)tm.Wday;
#ifdef DEBUG
Serial.print(„RTC Tag = „);
Serial.println(tag,DEC);
Serial.print(„RTC Monat = „);
Serial.println(monat,DEC);
Serial.print(„RTC Jahr = „);
Serial.println(jahr,DEC);
Serial.print(„RTC Stunde = „);
Serial.println(stunde,DEC);
Serial.print(„RTC Minute = „);
Serial.println(minut,DEC);
Serial.print(„RTC Wochentag = „);
switch(tm.Wday)
{
case 1:
Serial.println(„Sonntag“);
break;
case 2:
Serial.println(„Montag“);
break;
case 3:
Serial.println(„Dienstag“);
break;
case 4:
Serial.println(„Mittwoch“);
break;
case 5:
Serial.println(„Donnerstag“);
break;
case 6:
Serial.println(„Freitag“);
break;
case 7:
Serial.println(„Samstag“);
break;
}
#endif
}

void RTCWrite(void)
{
tmElements_t tm;
time_t tmp;
uint8_t ret = (uint8_t)0;

tm.Second = (uint8_t)0;
tm.Minute = minut;
tm.Hour = stunde;
tm.Day = tag;
tm.Month = monat;
// Y2kYearToTM() wird hier benutzt um die Bibliotheksfunktion zu ueberlisten
// Die Bibliotheksfunktion ist fuer die Verwendung unter Linux geschrieben
// Ein Problem existiert fuer diese Library mit Jahren ueber 69, da intern nur von 0 – 99 funktioniert
tm.Year = y2kYearToTm(jahr);
tm.Wday = wtag;
ret = RTC.write(tm);
delay(2000);
if((uint8_t)255 == ret)
{
DebugPrint(„RTC Fehler (WP not disabled)“);
}
else
{
DebugPrint(„RTC geschrieben!“);
}
}

Links

Die Systemspezifikation

Datenblatt Real Time Clock DS1302

Klicke, um auf DS1302.pdf zuzugreifen

Die verwendete Bibliothek
http://playground.arduino.cc/Main/DS1302RTC

Veröffentlicht von

Jürgen

Ich bin Software Ingenieur und habe meine Schwerpunkte in allen Aktivitäten, die zur Software Entwicklung gehören. Am längsten bin ich als Software Entwickler von Embedded Software in C tätig.