// // ************************************************************************************* // *** komplett ueberarbeitete Version. *** // *** ACHTUNG: Original-Code stimmte nicht mit Librarie ueberein. DEC = Dezimal *** // *** *** // *** Aufgabe: *** // *** Temperatur-Messung, Luftfeuchte *** // *** Luftdruckmessung, in Verbindung *** // *** der Echtzeit, auf SD-Karte speichern *** // *** Stand: V3 -Interval-Speicherung - 13.03.2016 *** // ************************ DL2EBZ ***************************************************** // *** Anschluesse: // *** DHT22 -Pin = D9 // *** DS3231-SDA = A4 // *** -SCL = A5 // *** BMP085-SDA = A4 // *** -SCL = A5 // *** SD-Card mit Zugriff auf den SPI-Bus // *** MOSI - pin 11 / 51 // *** MISO - pin 12 / 50 // *** CLK - pin 13 / 52 // *** CS - pin 4 / 53, bzw. SS // ************************************************ // *** offene Punkte: // *** a) SD-Karte einbinden --> OK, 02.03.2016 // *** b) Speicher-Zyklus einstellen --> OK, 12.03.2016 // *** c) Wenn-Dann-Auswahl beim Tages-Datum instand setzen --> OK, 13.03.2016 // *** d) Zeit= jede Sekunde, Sensorik= alle 30 Sekunden, Speichern= alle 10 Minuten // *** ===> allerdings nur ein einziges Mal !!!! Nicht eine ganze Minute lang jede Sekunde --> OK, 13.03.2016 // *** // *** e) Temperatur auch vom DS3231 auslesen (muss ueber die Kontrolle der vorhandenen I2C-Devices aufzufinden sein) // *** f) ... auch in Fahrenheit --> f = c*9. / 5. + 32 // *** g) Monats-Namen ausgeben (muss eine vorhandene Funktion in der TIME.h sein) --> monthShortStr(now.month()) --> OK, 02.03.2016 // *** h) Moeglichkeit einer Zeit-Korrektur schaffen --> 19.01.2016 // *** i) SD-Card einbinden --> schreiben, auslesen, sowie löschen // *** j) Darstellung einer Balkengrafik für Barometer-Verlauf // *** // *** DHT22 OK, BMP085 OK, DS3231 OK, SD-Kartenleser OK // *** // *** SA und SU bezogen auf Standort berechnen // *** MA und MU bezogen auf Standort berechnen // *** Tiedenkalender für z.B. Borkum berechnen // *** Kompass-Kurs für Sonnenuntergang berechnen // *** // ************************************************ // #include // Hier wird die Library des DS1307 genutzt !! #include // #include // I2C-Bibliothek einbinden #include "RTClib.h" // RTC-Bibliothek einbinden #include #include // SD-Karte einbinden RTC_DS1307 RTC; // RTC Modul #include // LCD-Bibliothek einbinden #include "DHT.h" // DHT-Bibliothek #include // BMP085-Bibliothek #define DHTPIN 9 #define DHTTYPE DHT22 //DHT11, DHT21, DHT22 // LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Auswahl der Anschluesse fuer das 2x 16-LCD-Paneel LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // Auswahl der Anschluesse fuer das 4x 20-LCD-Paneel DHT dht(DHTPIN, DHTTYPE); // Temp-Feuchte-Sensor Adafruit_BMP085 bmp; // Luftdruck-Sensor // *** fuer SD-Karte File dataFile; // diese Variable soll spaeter die Daten aufnehmen String dataString = ""; // fuer die Aufnahme sämtlicher Sensor-Daten #define SD_CS 53 // CS = Chip Select / beim UNO Pin 10 File logDat; // diese Variable 'logDat' im Format 'File' nimmt spaeter den Dateinamen und die Befehle auf int go = 0; // SD-Schreib-Freigabe float h; // Luftfeuchte DHT22 float t; // Temperatur DHT22 float t2; // Temperatur BMP085 float Druck; // Baro BMP085 // *********************************************************************************************************** // *************************** S E T U P ********************************************************************* void setup() { Serial.begin(9600); // Serielle Ausgabe starten Wire.begin(); // Initialisiere I2C RTC.begin(); // Initialisiere RTC // lcd.begin(16, 2); // Start der Bibliothek 2x 16 lcd.begin(20, 4); // Start der Bibliothek 4x 20 // **** Pruefen ob RTC läuft ************* if (! RTC.isrunning()) { DateTime now = RTC.now(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { Serial.println("RTC ist aelter als das Compile-Datum ! Updaten !"); RTC.adjust(DateTime(__DATE__, __TIME__)); // Hier wird die RTC auf die Zeit gesetzt, zu der dieser Sketch kompiliert wurde Serial.println("Starte Datum und Zeit"); // Anfangstext auf seriellem Monitor und LCD ausgeben } else Serial.println("Echtzeituhr laeuft bereits und ist aktuell."); } dht.begin(); // Start des Temp-Sensors lcd.clear(); // Leert die Display-Zeilen // **** Pruefen ob BMP085 laeuft ************* Serial.begin(9600); if (!bmp.begin()) { Serial.println("Kein BMP085 gefunden ... I2C Adresse und Verkabelung pruefen !"); while (1) {} } // ******* SD-Karte einbinden und pruefen ************ while (!Serial) { // Hier wird gewartet bis der 'Serielle Monitor' gestartet wurde } Serial.print("Initialisiere SD-Card... "); // Zugriffs-Versuch auf die SD-Karte pinMode (53, OUTPUT); // fuer MEGA2560 // pinMode (10, OUTPUT); // fuer UNO R3 if (!SD.begin(SD_CS)) // Alternative: if (!SD.begin(4)) { Serial.println(" SD-Fehler !"); return; } Serial.println("SD-OK!"); Serial.println(); } // Setup // **** Wochentag ermitteln **** Das muss ausserhalb von SETUP oder LOOP passieren ! **** String get_day_of_week(uint8_t dow) { String dows = " "; switch (dow) { case 0: dows = "Sonntag"; break; case 1: dows = " Montag"; break; case 2: dows = "Diensta"; break; case 3: dows = "Mittwoc"; break; case 4: dows = "Donners"; break; case 5: dows = "Freitag"; break; case 6: dows = "Samstag"; break; } return dows; } // *********************************************************************************************************** // **************** L O O P ****************************************************************************** long currentTime = millis(); // http://www.vielsichtig.de/index.php?id=120 void loop() { DateTime now = RTC.now(); Serial.print(now.year(), DEC); Serial.print('/'); Serial.print(now.month(), DEC); Serial.print('/'); Serial.print(now.day(), DEC); Serial.print(' '); Serial.print(now.hour(), DEC); Serial.print(':'); Serial.print(now.minute(), DEC); Serial.print(':'); Serial.print(now.second(), DEC); Serial.println(); /* // ******* Spielerei **** Serial.print(" since midnight 1/1/1970 = "); Serial.print(now.unixtime()); Serial.print("s = "); Serial.print(now.unixtime() / 86400L); Serial.println("d"); */ // ***** D a t u m ***** // ********************* // ***** Tag ***** if (now.day() < 10)Serial.print(0); // Wenn Wert kleiner/gleich '9', dann setzte noch eine '0' davor Serial.print("now.day= "); Serial.print(now.day(), DEC); Serial.print("."); if (now.day(), DEC >= 10) { lcd.setCursor(9, 0); lcd.print(now.day(), DEC); lcd.setCursor(11, 0); lcd.print("."); } else { lcd.setCursor(10, 0); lcd.print(now.day(), DEC); lcd.setCursor(11, 0); lcd.print("."); } // ***** Monat., Kurzform ***** lcd.setCursor(12, 0); lcd.print(monthShortStr(now.month())); lcd.setCursor(15, 0); lcd.print("."); // Kurzform Monat 'mmm' Serial.print(now.month(), DEC); Serial.print("."); Serial.print(now.year(), DEC); // ***** Jahr ***** lcd.setCursor(16, 0); lcd.println(now.year(), DEC); lcd.setCursor(20, 0); lcd.print(" "); // ***** Wochentag *** // Serial.print("Wochentag = "); Serial.println(weekday()); // Wochentag der UNIX-Zeit in 1970 Serial.print(" "); Serial.print(get_day_of_week(now.dayOfTheWeek())); Serial.print(", "); lcd.setCursor(0, 0); // 1.Zeile, 1.Spalte lcd.print(get_day_of_week(now.dayOfTheWeek())); lcd.setCursor(7, 0); lcd.print(". "); // ***** Stunde *** if (now.hour() < 10)Serial.print(0); // Wenn Wert kleiner 10, dann setzte noch eine '0' davor Serial.print("Es ist "); Serial.print(now.hour(), DEC); Serial.print(":"); if (now.hour() < 10) { // Wenn Wert kleiner 10, dann setzte noch eine '0' davor lcd.setCursor(5, 1); lcd.print(0); lcd.setCursor(6, 1); lcd.print(now.hour(), DEC); lcd.setCursor(7, 1); lcd.print(":"); } else // sonst eben ohne vorlaufende '0' lcd.setCursor(5, 1); lcd.print(now.hour(), DEC); lcd.setCursor(7, 1); lcd.print(":"); // *** Minute *** if (now.minute() < 10)Serial.print(0); Serial.print(now.minute(), DEC); Serial.print(":"); // Wenn Wert kleiner 10, dann setzte noch eine '0' davor if (now.minute() < 10) lcd.setCursor(8, 1); lcd.print(0); // Wenn Wert kleiner 10, dann setzte den Cursor auf Pos 9 und schreibe eine '0' if (now.minute() < 10) lcd.setCursor(9, 1); lcd.print(now.minute(), DEC); lcd.setCursor(10, 1); lcd.print(":"); // ... und dann schreibe die Sekunde if (now.minute() > 9) lcd.setCursor(8, 1); lcd.print(now.minute(), DEC); lcd.setCursor(10, 1); lcd.print(":"); // Wenn der Wert groesser 9, dann setze den Cursor auf Pos 11 und schreibe // *** Sekunde *** if (now.second() < 10)Serial.print(0); Serial.println(now.second(), DEC); // Wenn Wert kleiner 10, dann setzte noch eine '0' davor if (now.second() < 10) lcd.setCursor(11, 1); lcd.print(0); // Wenn Wert kleiner 10, dann setzte den Cursor auf Pos 12 und schreibe eine '0' if (now.second() < 10) lcd.setCursor(12, 1); lcd.print(now.second(), DEC); lcd.setCursor(13, 1); lcd.print(" "); // ... und dann schreibe die Sekunde if (now.second() > 9) lcd.setCursor(11, 1); lcd.print(now.second(), DEC); lcd.setCursor(13, 1); lcd.print(" "); // Wenn der Wert groesser 9, dann setze den Cursor auf Pos 11 und schreibe Serial.println(); lcd.setCursor(0, 2); lcd.print(" Hyg="); lcd.setCursor(0, 3); lcd.print("Baro= "); // *********** Sensorik **** alle 30 Sekunden ****************** if (now.second() == 30 || now.second() == 0) { h = (dht.readHumidity() + 30); // Luftfeuchte auslesen, sowie mit einem Korrektur-Wert addieren t = dht.readTemperature(); // Temperatur auslesen if (isnan(t) || isnan(h)) // Pruefen ob eine gueltige Zahl zurueckgegeben wird. Wenn NaN (not a number) zurueckgegeben wird, dann Fehler ausgeben. { // Serial.println("DHT22 konnte nicht ausgelesen werden"); } else { Serial.print("Luftfeuchte = "); Serial.print(h); Serial.println(" %\t"); Serial.print("Temperatur DHT22 = "); Serial.print(t); Serial.println(" C"); lcd.setCursor(0, 2); // 1.Spalte, 3.Zeile lcd.print(" Hyg="); lcd.setCursor(6, 2); // 7.Spalte, 3.Zeile lcd.print(h); lcd.setCursor(11, 2); // 12.Spalte, 3.Zeile lcd.print(" T= "); lcd.setCursor(15, 2); // 16.Spalte, 3.Zeile lcd.print(t); } // ****** Luftdruck ********************************* Serial.print("Temperatur BMP085 = "); t2 = bmp.readTemperature(); // Serial.print(bmp.readTemperature()); Serial.print(t2); Serial.println(" C"); Serial.print("durchschnittl. Temperatur aus beiden Werten = "); float t3 = (t2 + t) / 2; Serial.print(t3); Serial.println(" C"); Serial.print("Luftdruck = "); // Serial.print(bmp.readPressure()); // Serial.println(" Pa"); float d = bmp.readPressure(); Druck = (d + 2000) / 100; // Korrektur auf den hiesigen, aktuellen Wert Serial.print(Druck); Serial.println(" hPa"); lcd.setCursor(0, 3); // 1.Spalte, 4.Zeile lcd.print("Baro= "); lcd.setCursor(6, 3); // 8.Spalte, 4.Zeile lcd.print(Druck); lcd.setCursor(14, 3); lcd.print(" "); // Die kalkulierte Hoehe resultiert aus dem vorgegebenen Standard-Druck // von 1013.25 millibar = 101.325 Pascal. Die Korrektur erfolgt in Zeile 127. // Heiligenhaus liegt auf einer Hoehe von 170mtr (bzw. von 140 bis 190mtr). Serial.print("Hoehe = "); Serial.print(bmp.readAltitude()); Serial.println(" meter"); Serial.print("Luftdruck auf Seehoehe (errechnet) = "); Serial.print(bmp.readSealevelPressure()); Serial.println(" Pa"); // Man kann eine noch genauere Hoehen-Anzeige bekommen wenn man den aktuellen Luftdruck auf See-Höhe kennt, welche // mit dem Wetter variieren kann. Wenn es 1.015 millibar sind, dann ist es das selbe wie 101.500 Pascals. Serial.print("Tatsaechliche Hoehe = "); Serial.print(bmp.readAltitude(102240)); // Korrekturwert fuer Hlgh. in Klammern Serial.println(" meter"); // ****** Umrechnung auf Fahrenheit ******* /* float c = RTC.temperature() / 4.; float f = c * 9. / 5. + 32.; Serial << F(" ") << c << F(" C ") << f << F(" F"); */ } // Ende wenn Sekunde = 30, oder 59 else { // nichts tun } // wenn nicht 30 Sekunden, oder 59 Sekunden // ******* Aufbau des Daten-String ******** dataString = ""; dataString += (t); dataString += " C; "; dataString += (h); dataString += " %; "; dataString += (Druck); dataString += " hPa; "; dataString += (t2); dataString += " C;"; dataString += (" "); dataString += (now.day()); dataString += ("-"); dataString += (monthShortStr(now.month())); dataString += ("-"); dataString += (now.year()); dataString += (", "); dataString += (now.hour()); dataString += (":"); dataString += (now.minute()); dataString += (":"); dataString += (now.second()); Serial.println(dataString); // Serial.println(); // Serial.println(monthShortStr(now.month())); // Das hier ist der Monatsname als Kurz-Name, z.B. 'Feb' // *** FLAG zum Schreiben setzen ****** // *** ... und in einem Zeit-Rhytmus von 10 Minuten --> wenn m=09 or m=19 or m=29 or ... and s=00 // *** ... Da jedoch eine Messmoeglichkeit nicht immer genau um xy:19:59 zur Verfuegung stehen wird (Programmdurchlauf), oder gerade dann // der Wert 'nan' ist, muß auch da zudem noch solange der Schreib-Kanal geöffnet bleiben, bis es zu einer Speicherung gekommen // ist - und dann 'weiter wie geplant' = xy:29:59 ! if ((now.minute() == 9 && now.second() == 59) || (now.minute() == 19 && now.second() == 59) || (now.minute() == 29 && now.second() == 59) || (now.minute() == 39 && now.second() == 59) || (now.minute() == 49 && now.second() == 59) || (now.minute() == 59 && now.second() == 59)) { go = 1; // ... DANN go=1 --- Variable zur Freigabe des SPEICHER-Vorgangs auf die SD-Karte. Funktion ist geprueft ! } // if else { // nichts tun } // *** Speichern der Sensor-Daten ***** // ************************************ // *** Speicherung auf der SD-Karte *** // *** MOSI - pin 11 / 51 oder SPI Header // *** MISO - pin 12 / 50 oder SPI Header // *** CLK - pin 13 / 52 oder SPI Header // *** CS - pin 4 oder 10 beim UNO; 4 oder 53 beim MEGA, bzw. SS // *** hier werden die Kriterien ueberprueft, welche erfuellt sein muessen, um einen Schreib-Vorgang zu starten **** if (now.year() < 2016) { // *** 3. ... und wenn eine korrekt Zeit vorhanden ist Serial.println(); Serial.println(" RTC nicht vorhanden. "); // .. sonst nichts machen } else { // ... ansonsten weitermachen Serial.print(" RTC vorhanden - das akt. Jahr= "); Serial.println(now.year()); if (isnan(t) || isnan(h)) // *** 2. ... und keine Sensor-Werte fehlen --> wenn (hygro) oder (temp) = 'NAN' { Serial.println(" Keine Sensordaten "); // ... nichts machen } else { Serial.println(" Sensordaten komplett "); // ... ansonsten weitermachen if ( go < 1) { // *** 1. grundsaetzliche Speicherfreigabe gemaess Intervall-Vorgabe Serial.print(" Keine Freigabe ! go= "); Serial.println(go); // ... nichts machen } else { Serial.print("XY:"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" - go= "); Serial.print(go); Serial.print(" - year= "); Serial.print(now.year()); Serial.println(" - Sensordaten verfuegbar "); logDat = SD.open("senslog.txt", FILE_WRITE); // Oeffenen der Datei 'senslog.txt' zum nachfolgenden SCHREIBEN Serial.println("senslog.txt zum Schreiben oeffnen."); if (logDat) { logDat.println(dataString); // Beschreiben der soeben erstellten Datei logDat.close(); // Datei nach dem Schreiben wieder schliessen go = 0; // Intervall-Freigabe zuruecksetzen Serial.print("SD-Speicherung erfolgreich. "); Serial.print("Die Variable go wird zurueckgesetzt auf den Wert: "); Serial.println(go); } else { Serial.println("Fehler beim Oeffnen der Datei Senslog.txt !"); // Hinweis fuer den Fall, dass sich die Datei nicht mehr oeffnen laesst } // Ende Schreibfehler } // Ende GPS-Signal ? } // Ende else isnan } // Ende Speicher-Intervall delay(1000); // 5 Sekunden bis zur nächsten Ausgabe } // LOOP