ENC28J60 – Ethernet Modul – Temperatur Messung mit Alarm – Teil 2

Und weiter gehts...

Liebe Maker-Freunde, willkommen zurück zum zweiten Teil unseres ENC28J60 Blog-Beitrags. 
Wie im ersten Teil angekündigt, soll die Schaltung mit einem besseren Temperatur- und Luftfeuchtesensor sowie einem 0,91″ OLED Display ausgestattet werden. 
Der geneigte Leser mag sich nun fragen: Wieso ein anderer Temperatur- und Luftfeuchtesensor?
Rein vom Datenblatt her sollte der im ersten Teil verbaute DHT11 doch ausreichend sein!? Eine Abweichung von +-2°C bei der Temperatur und ein Delta von 5% auf die relative Luftfeuchte (das macht bei angenommener Luftfeuchte von 40% rel. eine Abweichung von +- 2%) sollten doch ausreichend genau sein.

Vorweg - die Bauteile...

Um den zweiten Teil dieser Blogreihe umzusetzen, werden die folgenden (Bau)teile benötigt:

Wer misst misst Mist...

Nachdem ich die Schaltung aus dem ersten Teil des Blogs einige Zeit im Betrieb hatte, bekam ich Zweifel an den angezeigten Messwerten für die Temperatur und die rel. Luftfeuchte. Um mir Gewissheit zu verschaffen, kramte ich einen weiteren DHT11 Sensor von einem anderen Hersteller (Elegoo) aus einer meiner Kisten und schloss diesen an. Bis auf eine geringe Abweichung im Nachkomma-Bereich waren die Ergebnisse aber identisch. Trotzdem… das konnte nicht stimmen, zumal meine parallel aufgestellte Wetterstation auch andere Werte anzeigte.

Also entschloss ich mich, einen weiteren Vergleich mit sowohl einem BME280 als auch einem BME680 zu machen.

Wie man dem nebenstehenden Screenshot der seriellen Konsole der Arduino Entwicklungsumgebung entnehmen kann, waren die Abweichungen zwischen dem DHT11 Sensor und dem BME280 erheblich. Beim Vergleich mit einem BME680 zeichnete sich ein sehr ähnlich schlechtes Bild ab.

DHT11 – der Sensor musste weg…

Der Sensortausch...

Der Sensor

Beim BME280 handelt es sich um einen Temperatur-, Luftfeuchte- und Luftdrucksensor, welcher von Bosch entwickelt wurde.
Der Sensor ist extrem klein: nur 2,5 x 2,5 x 0,9 mm und sehr akkurat in der Auflösung.
Temperaturbereich: -40°C bis 85°C bei +- 1°C
Luftfeuchtebereich: 0% bis 100% rel. bei +- 3%
Luftdruckbereich: 300hPa bis 1100hPa bei +- 1hPa

Auf Grund der hohen Genauigkeit bei der Luftdruckmessung kann der Sensor auch als Höhenmesser eingesetzt werden. Der Messbereich ist 0 bis 9000 Meter, die Genauigkeit beträgt hier 1 Meter auf 400 Meter Höhenunterschied.

Das Datenblatt und detaillierte Infos zu diesem Sensor findet man auf den Seite von Bosch:
https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/

Das Breakout Modul

Normalerweise arbeitet der BME280 Sensor für die Spannungsversorgung mit einem Spannungsbereich von 1.71V … 3.6V.
An den IO Pins beträgt der Spannungsbereich 1.2V … 3.6V.
Das üblicherweise gelieferte GYBMEP Breakout Board kommt jedoch mit einem LM6206 3.3V Regler und einem Spannungspegel Wandler für die I2C Schnittstelle. Damit kann das Breakout Board problemlos an allen üblichen Microcontrollern wie Arduino, ESP oder Raspi eingesetzt werden.

Die Verkabelung

Der BME280 wird per I2C Schnittstelle an den Arduino angeschlossen. VCC und GND Pin gehen an die entsprechenden Pins des Arduino, SCL des Sensors geht an Pin A5, SDA geht an Pin A4.

Die BME280 Bibliothek

Um programmatisch auf den BME280 Sensor zugreifen zu können, brauchen wir eine entsprechende Bibliothek. Schnell und einfach geht dies mit der Bibliothek von Adafruit, welche wir über die Bibliotheks-Verwaltung einfach installieren können. An einigen Stellen liest man immer wieder, dass man nach dem Installieren der Bibliothek die I2C Adresse für den Sensor in der Bibliothek anpassen muss. Dies ist bei der Adafruit Library so nicht notwendig. Diese berücksichtigt beide üblichen I2C Adressen des Sensors automatisch. 

Das Display

Zum Einsatz kommt ein 0,91″ Display mit einer Auflösung von 128×32 Pixel. Angesteuert wird das Display über die I2C Schnittstelle mit Hilfe des SSD1306 Standard Controllers. 

Die SSD1306 Bibliothek

Da der Arduino Nano nicht über sonderlich viel Speicher verfügt, müssen wir beim Einsatz der verwendeten Bibliotheken aufpassen, wie viele unserer kostbaren Ressourcen diese verbrauchen. Für die Anzeige der Temperatur und der Luftfeuchtigkeit reicht mir in diesem Projekt die reine Textdarstellung. Daher entscheide ich mich für den Einsatz der SSD1306Ascii Bibliothek – eine schlanke, ressourcensparende Bibliothek zum Ansteuern von Displays mittels des SSD1306 Controllers. Die Installation erfolgt, wie immer, über die Bibliotheksverwaltung in der Arduino IDE. 

Die Verkabelung

Das OLED Display wird per I2C Schnittstelle an den Arduino angeschlossen. VCC und GND Pin gehen an die entsprechenden Pins des Arduino, SCL des Displays geht an Pin A5, SDA geht an Pin A4.

Der neue Sketch

Nachdem wir den DHT11 Sensor durch einen BME280 getauscht und anschließend noch ein OLED Display zur Anzeige der Werte angeschlossen haben, müssen wir auch unseren Sketch dahingehend anpassen. Wir entfernen also aus dem Sketch alle Code-Zeilen zum DHT11 und binden die entsprechenden Libraries für BME280 und OLED Display ein. 

RAM! Wir brauchen mehr RAM...

Wie schon erwähnt, verfügt der Nano nicht über sonderlich viel RAM… sprich: Wir stoßen hier schnell an die Grenzen der Ressourcen dieses kleinen Microcontrollers. Dies zeigte sich, als ich den Sketch nach den Anpassungen das erste Mal in der Arduino IDE kompilieren ließ. 

Ich lud den Sketch trotzdem auf den Microcontroller und ließ ihn einige Zeit laufen. Zunächst schien noch alles normal. Bei einer länger anhaltenden Temperatur-Über- oder Unterschreitung oder einer Über- oder Unterschreitung der Luftfeuchte-Schwellwerte, wurde ein IFTTT Event ausgelöst und eine Email mit den entsprechenden Hinweisen gesendet… 

Sobald dieser Sketch jedoch längere Zeit lief, kam es zu „Aussetzern“ und trotz erreichen der Alarmschwellen, wurde keine entsprechende Email versendet.

Im seriellen Monitor der Arduino IDE konnte man erkennen, dass es zwar noch zu der Ausgabe der Serial.println(„“) Meldung kommt, dass der IFTTT Event jetzt aufgerufen werden soll, aber es wird kein HTTP Request mehr erzeugt, oder abgesetzt. 

Ich habe dies auf das knapp werdende RAM des Arduino „geschoben“.

Das F-Makro

Um jetzt ein wenig Speicher zu sparen, soll das sogenannten F-Makro zum Einsatz kommen. Zeichenketten werden normal im RAM abgelegt. Man kann jedoch ein F() darum schreiben. Dies hat zur Folge, dass diese im Flash Speicher abgelegt werden. Bei der print/println Ausgabe von Variablen kann das F-Makro nicht eingesetzt weden. 

Beispiel: Serial.println(F(„Hallo!“));

Dies habe ich bei allen fixen Zeichenketten in meinen print und println Anweisungen durchgeführt. Anschließend habe ich den Sketch neu kompilieren lassen und es sah RAM-technisch etwas besser aus. 

Der Sketch lief darauf hin testweise mehrere Tage fehlerfrei durch.


// 2020-07-11 ENC28J60 V1 - Extended Setup
// (c) Markus Pohle @Creative Commons BY-NC-SA
// https://en.wikipedia.org/wiki/File:Cc-by-nc-sa_icon.svg
// 
// UIPEthernet und BME280 und OLED Display
//
// Ethernet
#include <UIPEthernet.h>
// Ethernet Konfigparameter
EthernetClient client;
uint8_t mac[6] = {0xaa,0xbb,0xcc,0xdd,0xee,0xff};
char server[] = "maker.ifttt.com";
// OLED Display
#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C
// Define proper RST_PIN if required.
#define RST_PIN -1
SSD1306AsciiWire oled;
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
Adafruit_BME280 bme; // I2C
// Schwellwertzähler
static uint32_t highCount = 1;
static uint32_t sentTimer = 0;

void setup()
{
  Serial.begin(9600); // Öffne serielle Schnittsatelle
  Wire.begin();
  Wire.setClock(400000L);
#if RST_PIN >= 0
  oled.begin(&Adafruit128x32, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x32, I2C_ADDRESS);
#endif // RST_PIN >= 0
  oled.setFont(Adafruit5x7);
  oled.set1X();
  Serial.println(F("BME280 Init..."));
  unsigned status;
  
  status = bme.begin();  
  if (!status) {
    Serial.print(F("BME280 ERROR!"));
    oled.clear();
    oled.setCursor(0, 0);
    oled.print(F("Sensor Error!"));
    while(true);
  }
  Serial.println("ENC28J60 Init...");
  if(Ethernet.begin(mac) == 0){
    Serial.println(F("Failed to configure Ethernet using DHCP"));
    oled.clear();
    oled.setCursor(0, 0);
    oled.print(F("DHCP Network Error!"));
    while(true); // kein Netzwerk? Dann Ende!
  }
  Serial.print(F("localIP: "));
  Serial.println(Ethernet.localIP());
  oled.clear();
}
void loop()
{
  float h = bme.readHumidity();
  float t = bme.readTemperature();
  
  oled.setCursor(0, 0);
  oled.print(F("Temperatur: "));
  oled.print(t);
  oled.println(F(" *C"));
  oled.setCursor(0, 2);
  oled.print(F("Luftfeuchte: "));
  oled.print(h);
  oled.println(F(" %"));
  if ( t > 27 || t < 18 || h > 55 || h < 35 )
    highCount++;
  else
    highCount = 1;
  Serial.print(F("High Count: ")); Serial.println(highCount);
    
  // Nur, wenn der Schwellwert mehr als eine Minuten ansteht wird alarmiert - verhindert flappen
  // Modulo 13, weil Variable highCount initial 1 ist - wäre highCount zu Beginn 0, wäre hC % 12 == 0 sofort TRUE
  if (highCount % 13 == 0) {
    if (millis() > sentTimer) { // prüft ob seit dem letzten HTTP GET Request mehr als 10 Min vergangen sind
      highCount < 780 ? sentTimer = millis() + 600000 : sentTimer = millis() + 3600000;
      //sentTimer = millis() + 600000;
      Serial.println("Sende an IFTTT");
      if (client.connect(server,80)) {
        client.print(F("GET /trigger/RZTemp/with/key/wD37A*****************************jlN?value1="));
        client.print(t);
        client.print(F("&value2="));
        client.print(h);
        client.println(F(" HTTP/1.1"));
        client.println(F("Host: maker.ifttt.com"));
        client.println();
      }
          
      while(client.connected()) {
        if(client.available()) {
          char c = client.read();
          Serial.print(c);  
        }
      }
    }
    else
      highCount < 780 ? Serial.println(F("max. alle 10 Minuten ein Alarm...")) : Serial.println(F("max. alle 60 Minuten ein Alarm...")); 
  }
  delay(5000);  
}
 

Der Zusammenbau + das Gehäuse

Nachdem die Schaltung nun einige Tage auf dem Steckbrett lief, war es Zeit, sie auf eine Lochrasterplatine zu bringen und in ein Gehäuse zu packen. In der nachfolgenden Foto-Strecke zeige ich den Zusammenbau der einzelnen Komponenten auf der Lochrasterplatine. Die Fotos sind, denke ich, selbsterklärend. Welche Teile für den Zusammenbau benötigt werden, habe ich am Anfang des Artikels bereits aufgeführt. Am Ende drucke ich noch ein Gehäuse auf dem 3D Drucker.

Die .stl Druckdateien für den Slicer

Gehäuse-Körper: https://cloud.pohle.it/index.php/s/kcWrwEzb2gFNTnz

Gehäuse-Deckel: https://cloud.pohle.it/index.php/s/RmW5gMKp64HoXRQ

Viel Spaß beim Nachbauen 🙂

Kommentar verfassen

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