Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry Pi | Raspberry Pi Pico

Menu
  • Smarthome
  • Arduino
  • ESP32 & Co.
  • Raspberry Pi & Pico
  • Solo Mining
  • Über mich
  • Deutsch
  • English
Menu

Wemos D1 mini Shield: SD Card Shield mit RealTimeClock

Posted on 5. Juli 20187. Juni 2024 by Stefan Draeger

In diesem Tutorial möchte ich das SD Card Shield mit RealTimeClock für den Mikrocontroller Wemos D1 Mini vorstellen.

Auf der Vorderseite des Shields befindet sich der Kartenslot für die SD-Karte. Des Weiteren befindet sich auch hier ein kleiner Text, welcher auf die Pinbelegung hinweist (D1-SCL / D2-SDA).

Wemos D1 Mini - SD Card Shield
Wemos D1 Mini – SD Card Shield
Wemos D1 Mini - SD Card Shield - Unterseite
Wemos D1 Mini – SD Card Shield – Unterseite

Auf der Unterseite des Shield befindet sich die Halterung für eine Knopfzelle.

  • Bezug
  • Aufbau & Schaltung
    • SD Card
    • RTC DS1307
  • Quellcode
    • Beispiel – Daten auf der SD Card speichern
    • Beispiel – RTC DS1307
    • Beispiel – DHT11 Sensordaten mit Zeitstempel loggen

Bezug

Das Shield kann über ebay.de* bestellt werden. Auf amazon.de* gibt es das Shield leider nur  ohne RTC DS1307 Chip (stand 05.07.2018).

Für das Shield wird eine SD Card im Micro SD Card Format benötigt. Für die Beispiele wollte ich eine SD Card mit 16 GB nutzen jedoch wurde diese nicht erkannt somit musste ich auf eine 2 GB Karte wechseln, welche reibungslos erkannt wurde.  Eine 2 GB SD-Karte gibt es Bsp. bei amazon.de* oder ebay.de* für wenig Geld.

Micro SD Card
Micro SD Card

Damit die RTC DS1307 die eingestellte Zeit nach einem Stromausfall behält, kann dieses Shield um eine Batterie im Format CR1220 ergänzt werden. Diese Batterie gibt es im Blister pack auch bei amazon.de* und bei ebay.de*.

Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!

Aufbau & Schaltung

Das SD Card Shield mit RealTimeClock belegt folgende Pins des Wemos D1 Mini:

SD Card

PinFunktion
D5CLK
D6MISO
D7MOSI
D8CS

Quelle: Micro SD Card Shield [WEMOS Electronics]

RTC DS1307

PinFunktion
D1SCL
D2SDA

Somit verbleiben zur freien Programmierung noch weitere 3 digitale Pins und 1 analoger Pin.

Quellcode

Auf der Wikiseite zum original Shield findet man einen Link zu einem GitHub Repository wo diverse Anwendungsfälle mit einem Quellcode (*.ino Datei) hinterlegt wurde.

Ich möchte mich hier auf das lesen und schreiben einer Datei beschränken, da ich dieses für ein paralleles Projekt benötige.

Beispiel – Daten auf der SD Card speichern

#include <SD.h>

#define CS D8

void setup() {
    Serial.begin(9600);
    
    // CS-Pin als Ausgang konfigurieren
    pinMode(CS, OUTPUT);

    // SD-Karte initialisieren
    Serial.print("\r\nInitialisiere SD-Karte...");
    if (!SD.begin(CS)) {
        Serial.println(" fehlgeschlagen!");
        // Setup-Funktion verlassen
        return;
    }
    Serial.println(" fertig.");

    //Versucht die Datei "text.txt" zu im Modus FILE_WRITE zu öffnen.
    //Es gibt noch den Modus FILE_READ für nur lese Zugriff.
    //Wenn kein Modus angegeben wurde dann wird die Datei immer im FILE_READ Modus geöffnet.
    //Wenn die Datei "text.txt" nicht gefunden wurde dann wird diese erzeugt.
    File target = SD.open("text.txt", FILE_WRITE);

    //Wenn das File existiert dann....
    if (target) {
        Serial.print("Datei 'text.txt' gefunden.");
        //Eine neue Zeile an die Datei anhängen. 
        //Diese Zeile wird an das Ende der Datei angehängt.
        target.println("Test, Test. 1, 2, 3.");
        //Nach dem Schreiben nicht vergessen den Zugriff
        //auf die Datei zu schließen.
        target.close();
    }
    else {
        //Wenn die Datei nicht geöffnet werden kann, dann soll eine Fehlermeldung
        //ausgegeben werden.
        //Ein möglicher Fehler kann sein dass, die Datei bereits durch einen anderen 
        //Service geöffnet wurde.
        Serial.println("Fehler beim Öffnen von text.txt.");
    }
}

void loop() {
    /* Bleibt in diesem Beispiel leer. */
}

Beispiel – RTC DS1307

Das Shield verfügt wie schon erwähnt über eine RealTimeClock DS1307. Die RTC DS1307 habe ich bereits im Tutorial Arduino Lektion 27: Daten loggen mit dem Logging Shield behandelt.

#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68

/*
 * Array mit den Wochentagbezeichnungen.
 * Die erste Stelle ist 0 da die Wochentage bei 1 für Sonntag beginnen.  
 * Hier hätte man im Quellcode an der passenden Stelle auch den Zähler 
 * um 1 verringern können jedoch wird darunter die lesbarkeit leiden.
 */
String daysOfWeek[8] = {"","Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"};

//Konvertiert eine normale Dezimalzahl zu einer binärcodierten Dezimalzahl.
byte decToBcd(byte val){
  return( (val/10*16) + (val%10) );
}

//Konvertiert Binärcodierte Dezimalzahl zu einer
//normalen Dezimalzahl.
byte bcdToDec(byte val){
  return( (val/16*10) + (val%16) );
}

void setup(){
  Wire.begin();
  Serial.begin(9600);
  /*
   * Um die Uhrzeit & das Datum initial zu setzen, muss die
   * nachfolgende Zeile auskommentiert werden.
   * 
   * Parameter der Funktion 
   * setDS1307 - Sekunden, Minuten, Stunden, Tag der Woche, Tag im Monat, Monat, Jahr
   * Der "Tag der Woche" ist im Englischen Format d.h. Sonntag = 1, Montag = 2 usw.
   * Der Wert für das Jahr wird im 2 stelligen Bereich eingegeben, 
   * dieser Code ist also noch für ca. 82 Jahre funktionsfähig. 
   */
  //setDS1307(00,21,8,6,6,7,18);
}

void setDS1307(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year){
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(second)); // setzt die Sekunden
  Wire.write(decToBcd(minute)); // setzt die Minuten
  Wire.write(decToBcd(hour)); // setzt die Stunden
  Wire.write(decToBcd(dayOfWeek)); // setzt den Wert für den Tag der Woche
  Wire.write(decToBcd(dayOfMonth)); // setzt den Wert für den Tag im Monat
  Wire.write(decToBcd(month)); // setzt den Monat
  Wire.write(decToBcd(year)); // setzt das Jahr
  Wire.endTransmission();
}
void readDS1307time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year){
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  //Anfordern der ersten 7 Datenbyte  vom DS1307
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime(){
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

  //Ausgeben des Zeitstempels auf dem seriellen Ausgang.
  Serial.print(daysOfWeek[dayOfWeek]);
  Serial.print(" ");
  Serial.print(dayOfMonth, DEC);
  Serial.print(".");
  Serial.print(month, DEC);
  Serial.print(".");
  Serial.print(year, DEC);
  Serial.print(" ");
  Serial.print(hour<10?"0":"");
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute<10?"0":"");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second<10?"0":"");
  Serial.print(second, DEC);
  Serial.println(" ");
}
void loop(){
  displayTime(); 
  delay(1000); //kleine Pause von 1 Sekunde
}

Beispiel – DHT11 Sensordaten mit Zeitstempel loggen

Da die Shields für den Wemos D1 mini untereinander kompatibel und vor allem Stapelbar sind möchte ich nun ein kleines Beispiel mit dem DHT11 Shield und dem SD Card Shield zeigen. Zusätzlich werde ich hier die RTC DS1307 welche auf Shield verbaut wurde verwenden, um einen Zeitstempel zu speichern.

Für dieses Beispiel verwende ich:

  • Dual Base Shield,
  • Datalogging Shield,
  • DHT11 Shield,
  • Wemos D1 mini
Wemos D1 Mini mit Datalogging Shield und DHT11 Shield
Wemos D1 Mini mit Datalogging Shield und DHT11 Shield
#include <SD.h>
#include "Wire.h"
#include "DHT.h" //DHT Bibliothek

//Pin an welchem der DHT11 Sensor angeschlossen ist.
//Beim DHT11 Shield ist es der digitale Pin D4.
#define DHTPIN D4 
 
//Festlegen welcher Typ von DHT Sensor verwendet wird.
#define DHTTYPE DHT11
 
//Initialisieren des Sensors mit dem Anschluss und dem Typ
DHT dht(DHTPIN, DHTTYPE);

#define CS D8

#define DS1307_I2C_ADDRESS 0x68

String daysOfWeek[8] = {"","Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"};

//Konvertiert eine normale Dezimalzahl zu einer binärcodierten Dezimalzahl.
byte decToBcd(byte val){
  return( (val/10*16) + (val%10) );
}

//Konvertiert Binärcodierte Dezimalzahl zu einer
//normalen Dezimalzahl.
byte bcdToDec(byte val){
  return( (val/16*10) + (val%16) );
}

void setup(){
  Wire.begin();
  Serial.begin(9600);
  pinMode(CS, OUTPUT);
  
  dht.begin(); //DHT Kommunikation beginnen.
 if (!SD.begin(CS)) {
        Serial.println("Verbindung zur SD Card fehlgeschlagen!");
        // Setup-Funktion verlassen
        return;
  }  

  setDS1307(00,41,11,6,6,7,18);
}

void storeData(String timestamp, float luftfeuchtigkeit, float temperaturC, float temperaturF){
  String csvRow = getFormatedRow(timestamp, luftfeuchtigkeit, temperaturC, temperaturF,"","",";");
  writeToFile(csvRow, "data.csv");
  //String htmlTableRow = getFormatedRow(timestamp, luftfeuchtigkeit, temperaturC, temperaturF,"<tr><td>","</td></tr>","</td><td>");
  //writeToFile(csvRow, "htmldata.html");
}

String getFormatedRow(String timestamp, float luftfeuchtigkeit, float temperaturC, float temperaturF, String first, String last, String separator){
  String row = first;
  row += timestamp;
  row += separator;
  row += luftfeuchtigkeit;
  row += separator;
  row += temperaturC;
  row += separator;
  row += temperaturF;
  row += last;
  return row;
}

void writeToFile(String data, String filename){
 File dataFile = SD.open("data.csv", FILE_WRITE);
   Serial.println(data);
   if (dataFile) {
        dataFile.println(data);
        dataFile.close();
    }else {
          Serial.print("Fehler beim öffnen der Datei [");
          Serial.println(filename);
          Serial.println("]");         
    }
}

void setDS1307(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year){
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(second)); // setzt die Sekunden
  Wire.write(decToBcd(minute)); // setzt die Minuten
  Wire.write(decToBcd(hour)); // setzt die Stunden
  Wire.write(decToBcd(dayOfWeek)); // setzt den Wert für den Tag der Woche
  Wire.write(decToBcd(dayOfMonth)); // setzt den Wert für den Tag im Monat
  Wire.write(decToBcd(month)); // setzt den Monat
  Wire.write(decToBcd(year)); // setzt das Jahr
  Wire.endTransmission();
}

void readDS1307time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year){
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  //Anfordern der ersten 7 Datenbyte  vom DS1307
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

String getTimestamp(){
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  
  String timestamp = "";
  
  //Ausgeben des Zeitstempels auf dem seriellen Ausgang.
  timestamp += daysOfWeek[dayOfWeek];
  timestamp +=" ";
  timestamp += String(dayOfMonth, DEC);
  timestamp += ".";
  timestamp += String(month, DEC);
  timestamp += ".";
  timestamp += String(year, DEC);
  timestamp += " ";
  timestamp += (hour<10?"0":"");
  timestamp += String(hour, DEC);
  timestamp += ":";
  timestamp += (minute<10?"0":"");
  timestamp += String(minute, DEC);
  timestamp += ":";
  timestamp += (second<10?"0":"");
  timestamp += String(second, DEC);
  return timestamp;
}

void loop(){
 String timestamp = getTimestamp(); 
  delay(2000);
 
  float luftfeuchtigkeit = dht.readHumidity();
  float temperaturC = dht.readTemperature();
  float temperaturF = dht.readTemperature(true);
 
  //Prüfen ob die Werte des DHT11 Sensors erfolgreich gelesen wurden.
  if (isnan(luftfeuchtigkeit) || isnan(temperaturC) || isnan(temperaturF)) {
    Serial.println("Fehler beim lesen von Daten.");
    return;
  }
   
  storeData(timestamp, luftfeuchtigkeit, temperaturC, temperaturF);
  delay(2500);
}

3 thoughts on “Wemos D1 mini Shield: SD Card Shield mit RealTimeClock”

  1. Thomas Igerst sagt:
    16. August 2018 um 12:46 Uhr

    Hallo Stefan,

    sehr schöner Sketch, den ich auch als Einsteiger gut nachvollziehen kann.
    Bei den Definitionen am Anfang verwendest du keine „RTClib.h“ Lib, sondern sprichst die RTC direkt über die Adresse an (#define DS1307_I2C_ADDRESS 0x68). Wie kann bei dem Sketch das Logfile mit einem Timestamp als Dateiname erzeugt werden?

    Mit besten Grüßen
    Thomas

    Antworten
  2. Arved Lompe sagt:
    3. Dezember 2020 um 13:59 Uhr

    Wer Probleme mit diesem Modulen hat sollte das mal prüfen:

    Bei den gängigen Modulen dieser Bauart funktioniert die Pufferung der Datum-/Zeiteinstellung nicht. Sie funktionieren, solange sie mit 5V über Vcc versorgt werden. Bei Unterbrechung der Stromzufuhr und nach dem Wiederanschließen starten sie wieder mit Sonntag 1.1.2000.
    Auf der Platine gibt es eine Kombination aus Widerstand (2MOhm) und Diode, die Vbat auf definiertes Potential ziehen soll, wenn keine Batterie eingelegt ist (siehe Datenblatt DS1307).
    Die Diode ist bei den gängigen China-Modulen (DS1307 + SD-Kartenslot, auch bei dem aus Ihrer Abbildung) verkehrt herum eingebaut!!! Bei Modulen ohne SD-Karte ist sie allerdings richtig eingebaut.

    Ich hab’s kaum glauben können, aber es ist so. Die Batterie entlädt sich. Bei der ersten Batterie, die ich eingelegt habe, habe ich im Laufe der Untersuchungen nur noch 1,9V gemessen. Ok, die Batterie war nicht neu und lag schon eine Weile herum. Daraufhin habe ich eine neue gekauft und eingelegt.
    Es funktionierte wieder nicht. Batterie entnommen und Spannung gemessen: 2,7V, das bei einer neu gekauften Batterie mit 3V Nennspannung??
    Im Internet habe ich dann einen Hinweis gefunden, daß die besagte Diode defekt sein könne (https://sharedinventions.com/?p=663). Daraufhin habe ich mir das Modul angeschaut und mit einem funktionierenden (ohne SD-Karte!) verglichen und festgestellt, daß die Diode verkehrt herum eingelötet ist.

    Diode (und Widerstand) entfernt, da ich das Modul nicht ohne Batterie betreiben will. Alles ok, funktioniert so wie es soll!
    Alle Module dieser Bauart bei Ebay haben laut Photo diesen Fehler (Photos mit Gammaverschiebung aufhellen dann sieht man die Leiterbahnen).

    Antworten
    1. JL sagt:
      18. März 2025 um 20:45 Uhr

      Das mit der verkehrt herum eingebauten Diode kann ich bei einem aktuell über Ebay gekauften China-Modul bestätigen. Hat mich auch einige Zeit gekostet bis ich drauf gekommen bin.

      Antworten

Schreibe einen Kommentar Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Fragen oder Feedback?

Du hast eine Idee, brauchst Hilfe oder möchtest Feedback loswerden?
Support-Ticket erstellen

Newsletter abonnieren

Bleib auf dem Laufenden: Erhalte regelmäßig Updates zu neuen Projekten, Tutorials und Tipps rund um Arduino, ESP32 und mehr – direkt in dein Postfach.

Jetzt Newsletter abonnieren

Unterstütze meinen Blog

Wenn dir meine Inhalte gefallen, freue ich mich über deine Unterstützung auf Tipeee.
So hilfst du mit, den Blog am Leben zu halten und neue Beiträge zu ermöglichen.

draeger-it.blog auf Tipeee unterstützen

Vielen Dank für deinen Support!
– Stefan Draeger

Kategorien

Tools

  • Unix-Zeitstempel-Rechner
  • ASCII Tabelle
  • Spannung, Strom, Widerstand und Leistung berechnen
  • Widerstandsrechner
  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator

Links

Blogverzeichnis Bloggerei.de TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com

Stefan Draeger
Königsberger Str. 13
38364 Schöningen

Tel.: 01778501273
E-Mail: info@draeger-it.blog

Folge mir auf

  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Cookie-Richtlinie (EU)
©2025 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb
Cookie-Zustimmung verwalten
Wir verwenden Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wir tun dies, um das Surferlebnis zu verbessern und um personalisierte Werbung anzuzeigen. Wenn Sie diesen Technologien zustimmen, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn Sie Ihre Zustimmung nicht erteilen oder zurückziehen, können bestimmte Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Verwalten von {vendor_count}-Lieferanten Lese mehr über diese Zwecke
Einstellungen anzeigen
{title} {title} {title}