// // *** nur fuer **** M E G A 2 5 6 0 **** oder groesser ********************************* // *************************************************************************************************** // *** Version: *** Sensorik_SD_TFT6c1.ino *** *** // *** ************* WICHTIGE HINWEISE ************************************************************** // *** ACHTUNG: Original-Code stimmte nicht mit Library ueberein. DEC = Dezimal *** // *** ********* DIE SPEICHERUNG ERFOLGT NUR ZUVERLAESSIG MIT EINER 2GB-KARTE ************* *** // *** Die SD-Slot-Anschluesse MOSI, MISO und SCK sind zwingend mit 3.3V-Pegel zu betreiben !!!! *** // *** Der BMP080 (BMP185, BY68, ....) ist ebenfalls nur mit 3.3V zu betreiben ! *** // *************************************************************************************************** // *** *** // *** Aufgabe: *** // *** Temperatur-Messung, Luftfeuchte, Luftdruckmessung, in Verbindung mit der *** // *** Zeit anzeigen und auf SD-Karte speichern *** // *** Stand: Sensorik-SD-TFT3 - 1.8"-TFT-Display, 13.03.2016 *** // *** Sensorik-SD_TFT4 - Sommer-/Winterzeit-Steuerung, 03.04.2016 *** // *** Sensorik_SD_TFT5 - mit 433Mhz-Empfaenger von Aussensensordaten, 19.04.2016 *** // *** Sensorik_SD_TFT6 - wie vor, jedoch mit besserem 433 Mhz-Empfaenger, 19.05.2016 *** // *** Sensorik_SD_TFT6a - wie vor, jedoch zusaetzlich auch die Anzeige der Aussen-Werte *** // *** Anzeige ob Aussendaten fehlen und ob SD-Speicherung ausgefallen *** // *** >>> 02.06.2016 <<< *** // *** 07.07.2016 Sensorik_SD_TFT6b.ino Wie vor jedoch mit einer Korrektur für die Zeiteinstellung *** // *** 13.07.2016 Sensorik_SD_TFT6c.ino - Komplett ueberarbeitet und erweitert *** // *** 25.07.2016 Sensorik_SD_TFT6c1.ino *** // ************************ DL2EBZ ******************************************************************* // *** Anschluesse: // *** DHT22 -Pin = Pin 7 // *** 433Mhz-Empaenger = Pin 2 // *** DS3231-SDA = Pin 20 (SDA) // *** -SCL = Pin 21 (SCL) // *** BMP085-SDA = Pin 20 (SDA) // *** -SCL = Pin 21 (SCL) // *** SD-Card mit Zugriff ueber den SPI-Bus // *** MOSI - SPI (oder MEGA 51) // *** MISO - SPI (oder MEGA 50) // *** CLK - SPI (oder MEGA 52) // *** SD_CS = Pin 53 // *** TFT_CS = Pin 10 // *** TFT_Reset (RST) = Pin 9 // *** TFT_A0 (RS) = Pin 8 // *** TFT_SDA (MOSI) = Pin 51 // *** TFT_SCK (SCLK) = Pin 52 // *** ******************* A e n d e r u n g e n ********************************************* // *** 02.03.2016 a) SD-Karte einbinden // *** 12.03.2016 b) Speicher-Zyklus einstellen // *** 13.03.2016 c) Wenn-Dann-Auswahl beim Tages-Datum instand setzen // *** d) Zeit= jede Sekunde, Sensorik= alle 30 Sekunden, Speichern= alle 10 Minuten // *** 13.03.2016 ==> allerdings nur ein einziges Mal !!!! Nicht eine ganze Minute lang jede Sekunde // *** 14.03.2016 Erweiterung um die sekundengenaue Ausgabe nach Volker d.V. // *** 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 // *** 02.03.2016 g) Monats-Namen ausgeben (muss eine vorhandene Funktion in der TIME.h sein) --> monthShortStr(now.month()) // *** 19.01.2016 h) Moeglichkeit einer Zeit-Korrektur schaffen // *** i) SD-Card einbinden --> schreiben, auslesen, sowie löschen // *** j) Darstellung einer Balkengrafik für Barometer-Verlauf // *** 19.03.2016 k) Anzeige auf TFT-Display, statt LCD-Display, Version-4 (Sensorik_SD_TFT.ino) // *** l) Das Datums muß noch vor einer jeden Aenderung 'uebermalt' werden !! // *** 03.04.2016 m) Erweiterung um die Sommer-/Winterzeit-Umstellung durch DL9VDV // *** 01.05.2016 n) Erweiterung um den Empfaenger für Aussen-Daten // *** 19.05.2016 o) Verbesserung des Empfaengers durch DL9VDV Sketch-Einbindung, sowie 'TimeOut-Pruefung' von mir // *** Ausgabe der externen Daten auf seriellen Monitor << noch offen >> Ausgabe auf TFT // *** behoben - siehe p, q, r: Bei einem Kalt-Start (gegen 00:xy und/oder xy:00) werden die Stunden und Minuten nicht mehr angezeigt; erst nach der Aktualisierung des Wertes wieder. // *** 07.07.2016 p) Wie vor jedoch mit Aenderungen im Bereich der Zeiteinstellung (Zeile 164-192 und 645-646) --> Version 6b // *** 13.07.2016 q) Ueberarbeitung der Zeiteinstellung, sowie der sofortigen Anzeige einer fehlerhafter SD-Karten-Initialisierung --> Version 6c // *** 25.07.2016 r) nochmalige Ueberarbeitung der sich jede Sekunde komplett (!) neu aufbauenden Zeit-Anzeige --> Version 6c1 // *** // *** // *** Weitere Planungen: // *** Man koennte den MAX- und MIN-Wert des Tages auf dem Display ausgeben (diese Werte auch zu speichern macht keinen Sinn, da die EXCEL-Auswertung der Daten einfaqcher ist) // *** ...... jedoch koennte man zusätzlich die letzte Speicher-Datenzeile auslesen und bei gleichem Datum (!) mit den neuen MIN/MAX-Werten vergleichen. // *** Ausgabe auf 2.4"-TFT und ggf. auf 4.3"-TFT umbauen // *** 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 am Standort berechnen // *** Der gelbe Hinweis auf eine nicht erfolgte SD-Karten-Speicherung sollte moeglichst automatisiert abgeschaltet werden könne (--> Neu-Initialisierung bei Bedarf) // *** ... bisher jedoch fuehrt ein turnusmaeßiger weiterer Initialisierungs-Versuch im Falle eines Fehlers zu Verzoegerungen des restlichen Ablaufes (nur noch alle 2 Sekunden Anzeige !) // *** // *** Bauteile/Module // *** DHT22 OK, BMP085 OK, DS3231 OK, SD-Kartenleser OK, 433Mhz-Empfaenger, 1.8"-TFT-Anzeige, sowie externer TX // *** // ************************************************ #include // #include // I2C-Bibliothek einbinden #include "RTClib.h" // RTC-Bibliothek einbinden #include #include // SD-Karte einbinden // #include // Im Folgenden wird jedoch die Library des DS1307 genutzt !! RTC_DS1307 RTC; // RTC Modul // ************** 433 MHz ************************ #include // 433MHz-Empfaenger RCSwitch mySwitch = RCSwitch(); long wartezeit = 65000; // Vorgabe: aktuell 65 Sekunden long lastMillis = 0; // Variable für den letzten verfuegbaren Millis-Wert long zeitspanne = 0; // Variable fuer die Differenz von Millis zu lastMillis struct ts_ausgabe { int ident; float wert; int nachkomma; }; // ************** TFT ************************ #include // Core graphics library #include // Hardware-specific library #define TFT_CS 10 // egal ob UNO, oder MEGA2560 - immer dieser Pin #define TFT_RST 9 // man kann auch den Arduino reset nutzen. In dem Fall lautet die Zeile #define pin 0! #define TFT_DC 8 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); #define TFT_SCLK 52 // MEGA --> UNO 13 #define TFT_MOSI 51 // MEGA --> UNO 11 // *** alternative Schreibweise : Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); // Adafruit_ST7735 tft = Adafruit_ST7735(10, 8, 52, 51, 9); // ************* Sensorik ********************** #include "DHT.h" // DHT-Bibliothek #include // BMP085-Bibliothek #define DHTPIN 7 #define DHTTYPE DHT22 // DHT11, DHT21, DHT22 DHT dht(DHTPIN, DHTTYPE); // Temp-Feuchte-Sensor Adafruit_BMP085 bmp; // Luftdruck-Sensor // ************** 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, oder Pin4oder Pin10 File logDat; // diese Variable 'logDat' im Format 'File' nimmt spaeter den Dateinamen und die Befehle auf int go = 0; // SD-Schreib-Freigabe int initSD = 0; // ******** diverse Variablen ******************* float h; // Luftfeuchte DHT22 float t; // Temperatur DHT22 float t2; // Temperatur BMP085 float Druck; // Baro BMP085 static long md = 7; // default-Wert, der nie erreicht wird, um so mindestens einen Durchlauf zu gewaehrleisten static long tag; static long mh = 25; // eine Stunde mehr als noetig static long mm = 61; // eine Minute mehr als noetig float ta; // Aussen-Temperatur float ha; // Aussen-Luftfeuchte // *********************************************************************************************************** // *************************** S E T U P ********************************************************************* void setup() { Serial.begin(9600); // Serielle Ausgabe starten Wire.begin(); // Initialisiere I2C RTC.begin(); // Initialisiere RTC tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab tft.fillScreen(ST7735_BLACK); Serial.println("Initialized"); // *** Kurzer Funktions-Test *** uint16_t time = millis(); tft.fillScreen(ST7735_BLACK); time = millis() - time; Serial.println(time, DEC); // delay(200); // large block of text // testdrawtext("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", ST7735_WHITE); // delay(3000); // ** erste Nennung den Bildschirm zu loeschen, schwarzer Hintergrund, rote Schrift (bis auf Widerruf) und text-Groesse tft.setTextWrap(false); tft.fillScreen(ST7735_BLACK); tft.setTextColor(ST7735_RED); tft.setTextSize(2); // (Werte von 1-4) tft.setRotation (45); // 90° gedrehte Darstellung tft.setTextColor(ST7735_WHITE); tft.setTextSize(1); tft.setCursor(51, 62); tft.print(" innen aussen "); // Ueberschrift (Spalte 51, Zeile 62) tft.fillRect( 5, 72, 150, 2, 0xFFFF); // setze eine 2-zlg., weisse Linie unter die Titel-Zeile (von Spalte 5, Zeile 72, bis Spalte 150, Breite 2-zlg., weiss) tft.setCursor(5, 80); tft.print("Thermo = "); // (Spalte 5, Zeil 80) tft.setCursor(5, 95); tft.print(" Hygro = "); // (Spalte 5, Zeile 95) tft.setCursor(5, 110); tft.print(" Baro = "); // (Spalte 5, Zeile 110) // **** Temp/Feuchte-Sensor starten **** dht.begin(); // Start des Temp-Sensors // **** Empfaenger starten ************* mySwitch.enableReceive(0); // 433Mhz-Receiver an interrupt 0 => das ist pin #2 // **** Pruefen ob BMP085 laeuft ************* // Serial.begin(9600); if (!bmp.begin()) { Serial.println("Kein BMP085 gefunden ... I2C Adresse und Verkabelung pruefen !"); while (1) {} } // **** RTC in Betrieb nehmen ************* // *** Es gibt die Moeglichkeit die Uhrzeit fix vorzugeben *** Hier beispielhaft 25.Juli 2016, 12:29:00 Uhr ******************* // RTC.adjust(DateTime(2016, 7, 25, 13, 39, 30)); // Hier ist immer (!) die MEZ (Winterzeit) anzugeben // *** ... und nach dem Hochladen ist dann diese Zeile wieder auszukommentieren +++++++ !!! .. und nochmals hochladen !!!!! *** if (! RTC.isrunning()) { Serial.println("RTC laeuft nicht !"); // nichts weiter machen } // *** Der folgende Teil dient einer automatisierten Zeit-Einstellung ueber die PC-Zeit ***** /* else { DateTime now = RTC.now(); // Zeit von RTC holen DateTime compiled = DateTime(__DATE__, __TIME__); // Zeit von PC holen if (now.unixtime() < compiled.unixtime()) // wenn RTC-Zeit groesser als PC-Zeit dann korrigieren { 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 neu"); } else { Serial.print("Es ist "); Serial.print(now.unixtime()); Serial.println(" Echtzeituhr laeuft bereits und ist aktuell."); } */ else { Serial.println("Die RTC laeuft bereits."); } // ******* SD-Karte einbinden und pruefen ************ while (!Serial) // Zugriffs-Versuch auf die SD-Karte { // Hier wird gewartet bis der 'Serielle Monitor' gestartet wurde } Serial.print("Initialisiere SD-Card... "); pinMode (53, OUTPUT); // fuer MEGA2560; fuer UNO '04', oder '10' if (!SD.begin(SD_CS)) { Serial.println(" SD-Fehler !"); initSD = 0; return; } Serial.println("SD-OK!"); Serial.println(); initSD = 1; } // Setup // **** Wochentag ermitteln **** Das muss noch ausserhalb von 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; } void testdrawtext(char *text, uint16_t color) { tft.setCursor(0, 0); tft.setTextColor(color); tft.setTextWrap(false); tft.print(text); } // *********************************************************************************************************** // **************** L O O P ****************************************************************************** long currentTime = millis(); // http://www.vielsichtig.de/index.php?id=120 void loop() { // -------- Code-Erweiterung von Volker v.d.V. ------------------------ static long sav_sec; // letzte Sekunde merken DateTime now = RTC.now(); if (now.second() == sav_sec) { return; // Loop bis zur neuen Sekunde } else { sav_sec = now.second(); // aktuelle Sekunde merken // DL9VDV Sommerzeit Anfang now = aktualisiere_zeit(now); // DL9VDV Sommerzeit Ende // DL9VDV fuer Kalenderwoche Anfang static int lv_day; static int lv_kw; if (now.day() != lv_day) { lv_day = now.day(); lv_kw = hole_kalenderwoche(now.year(), now.month(), now.day(), 0); } // DL9VDV fuer Kalenderwoche Ende // *** 433Mhz-Empfang ***** DL9VDV ************************* struct ts_ausgabe ls_ausgabe; if (mySwitch.available()) { ls_ausgabe = decode_433(mySwitch.getReceivedValue()); if (ls_ausgabe.ident > 0) { ausgabe(ls_ausgabe); ls_ausgabe.ident = 0; } mySwitch.resetAvailable(); } // *** TimeOut-Pruefung *** DL2EBZ *** zeitspanne = (millis() - lastMillis); if ((millis() - lastMillis) > wartezeit) { Serial.print ("Zeitspanne= "); Serial.print (zeitspanne); Serial.println(" Timeout-Zeit fuer den 433-MHz-Sender ist ueberschritten !!"); tft.fillRect(110, 76, 37, 13, 0xF800); // male den Bereich für die Temp rot aus - Beginn Y=110, X=76, 37 Spalten breit, 13 Zeilen tief tft.fillRect(110, 91, 37, 13, 0xF800); // male den Bereich für die Temp rot aus } else { // Serial.println(" Timeout-Zeit ist OK "); } // ********** Live-Pruefung ob die SD-Karte 'OK' ist ****************** // if (!SD.begin(SD_CS)) Serial.print("initSD= "); Serial.print(initSD); if (initSD == 0) { tft.fillRect(10, 55, 15, 10, 0xFFE0); // male den Bereich für die Temp gelb aus - Beginn Y=15, X=55, 15 Spalten breit, 10 Zeilen tief tft.setTextColor(ST7735_BLACK); tft.setTextSize(1); tft.setCursor(12, 57); tft.print("SD"); // (Spalte 12, Zeile 57) Serial.println(" --> Fehlerhafte Initialisierung der SD-Karte !"); } else { tft.fillRect(10, 55, 15, 10, 0x07E0); // male den Bereich für die Temp gruen aus - Beginn Y=20, X=55, 15 Spalten breit, 10 Zeilen tief tft.setTextColor(ST7735_BLACK); tft.setTextSize(1); tft.setCursor(12, 57); tft.print("SD"); // (Spalte 12, Zeile 57) Serial.println(" --> Initialisierung der SD-Karte OK"); } // ***** D a t u m ***** // ********************* if (now.day() == tag) // wenn das Tages-Datum gleich dem gemerkten TagesDatum ist, dann ... { // ... nichts machen } else // ... sonst hier weiter machen (also bei Datums-Wechsel) { // ***** Tag ***** if (now.day() < 10)Serial.print(0); // Wenn Wert kleiner 10, dann setzte noch eine '0' davor Serial.print("now.day= "); Serial.print(now.day(), DEC); Serial.print("."); tft.fillRect(1, 5, 140, 15, 0x0000); // (links,oben,rechts,unten, Farbe) male den Bereich für des Wochentages schwarz aus if (now.day(), DEC >= 10) // bei einstelligen Datum eine '0' vorausstellen { tft.setCursor(8, 10); tft.setTextColor(ST7735_RED); tft.setTextSize(2); tft.print(now.day()); tft.setCursor(18, 10); tft.println(" . "); // Position und Inhalt } else { tft.setCursor(13, 10); tft.setTextColor(ST7735_RED); tft.setTextSize(2); tft.print(now.day()); tft.setCursor(18, 10); tft.println(" . "); // Position und Inhalt } tag = now.day(); // die gemerkte Minute erhält den Wert der aktuellen Stunde // ***** Monat., Kurzform ***** Serial.print(now.month(), DEC); Serial.print("."); Serial.print(now.year(), DEC); tft.setCursor(48, 10); tft.setTextColor(ST7735_YELLOW); tft.setTextSize(2); tft.print(monthShortStr(now.month())); tft.setCursor(69, 10); tft.println(" . "); // Monat in klein und gelb // ***** Jahr ***** tft.setCursor(99, 10); tft.println(now.year()); // Jahreszahl in klein und gelb // ***** Wochentag *** Serial.print(" "); Serial.print(get_day_of_week(now.dayOfTheWeek())); Serial.print(", "); tft.fillRect(8, 31, 49, 35, 0x0000); // (links,oben,rechts,unten, Farbe) male den Bereich für des Wochentages schwarz aus tft.setCursor(8, 33); tft.setTextColor(ST7735_GREEN); tft.setTextSize(1); tft.println(get_day_of_week(now.dayOfTheWeek())); // Tagesname in klein und gruen } // else tag <> now.day // ***** 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() == mh) // wenn die aktuelle Minute gleich der gemerkten Minute ist, dann ... { // ... nichts machen } else // ... sonst hier weiter machen { if (now.hour() < 10) { tft.fillRect(60, 25, 79, 35, 0x0000); // male den Bereich für die Stunde schwarz aus tft.setCursor(60, 30); tft.setTextColor(ST7735_BLUE); tft.setTextSize(2); tft.print("0"); tft.setCursor(72, 30); tft.print(now.hour(), DEC); tft.setCursor(80, 30); tft.print(":"); // Stunde in klein und blau } else { tft.fillRect(60, 25, 79, 35, 0x0000); // male den Bereich für die Stunde schwarz aus tft.setCursor(60, 30); tft.setTextColor(ST7735_BLUE); tft.setTextSize(2); tft.print(now.hour(), DEC); tft.setCursor(80, 30); tft.print(":"); } mh = now.hour(); // die gemerkte Minute erhält den Wert der aktuellen Stunde } // *** Minute *** if (now.minute() == mm) // wenn die aktuelle Minute gleich der gemerkten Minute ist, dann ... { // ... nichts machen } else // ... sonst hier weiter machen { if (now.minute() < 10) { tft.fillRect(90, 25, 109, 35, 0x0000); // male den Bereich für die Minute schwarz aus tft.setTextColor(ST7735_BLUE); tft.setTextSize(2); tft.setCursor(90, 30); tft.print("0"); tft.setCursor(102, 30); tft.print(now.minute(), DEC); tft.setCursor(110, 30); tft.print(":"); } else { tft.fillRect(90, 25, 109, 35, 0x0000); // male den Bereich für die Minute schwarz aus tft.setTextColor(ST7735_BLUE); tft.setTextSize(2); tft.setCursor(90, 30); tft.print(now.minute(), DEC); tft.setCursor(110, 30); tft.print(":"); } mm = now.minute(); // die gemerkte Minute erhält den Wert der aktuellen Minute } // *** Sekunde *** tft.fillRect(120, 25, 140, 35, 0x0000); if (now.second() < 10) { tft.setTextColor(ST7735_BLUE); tft.setTextSize(2); tft.setCursor(120, 30); tft.print("0"); tft.setCursor(132, 30); tft.print(now.second(), DEC); // Wenn Wert kleiner 10, dann setzte noch eine '0' davor } else { tft.setTextColor(ST7735_BLUE); tft.setTextSize(2); tft.setCursor(120, 30); tft.print(now.second(), DEC); } Serial.println(); } // *********** Sensorik **** alle 30 Sekunden ****************** tft.setTextColor(ST7735_WHITE); tft.setTextSize(1); if (now.second() == 30 || now.second() == 0) { // h = (dht.readHumidity() + 30); // Luftfeuchte auslesen, sowie mit einem Korrektur-Wert addieren h = (dht.readHumidity()); // Luftfeuchte auslesen 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"); static long mte; // Anzeige der Temperatur if (t == mte) // wenn die aktuelle Temperatur gleich der gemerkten Temperatur ist, dann ... { // ... nichts machen } else // ... sonst hier weiter machen { tft.fillRect(55, 75, 150, 85, 0x0000); // male den Bereich für die Temp schwarz aus tft.setTextSize(1); tft.setCursor(58, 80); tft.print(t); mte = t; // die gemerkte Temperatur erhält den Wert der aktuellen Temperatur } // else Temperatur static long mhu; // Anzeige der Luftfeuchte if (h == mhu) // wenn die aktuelle Feuchte gleich der gemerkten Feuchte ist, dann ... { // ... nichts machen } else // ... sonst hier weiter machen { tft.fillRect(58, 90, 150, 100, 0x0000); // male den Bereich für die Feuchte schwarz aus tft.setTextSize(1); tft.setCursor(58, 95); tft.print(h); mhu = h; // die gemerkte Feuchte erhält den Wert der aktuellen Feuchte } // else Luftfeuchte } // else 30-Sekunden-Interval // ***** Aussenwerte **** // (Spalte links, Zeile oben, Spalte rechts, Zeile unten) tft.fillRect(110, 75, 150, 85, 0x0000); // male den Bereich für die Temp schwarz aus tft.setTextSize(1); tft.setCursor(110, 80); tft.print(ta); tft.setCursor(135, 80); tft.print(" C"); tft.fillRect(110, 90, 150, 100, 0x0000); // male den Bereich für die Feuchte schwarz aus tft.setTextSize(1); tft.setCursor(110, 95); tft.print(ha); tft.setCursor(135, 95); tft.print(" %"); // ****** 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"); static long mdr; // Anzeige des Luftdruck if (Druck == mdr) // wenn die aktuelle Minute gleich der gemerkten Minute ist, dann ... { // ... nichts machen } else // ... sonst hier weiter machen { tft.fillRect(58, 105, 150, 115, 0x0000); // male den Bereich für die Minute schwarz aus tft.setTextSize(1); tft.setCursor(58, 110); tft.print(Druck); tft.setCursor(100, 110); tft.print(" hpa"); mdr = Druck; // die gemerkte Minute erhält den Wert der aktuellen Minute } // 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); // Innen-Temperatur (DHT22) dataString += " C; "; dataString += (h); // Innen-Luftfeuchte (DHT22) dataString += " %; "; dataString += (Druck); dataString += " hPa; "; dataString += (t2); // Innen-Temperatur (BMP085) 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()); dataString += ("; "); // Aussen-Temperatur dataString += (ta); dataString += (" C; "); // Aussen-Luftfeuchte dataString += (ha); dataString += (" %"); Serial.println("Innen-T; Innen-Hygro; Luftdruck; 2.Innen-T; Datum; Uhrzeit; Aussen-Temp; Aussen-Hygro"); 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, 10 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.print("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); tft.fillRect(30, 55, 15, 10, 0x0000); // male den Bereich für die Temp schwarz aus - Beginn Y=20, X=55, 15 Spalten breit, 10 Zeilen tief } else { Serial.println("Fehler beim Oeffnen der Datei Senslog.txt !"); // Hinweis fuer den Fall, dass sich die Datei nicht mehr oeffnen laesst tft.fillRect(30, 55, 15, 10, 0xFFE0); // male den Bereich für die Temp gelb aus - Beginn Y=20, X=55, 15 Spalten breit, 10 Zeilen tief tft.setTextColor(ST7735_BLACK); tft.setTextSize(1); tft.setCursor(32, 57); tft.print("SD"); // (Spalte 22, Zeile 57) } // Ende Schreibfehler } // Ende GPS-Signal ? } // Ende else isnan } // Ende Speicher-Intervall } // LOOP // *********************************************************************************************************** // DL9VDV Beginn ---------------------- DateTime aktualisiere_zeit(DateTime ls_now1) { DateTime ls_now; static int lv_stunde = -1; static int lv_zeitdiff; ls_now = ls_now1; // ** falls RTC auf UTC laeuft ** // ls_now = ls_now + TimeSpan(0, 1, 0, 0); // + Stunde(n) // ** falls RTC auf MESZ laeuft ** ls_now = ls_now + TimeSpan(0, -1, 0, 0); // -1 Stunde if (ls_now1.hour() != lv_stunde) { lv_stunde = ls_now1.hour(); lv_zeitdiff = sommerzeit(ls_now); } if (lv_zeitdiff != 0) ls_now = ls_now + TimeSpan(0, lv_zeitdiff, 0, 0); // + Stunde(n) return ls_now; } int sommerzeit(DateTime ls_now) { int lv_aenderungsstunde = 2; // Aenderungszeit 2 Uhr int lv_day_sonntag; // Sommerzeit letzter Sonntag Maerz 2 Uhr 25. - 31. // bis letzter Sonntag Oktober 2 Uhr 25. - 31. if (ls_now.month() < 3 || ls_now.month() > 10 || (ls_now.month() == 3 && ls_now.day() < 25)) return 0; if ((ls_now.month() > 3 && ls_now.month() < 10) || (ls_now.month() == 10 && ls_now.day() < 25)) return 1; if (ls_now.month() == 3 && ls_now.dayOfTheWeek() == 0 && ls_now.hour() >= lv_aenderungsstunde) return 1; if (ls_now.month() == 3 && ls_now.dayOfTheWeek() == 0 && ls_now.hour() < lv_aenderungsstunde) return 0; if (ls_now.month() == 10 && ls_now.dayOfTheWeek() == 0 && ls_now.hour() >= lv_aenderungsstunde) return 0; if (ls_now.month() == 10 && ls_now.dayOfTheWeek() == 0 && ls_now.hour() < lv_aenderungsstunde) return 1; lv_day_sonntag = ls_now.day() - ls_now.dayOfTheWeek(); if (ls_now.month() == 3 && lv_day_sonntag >= 25) return 1; if (ls_now.month() == 3 && lv_day_sonntag < 25) return 0; if (ls_now.month() == 10 && lv_day_sonntag >= 25) return 0; if (ls_now.month() == 10 && lv_day_sonntag < 25) return 1; return 0; // sollte unnoetig sein } // Rest fuer Kalenderwoche (auch Jahrestag) int hole_kalenderwoche(int jahr, int monat, int tag, int jt) { const int lt_monatstage[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int lv_jahrestag; int lv_tag_akt; int lv_tag_first; int lv_diff_tag; if (jt == 0) { lv_jahrestag = hole_jahrestag(jahr, monat, tag); } else { lv_jahrestag = jt; } DateTime ls_now_montag_akt (jahr, monat, tag, 0, 0, 0); lv_tag_akt = ls_now_montag_akt.dayOfTheWeek(); // Montag der Woche if (lv_tag_akt == 0) { lv_diff_tag = lv_jahrestag - 6; } else { lv_diff_tag = lv_jahrestag - lv_tag_akt + 1; } // 1.KW, wenn 1.1. Mo-Do; letzte KW-Vorjahr, wenn 1.1 Fr - So // daraus ergibt sich: der 4.1. liegt immer in der ersten Woche // 4.1. Mo-Mi 1.1. letzte KW-Vorjahr; 4.1. Do-So 1.1. 1.KW // 31.12 Mo-Mi 1.KW; 31.12. Do-So akt. KW - möglich bei 29.-31.12. DateTime ls_now_montag_first (jahr, 1, 4, 0, 0, 0); lv_tag_first = ls_now_montag_first.dayOfTheWeek(); // 4.1. Mo-Mi und akt. Tag nicht in dieser Woche: letzte KW-Vorjahr if (lv_tag_first >= 1 && lv_tag_first <= 3 && lv_jahrestag < (4 - lv_tag_first + 1)) return hole_kalenderwoche((jahr - 1), 12, 31, 0); // 31.12 Mo-Mi 1.KW Folgejahr; if (lv_tag_akt >= 1 && lv_tag_akt <= 3 && monat == 12 && tag >= 29 && (31 - tag + lv_tag_akt) < 4) return 1; // Montag der 1.KW if (lv_tag_first == 0) { lv_diff_tag = lv_diff_tag + 6; } else { lv_diff_tag = lv_diff_tag + lv_tag_first - 1; } return ((lv_diff_tag / 7) + 1); } int hole_jahrestag(int jahr, int monat, int tag) { const int lt_monatstage[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int lv_jt; int lv_loop_monat; lv_jt = tag; lv_loop_monat = monat - 1; while (lv_loop_monat > 0) { lv_jt = lv_jt + lt_monatstage[lv_loop_monat - 1]; // Schaltjahr = durch 4 teilbar aber nicht durch 100 ausser 400 if (lv_loop_monat == 2 && ((jahr % 4 == 0 && jahr % 100 != 0) || jahr % 400 == 0)) lv_jt = lv_jt + 1; lv_loop_monat = lv_loop_monat - 1; } return lv_jt; } // DL9VDV Ende ---------------------- // DL9VDV Beginn --- 433 MHz -------- void ausgabe( struct ts_ausgabe ls_ausgabe) { int lv_std, lv_min, lv_sek; long lv_wert; if (ls_ausgabe.ident == 10) // Luftfeuchte { // Serial.print("Aussen-Hygro: "); Serial.println(ls_ausgabe.wert, ls_ausgabe.nachkomma); ha = (ls_ausgabe.wert); lastMillis = millis(); // aktualisieren des letzten erreichbaren Zeit-Wert (nur bei vorhandenem Empfang) } else if (ls_ausgabe.ident == 12) // Temperatur { // Serial.print("Aussen-Temp: "); Serial.println(ls_ausgabe.wert, ls_ausgabe.nachkomma); ta = (ls_ausgabe.wert); lastMillis = millis(); // aktualisieren des letzten erreichbaren Zeit-Wert (nur bei vorhandenem Empfang) } // ***** weitere Sensoren anschliessbar *** /* else if (ls_ausgabe.ident == 14) { Serial.print("temp_bmp180: "); Serial.println(ls_ausgabe.wert, ls_ausgabe.nachkomma); lastMillis = millis(); // aktualisieren des letzten erreichbaren Zeit-Wert (nur bei vorhandenem Empfang) } else if (ls_ausgabe.ident == 16) { Serial.print("baro: "); Serial.println(ls_ausgabe.wert, ls_ausgabe.nachkomma); lastMillis = millis(); // aktualisieren des letzten erreichbaren Zeit-Wert (nur bei vorhandenem Empfang) } else if (ls_ausgabe.ident == 18) { lv_wert = ls_ausgabe.wert; lv_std = lv_wert / 10000; lv_min = (lv_wert - ((lv_wert / 10000) * 10000)) / 100; lv_sek = lv_wert - ((lv_wert / 100) * 100); Serial.print("zeit1: "); Serial.print(lv_std); Serial.print(":"); Serial.print(lv_min); Serial.print(":"); Serial.println(lv_sek); lastMillis = millis(); // aktualisieren des letzten erreichbaren Zeit-Wert (nur bei vorhandenem Empfang) } else if (ls_ausgabe.ident == 40) { Serial.print("Tests: "); Serial.println(ls_ausgabe.wert, ls_ausgabe.nachkomma); lastMillis = millis(); // aktualisieren des letzten erreichbaren Zeit-Wert (nur bei vorhandenem Empfang) } */ } // ausgabe // **** 433 MHz Empfang-Funktionen Beginn ***************************** /* vdv test 1234567890 mySwitch.send(4294967295, 32); Typ long max 10 Stellen 1-2: Code 10-40 in Zweierschritten - Identifikation des Wertes Zweierpaerchen: Code + 1 (ungerade) für negatives Vorzeichen 3: Anzahl der Nachkommastellen 4-9: Wert 6 Stellen 10: Pruefcode Module 9 Stellen 1-9 */ struct ts_ausgabe decode_433(unsigned long lv_input) { int lv_pruefcode; static unsigned long lv_last_command; int lv_ident; int lv_nachkomma; int lv_while; float lv_wert; struct ts_ausgabe ls_ausgabe; ls_ausgabe.ident = 0; if (lv_input < 1000000000 || lv_input > 4199999999) return ls_ausgabe; lv_pruefcode = lv_input - ((lv_input / 10) * 10); lv_input = lv_input / 10; if ((lv_input % 9) != lv_pruefcode) return ls_ausgabe; // Wiederholung ? #ifdef protokoll if (lv_input == lv_last_command) // Testausgabe { Serial.print("----- Wiederholung: "); Serial.println(lv_last_command); } #endif if (lv_input == lv_last_command) return ls_ausgabe; lv_last_command = lv_input; lv_ident = lv_input / 10000000; lv_input = lv_input - ((lv_input / 10000000) * 10000000); lv_nachkomma = lv_input / 1000000; lv_input = lv_input - ((lv_input / 1000000) * 1000000); lv_wert = lv_input; lv_while = lv_nachkomma; while (lv_while > 0) { lv_wert = lv_wert / 10.0; lv_while = lv_while - 1; } if (lv_ident % 2 != 0) { lv_wert = -lv_wert; lv_ident = lv_ident - 1; } if (lv_ident % 2 != 0) return ls_ausgabe; ls_ausgabe.ident = lv_ident; ls_ausgabe.wert = lv_wert; ls_ausgabe.nachkomma = lv_nachkomma; return ls_ausgabe; } // --- 433 MHz Empfang-Funktionen Ende ********************** // ***** ENDE des Script ****************************************************************