Kabellose Wetterstation

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen

WS 23/24: Fachpraktikum Elektrotechnik (MTR) und Angewandte Elektrotechnik (BSE)
Autor: Daniel Hilgers & Daniel Block
Betreuer: Prof. Dr.-Ing. Schneider


Einleitung

Dieses Projekt ist Teil des GET-Fachpraktikums und hat zum Ziel, wettertechnische Messdaten wie Temperatur und Luftfeuchtigkeit zu erfassen. Zur Umsetzung dieses Vorhabens werden zwei Arduino-Plattformen verwendet. Deren drahtlose Kommunikation miteinander ermöglicht die Übermittlung der Messdaten zu einer Innenraum-Station. Beide Arduinos werden in ein speziell dafür 3D-gedrucktes Gehäuse integriert, wobei das Außengehäuse wasserabweisende Eigenschaften aufweisen muss, um vor Regen geschützt zu sein und Feuchtigkeitsschäden zu vermeiden. Sowohl die Außenstation als auch die Inneneinheit erfassen Messdaten. Die gesammelten Daten von beiden Stationen werden auf der im Haus befindlichen Einheit miteinander dargestellt. Die gesamte Programmierung der Arduinos erfolgt mithilfe von Matlab Simulink.

Anforderungen

Teilanforderungen
Nr. Beschreibung Bereich Zuständigkeit
1 Das Gehäuse für die Außenstation muss wetterfest sein. Hardware Block, Hilgers
2 Die Reichweite der Wetterstation soll mindestens 10 Meter durch Wände betragen. Hardware Block, Hilgers
3 Das Außensystem muss mit einem Akku betrieben werden. Hardware Block, Hilgers
4 Das Innensystem soll mit einem kabelgebundenen Netzteil betrieben werden. Hardware Block, Hilgers
5 Die Wetterstation muss Temperatur, Luftfeuchtigkeit, Luftdruck und Windgeschwindigkeit messen. Hardware/Software Block, Hilgers
6 Das Programm Simulink muss für die Programmierung verwendet werden. Software Block, Hilgers
7 Die Messdaten müssen auf einem Display in Echtzeit angezeigt werden. Software Block, Hilgers
8 Die Messdaten sollen spätestens alle 15 Minuten aktualisiert werden. Software Block, Hilgers
9 Die Messdaten sollen gespeichert und über die Zeit dargestellt werden. Software Block, Hilgers
10 Die Wetterstation soll folgende Prognosen anzeigen: gefühlte Temperatur, Hitzeindex, Taupunkt. Software Block, Hilgers

Funktionaler Systementwurf/Technischer Systementwurf

Im folgenden Systementwurf wird das Projekt in Systemkomponenten unterteilt:

  • Arduino: Der Mikrocontroller führt den Code aus.
  • Display: Auf dem Display werden die Wetterdaten der Innen- und Außenstation nebeneinander dargestellt.
  • Temperatur und Feuchtigkeitssensor: Dieser Sensor ermittelt Temperatur und Feuchtigkeitsdaten und gibt sie an den Arduino weiter.

Der DHT22, auch bekannt als AM2302, ist ein einfacher und preiswerter Sensor zur Messung von Luftfeuchtigkeit und Temperatur, der zur Erfassung von Temperatur- und Feuchtigkeitsdaten dient.

Feuchtigkeitssensor: Der DHT22 nutzt einen kapazitiven Feuchtigkeitssensor, aus einem hygroskopischen Material. Die elektrische Kapazität dieses Materials ändert sich in Abhängigkeit von der Luftfeuchtigkeit. Bei steigender Luftfeuchtigkeit bindet das Material mehr Wasserdampf, was zu einer Veränderung seiner Kapazität führt.
Temperatursensor: Für die Temperaturmessung verwendet der DHT22 einen Thermistor, einen Widerstand, dessen elektrischer Widerstand sich mit der Temperatur ändert. Typischerweise sinkt der Widerstand eines Thermistors mit steigender Temperatur.
Signalverarbeitung: Der Sensor besitzt eine integrierte Schaltung, die die Änderungen der Kapazität und des Widerstands in elektrische Signale umwandelt. Diese Signale werden anschließend digitalisiert.
Digitale Signalumwandlung: Der DHT22 wandelt die von den Feuchtigkeits- und Temperatursensoren kommenden analogen Signale in digitale Form um, was durch einen internen Analog-Digital-Umsetzer (ADC) erreicht wird.
Kommunikationsschnittstelle: Der Sensor verwendet eine einzelne Drahtschnittstelle zur Datenübertragung. Für den Anschluss an einen Mikrocontroller wird neben VCC für die Stromversorgung und GND für die Erdung nur ein Datenpin benötigt.


  • Anemometer: Misst die aktuelle Windgeschwindigkeit
  • Barometer: Misst den aktuellen Luftdruck am Gerät

Der BMP280 ist ein digitaler Druck- und Temperatursensor, der von Bosch Sensortec hergestellt wird. Er nutzt ein piezoresistives Design für die Luftdruckmessung.
Piezoresistiver Drucksensor: Im Herzen des BMP280 befindet sich ein piezoresistiver Sensor, ein kleiner Chip mit einer druckempfindlichen Membran. Diese Membran ist so konzipiert, dass sie sich bei Änderungen des Luftdrucks leicht verbiegt.
Widerstandsänderung: Die Membran ist mit piezoresistiven Materialien verbunden, die ihren elektrischen Widerstand in Abhängigkeit von der mechanischen Deformation ändern. Bei Biegung der Membran durch Luftdruckänderungen ändert sich der Widerstand dieser Materialien. Der BMP280 erfasst diese Widerstandsänderungen und wandelt sie mithilfe eines Analog-Digital-Umsetzers (ADC) in ein digitales Signal um.
Temperaturkompensation: Da der Widerstand der Sensormaterialien auch temperaturabhängig ist, misst der BMP280 zusätzlich die Temperatur, um die Druckmessungen zu korrigieren und genauere Ergebnisse zu erzielen.
Digitale Signalverarbeitung: Der Sensor beinhaltet einen Mikroprozessor, der die digitalen Signale weiterverarbeitet. Dies umfasst die Anwendung von Kalibrierungsdaten zur Genauigkeitssteigerung und die Berechnung des Luftdrucks in Pascal oder anderen Einheiten.
Kommunikation mit Mikrocontrollern: Schließlich sendet der BMP280 die Druck- und Temperaturdaten über eine I2C- oder SPI-Schnittstelle an einen angeschlossenen Mikrocontroller, wodurch die Daten in verschiedenen Anwendungen wie Wetterstationen, Smartphones, Drohnen und anderen genutzt werden können.


  • Echtzeituhr: Dieser Baustein gibt die reale Zeit an den Arduino weiter.
  • Spannungsversorgung: Versorgt die jeweilige Station.
  • Funk- und Empfängermodul: Ermöglicht die Kommunikation der beiden Stationen und lässt einen kabellosen Datenaustausch zu.


Abbildung 3.1: Funktionaler Systementwurf - Skizze Datei:Systementwurf PowerPoint.pptx
Abbildung 3.2: Technischer Systementwurf - Skizze Datei:Systementwurf PowerPoint.pptx


Komponentenspezifikation

Komponentenliste
Nr. Komponentenbezeichnung Beschreibung Anzahl Bild Preis
1 Arduino MEGA
  • ATmega2560 Prozessor
  • Versorgungsspannung: 7V-12V (empfohlen)
  • Betriebsspannung: 5V
  • 54 digitale Ein-/Ausgänge und 16 analoge Eingänge
2x
mini
mini
[1]
1x 72,90€ im Funduino Starter Paket + 1x 23,99€
2 DHT22 AM2302 Temperatursensor und Luftfeuchtigkeitssensor
  • Betriebsspannung: 3,3 V bis 5,5 V
  • Temperatur:
  • Messbereich: -40 bis +80°C
  • Genauigkeit: ± 0,5 ° C
  • Feuchtigkeit:
  • Genauigkeit: ± 2 % rF
2x
mini
mini
[2]
2x 4,33€
3 NRF24L01+, PA + LNA Wireless Modul
  • Spannungsversorgung: 3-3.6V
  • max. Ausgangsleistung: +20 dBm
  • 1100m Reichweite
2x
mini
mini
[3]
2x 4,11€
4 NRF24L01 Adapter
  • Betriebsspannung: 4,8V bis 12V
  • Stabile Spannungsversorgen für NRF24L01+
2x
mini
mini
[4]
1x 4,49€ als Dreierset
5 GY-BMP280 Barometrischer Sensor
  • Luftdruck-Sensor
  • Betriebsspannung: 1.8 - 5V
  • Ansteuerung über I2C bzw. SPI
  • Luftdruck: Unsicherheit von ±1 hPa
1x
mini
mini
[5]
6,79€
6 DS3231 Echtzeituhr
  • Betriebsspannung: 3,3V
  • Kommunikationsschnittstelle: I2C
1x
mini
mini
[6]
5,10€
7 3,5" TFT-LCD-Display-Modul 480x320
  • Betriebsspannung: 2.8 - 3.3V
  • Bildschirmgröße: 3,5 Zoll
  • Mit Touch-Panel
1x
mini
mini
[7]
15,12€
8 Anemometer
  • Durchmesser: 215 mm
  • Halbkugeldurchmesser: 65 mm
  • Ausgangsspannung: 0V - 2V
  • Auswertung des Signals: Windgeschwindigkeit (m/s) = Spannung (V) x 25
1x
mini
mini
[8]
30,80€
9 18650 Battery Expansion Shield
  • Input-Anschluss: Micro USB, Weitspannungseingang bis zu 6,5V
  • Input-Anforderungen: 5V Konstantspannungs-Netzteil, geeignetes Ladegerät 5V/1A oder höher
  • Output-Anschluss: USB- oder Erweiterungsanschluss
  • Output: 3V und 5V
1x
mini
mini
[9]
8,90€
10 18650 Li-Ion-Akku
  • Kapazität: 3400mAh
  • Nennspannung: 3,6V
1x
mini
mini
[10]
6,64€
11 Außengehäuse
  • 3D gedruckt
  • Material: ASA Kunststoff
  • Wetterfest
1x
mini
mini
n.A.
12 Innengehäuse
  • 3D gedruckt
  • Material: PLA Kunststoff
1x
mini
mini
n.A.


Weiteres Verbrauchsmaterial wie unter anderem das verwendete Werkzeug, Schrauben, PLA, ASA und Löteinsätze wurden aus dem privaten Inventar entnommen und fallen somit nicht in die Kostenrechnung.

Umsetzung (HW/SW)

Hardware

Projektübersicht:

In unserem Projekt zur Entwicklung einer kabellosen Wetterstation spielt die Konzeptionierung und Klärung der designtechnischen Aufgaben der Gehäuse für den Innen- und Außenbereich eine zentrale Rolle. Die zu entwerfenden Gehäuse sind nicht nur Behältnisse für die Elektronik, sondern erfüllen auch entscheidende funktionale Anforderungen, um die Langlebigkeit und Zuverlässigkeit der Wetterstation zu gewährleisten.

Auswahl der Sensoren:

DHT22:

Der DHT22 Sensor ist ein weit verbreiteter, kosteneffizienter digitaler Sensor zur Messung von Temperatur und Luftfeuchtigkeit. Er zeichnet sich durch seine Kompatibilität mit verschiedenen Mikrocontrollern und seine präzisen Messergebnisse aus. Der Sensor findet Anwendung in verschiedenen Bereichen wie Wetterstationen, Klimakontrollsystemen und medizinischen Geräten.

Komponenten des DHT22:

-NTC-Temperatursensor:
-Funktionsweise: Ändert seinen elektrischen Widerstand in Abhängigkeit von der Temperatur. Eigenschaften: Der Widerstand nimmt mit steigender Temperatur ab.
-Feuchtigkeitskondensator:
-Funktionsweise: Misst die relative Luftfeuchtigkeit basierend auf einem Material als Dielektrikum, welche seine Dielektrizitätszahl in Abhängigkeit von der Feuchtigkeit ändert. Eigenschaften: Die Kapazität des Kondensators variiert mit dem Feuchtigkeitsgehalt der Luft.
-8-Bit-Mikrocontroller-IC:
-Funktionsweise: Verarbeitet die Signale von den Temperatur- und Feuchtigkeitssensoren und konvertiert diese in digitale Signale. Eigenschaften: Ermöglicht die Übertragung der Daten über eine digitale Schnittstelle an externe Mikrocontroller.

Merkmale und Anwendungen:

-Einfache Handhabung: Der DHT22 ist benutzerfreundlich und leicht zu integrieren. Kompatibilität: Funktioniert reibungslos mit einer Vielzahl von Mikrocontrollern. Genauigkeit: Bietet hohe Genauigkeit bei der Messung von Temperatur (±0,5°C) und Luftfeuchtigkeit (±2-5% RH).

BMP280:

Der BMP280, entwickelt von Bosch, ist ein kompakter, hochpräziser und kostengünstiger Sensor, der sowohl Druck- als auch Temperaturmessungen durchführt. Er ist speziell für mobile Anwendungen wie Smartphones, GPS-Geräte und Wearables konzipiert, findet jedoch auch in einer Vielzahl anderer Projekte Verwendung.

Komponenten des BMP280:

-Drucksensor:
-Funktionsweise: Nutzt ein piezoresistives Element, das seinen Widerstand je nach Druck ändert. Anwendung: Ideal für Höhenmessungen in Projekten wie Drohnen, Wetterstationen und Handgeräten zur Navigation, da der Luftdruck mit der Höhe variiert.
-Temperatursensor:
-Funktionsweise: Misst die Umgebungstemperatur und dient der Temperaturkompensation der Druckmessungen. Vorteile: Erhöht die Genauigkeit der Druckmessungen.

Merkmale und Anwendungen:

-Digitale Schnittstellen (I2C und SPI):
-Eigenschaften: Ermöglichen eine einfache und schnelle Datenübertragung an Mikrocontroller oder Mikroprozessoren.
-Kompakte Größe und geringer Energieverbrauch:
-Vorteile: Macht den Sensor ideal für mobile und batteriebetriebene Anwendungen.
-Hohe Präzision und Auflösung:
-Ergebnis: Führt zu genauen und zuverlässigen Druck- und Temperaturmessungen (± 1 hPa).

Innengehäuse Design:

Für den Innenbereich wird das Gehäuse um ein 3,5-Zoll-Display entworfen, das die Lesbarkeit der Wetterdaten sicherstellt. Es enthält auch ein Empfänger-Modul, Sensoren für Temperatur und Feuchtigkeit sowie eine Echtzeituhr, die alle innerhalb des Gehäuses geschützt sind. Die Benutzerfreundlichkeit und Ästhetik stehen hier im Vordergrund, wobei das Gehäuse auch eine gute Belüftung und einfache Wartung ermöglichen muss.

Außengehäuse Design:

Das Gehäuse für den Außenbereich ist ohne Display gestaltet, beherbergt aber neben dem Funkmodul und den Temperatur- und Feuchtigkeitssensoren zusätzlich ein Anemometer und ein Barometer. Dieses Gehäuse erfüllt höhere Anforderungen im Bezug auf die Witterungsbeständigkeit, um die Technik vor den Elementen zu schützen. Hier kommt das Material ASA (Acrylonitril-Styrol-Acrylester) ins Spiel, das sich durch seine hervorragende UV- und Witterungsbeständigkeit, Hitze- und Stoßfestigkeit als ideal für Außenanwendungen erweist.

Materialwahl und Verarbeitung:

Obwohl ASA in der Verarbeitung anspruchsvoller sein kann, überwiegen die Vorteile für den Außenbereich deutlich im Vergleich zu PLA. Wegen der potenziell gefährlichen Dämpfe während des Druckprozesses ist eine gute Belüftung unerlässlich. Außerdem müssen die gesteigerten Kosten und die nötigen höheren Extrudertemperaturen berücksichtigt werden und realisierbar sein.

Integration:

Ästhetisch soll das Design der Gehäuse das moderne und technische Wesen der Wetterstation widerspiegeln und sich harmonisch in die jeweilige Umgebung einfügen. Zusammengefasst bieten die durchdacht gestalteten Gehäuse eine optimale Balance zwischen Funktionalität und Widerstandsfähigkeit, wodurch die kabellose Wetterstation nicht nur ein nützliches, sondern auch ein ansprechendes Element im Wohn- oder Außenbereich darstellt.

Verdrahtungspläne:

Abbildung 5.1: Verbindungsplan der Außenstation Datei:Außenstation Fritzing.fzz
Abbildung 5.2: Verdrahtungsplan der Außenstation Datei:Außenstation Fritzing.fzz


Abbildung 5.3: Verdrahtungsplan der Außenstation Datei:Innenstation Fritzing.fzz
Abbildung 5.4: Verdrahtungsplan der Außenstation Datei:Innenstation Fritzing.fzz



Innenstation:

Abbildung 5.5: Linksseitige Ansicht der Innenstation in SolidWorks Datei:Innenstation Gehäuse ZIP.zip
Abbildung 5.6: Rechtsseitige Ansicht der Innenstation in SolidWorks Datei:Innenstation Gehäuse ZIP.zip


Abbildung 5.7: Erste Ansicht der Innenstation
Abbildung 5.8: Zweite Ansicht der Innenstation


Außenstation:

Abbildung 5.9: Linksseitige Ansicht der Außenstation in SolidWorks Datei:Außenstation Gehäuse.zip
Abbildung 5.10: Rechtsseitige Ansicht der Außenstation in SolidWorks Datei:Außenstation Gehäuse.zip


Abbildung 5.11: Erste Ansicht der Außenstation
Abbildung 5.12: Zweite Ansicht der Außenstation


Software

In der Entwicklung unseres Projekts spielte die Verwendung von MATLAB/Simulink eine zentrale Rolle. Um die spezifischen Anforderungen unseres Systems zu erfüllen, wurden zwei unterschiedliche Simulink-Modelle entwickelt. Diese Entscheidung ergab sich aus der Notwendigkeit, zwei separate Arduino-Controller zu steuern: einen für den Außenbereich und einen weiteren für den Innenbereich.

Um eine effiziente Integration mit den Arduino-Controllern zu gewährleisten, wurde das Simulink Support Package für Arduino eingesetzt. Dieses Paket ermöglichte es uns, die Funktionalität der Arduino-Hardware direkt in die Simulink-Umgebung zu integrieren, was eine nahtlose Interaktion zwischen unserer Software und der Hardware sicherstellte.

Ein entscheidendes Element unserer Softwareentwicklung war die Verwendung des Simulink S-Function Builder Blocks. Dieser Block spielte eine Schlüsselrolle, da er es uns ermöglichte, benutzerdefinierten C++-Code in unsere Simulink-Modelle zu integrieren. Durch diesen Ansatz konnten wir verschiedene Arduino-Bibliotheken nutzen, um spezifische Funktionen und Fähigkeiten unserer Hardware zu steuern und zu erweitern.

Für eine transparente Dokumentation und mögliche Weiterentwicklungen haben wir zudem den Quellcode der einzelnen S-Function Blöcke separat im Artikel beigefügt. Diese Dokumentation des Quellcodes erleichtert das Verständnis der Funktionsweise und ermöglicht es anderen Entwicklern, auf unserer Arbeit aufzubauen oder sie für ihre eigenen Projekte anzupassen.

Display Anzeige

Abbildung 5.13: Erste Seite des Displays
Abbildung 5.14: Zweite Seite des Displays
Abbildung 5.15: Dritte Seite des Displays


Programmablaufplan

Abbildung 5.16: Programmablaufplan der Außenstation Datei:Programmablaufplan Aussen ZIP.zip
Abbildung 5.17: Programmablaufplan der Innenstation Datei:Programmablaufplan Innen ZIP.zip

Innenstation

Touchdisplay Block
/* Includes_BEGIN */
/***************************************************************************
%                   Hochschule Hamm-Lippstadt                             *
//**************************************************************************
% Modul	          :                                                       *
%                                                                         *
% Datum           : 15.01.2024                                            *
%                                                                         *
% Funktion        : Treiberfunktionalität für den 3.5 Zoll Touch Display  *
%                 : + SD Karte                                            *
%                                                                         *
% Implementation  : MATLAB/Simulink 2023b                                 *
%                                                                         *
% Req. Toolbox    : ------                                                *
%                                                                         *
% Author          : Daniel Hilger und Daniel Block                        *
%                                                                         *
% Bemerkung       :                                                       *
%                                                                         *
% Letzte Änderung : 15-Jan-2024                                           *
%                                                                         *
%**************************************************************************/
#ifndef MATLAB_MEX_FILE

#define ARDUINO 101

#include "Adafruit_GFX.h"
#include "MCUFRIEND_kbv.h"
#include "TouchScreen.h"
#include "Grafici.h"

// Für SD Karte
#include "SPI.h"        
#include "SD.h"   
#include <ArduinoJson.h>

// Definition von Farbcodes für die Verwendung in Grafiken oder auf dem Display.
// Diese Werte entsprechen den 16-Bit-Farbcodes, die von vielen Grafikbibliotheken verwendet werden.
constexpr uint16_t BLACK       { 0x0000 };
constexpr uint16_t NAVY        { 0x000F };
constexpr uint16_t DARKGREEN   { 0x03E0 };
constexpr uint16_t DARKCYAN    { 0x03EF };
constexpr uint16_t MAROON      { 0x7800 };
constexpr uint16_t PURPLE      { 0x780F };
constexpr uint16_t OLIVE       { 0x7BE0 };
constexpr uint16_t LIGHTGREY   { 0xC618 };
constexpr uint16_t DARKGREY    { 0x7BEF };
constexpr uint16_t BLUE        { 0x001F };
constexpr uint16_t GREEN       { 0x07E0 };
constexpr uint16_t CYAN        { 0x07FF };
constexpr uint16_t RED         { 0xF800 };
constexpr uint16_t MAGENTA     { 0xF81F };
constexpr uint16_t YELLOW      { 0xFFE0 };
constexpr uint16_t WHITE       { 0xFFFF };
constexpr uint16_t ORANGE      { 0xFD20 };
constexpr uint16_t GREENYELLOW { 0xAFE5 };

// Pinzuweisungen für den Touchscreen.
constexpr uint8_t YP { A1 };
constexpr uint8_t XM { A2 };
constexpr uint8_t YM { 7 };
constexpr uint8_t XP { 6 };

// Kalibrierungswerte für den Touchscreen.
constexpr int TS_LEFT { 924 };
constexpr int TS_RT   { 150 };
constexpr int TS_TOP  { 958 };
constexpr int TS_BOT  { 139 };

// Druckschwellenwerte für Touchscreen-Interaktionen.
constexpr int MINPRESSURE { 200 };
constexpr int MAXPRESSURE { 1000 };

// Initialisierung des Display-Objekts.
MCUFRIEND_kbv tft;

// Initialisierung des TouchScreen-Objekts mit den zuvor definierten Pins und einem Widerstandswert.
TouchScreen ts { TouchScreen(XP, YP, XM, YM, 300) };
// Initialisierung eines Grafikobjekts, das für die Anzeige des Plots auf dem Display verwendet wird.
Grafici plot{ tft };
// Dateiobjekt für die Interaktion mit der SD-Karte.
File myFile;
// Allocate the JSON document
const int capacity = 1024;

// Weitere Variablen für die Anzeigesteuerung.
int displayState = 0;
int refresh = 1;
// Struktur zur Speicherung von Sensordaten.
struct SensorData {
    uint32_t time;
    float temp;
    float otemp;
};
// Variablen für die JSON-Verarbeitung.
bool firstRunJson = true;
uint32_t previousTime = 0;
uint32_t newTime = 0;
// Funktion zum Deserialisieren von JSON-Daten aus einer Datei.
StaticJsonDocument<capacity> deserialize() {
    // Erstellen eines StaticJsonDocument-Objekts mit vorgegebener Kapazität.
    StaticJsonDocument<capacity> doc;
    
    myFile = SD.open("data.txt", FILE_READ);    // Öffnen der Datei 'data.txt' im Lese-Modus von der SD-Karte.
    deserializeJson(doc, myFile);               // Deserialisieren der JSON-Daten aus der Datei in das Dokument 'doc'.
    myFile.close();                             // Schließen der Datei nach der Verarbeitung.

    return doc;     // Rückgabe des deserialisierten Dokuments.
}
// Funktion zum Serialisieren und Speichern von Sensordaten in einer JSON-Datei.
void serialize(SensorData data) {
    StaticJsonDocument<capacity> doc;

    // if (firstRunJson) {
    //     JsonArray arr = doc.to<JsonArray>();
    //     firstRunJson = false;
    // }
    // else
    // {
    myFile = SD.open("data.txt", FILE_READ);
    deserializeJson(doc, myFile);
    myFile.close();
    // }
    
    // unsigned long secondsSinceMidnight = (((data.time % 86400) % 3600) / 60);

    // Serial.println(data.time);
    // Serial.println(secondsSinceMidnight);

    doc[data.time]["time"] = data.time;
    doc[data.time]["temp"] = data.temp;
    doc[data.time]["otemp"] = data.otemp;

    SD.remove("data.txt");
    myFile = SD.open("data.txt", FILE_WRITE);
    if(myFile) {
        serializeJsonPretty(doc, myFile);
        myFile.close();
    }
    else
    {
        Serial.print("failed to write to txt");
    }
}
#endif
/* Includes_END */

/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */

void TouchDisplay_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    uint16_t ID { tft.readID() };       // Lesen der Identifikationsnummer des TFT-Displays.
    tft.begin(ID);                      // Starten des TFT-Displays mit der ausgelesenen ID.
    Serial.begin(9600);                 
    tft.setRotation(1);                 // Einstellen der Ausrichtung des TFT-Displays.
    tft.setTextSize(2);                 // Einstellen der Textgröße für das Display.
    tft.setTextColor(BLACK, WHITE);     // Festlegen der Textfarbe (hier Schwarz) und der Hintergrundfarbe (hier Weiß) für das Display.
    tft.fillScreen(WHITE);
    
    // Versuch, das SD-Kartenmodul zu starten, wobei '10' der Pin für das CS-Signal (Chip Select) ist.
    if (!SD.begin(10)) {
        Serial.print(F("cannot start SD"));
        while (1);
    }
    Serial.print("SD good");
#endif
/* Start_END */
}

void TouchDisplay_Outputs_wrapper(const real32_T *temp,
                                  const real32_T *humid,
                                  const uint32_T *time,
                                  const real32_T *windspeedoutside,
                                  const real32_T *tempoutside,
                                  const real32_T *humidoutside,
                                  const real_T *pressureoutside,
                                  const real32_T *heatindex,
                                  const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    int hours = time[0];                // Zuweisung der aktuellen Stunde aus dem Eingang "time". 
    
    SensorData data { hours, temp[0], tempoutside[0] };     // Initialisierung eines SensorData-Objekts.
    
    // Logik zur Aktualisierung der Zeitvariablen.
    if (newTime == 0 && previousTime == 0) {
        previousTime = hours;
        newTime = hours;
    }
    previousTime = newTime;
    newTime = hours;
    // Serialisieren und Speichern der Daten, wenn sich die Zeit geändert hat.
    if (previousTime != newTime)
        serialize(data);

    // Konfiguration und Zeichnen von der Menüleiste links
    tft.setTextSize(4);
    tft.setTextColor(WHITE, BLACK);
    tft.drawFastVLine(80, 0, tft.height(), BLACK);
    tft.fillRect(0, 0, 80, 80, BLACK);
    tft.setCursor(30, 20);
    tft.print("1");
        
    tft.fillRect(0, 120, 80, 80, BLACK);
    tft.setCursor(30, 140);
    tft.print("2");

    tft.fillRect(0, 240, 80, 80, BLACK);
    tft.setCursor(30, 260);
    tft.print("3");
    tft.setTextSize(2);
    tft.setTextColor(BLACK, WHITE);

    // Anzeigen von Sensordaten auf dem Display, abhängig vom Zustand des Displays.
    if (displayState == 0) {                     // Anzeige von Innenraumdaten.
        tft.setCursor(400, 20);
        tft.drawRect(390, 10, 80, 35, BLACK);
        tft.print("Innen");

        tft.setCursor(90, 20);
        tft.print("Temperatur: ");
        tft.print(temp[0]);
        tft.print(" Grad C");
    
        tft.setCursor(90, 60);
        tft.print("Luftfeuchtigkeit: ");
        tft.print(humid[0]);
        tft.print(" %");
    
        tft.drawFastHLine(80, 100, tft.width(), BLACK);
    
        tft.setCursor(400, 120);
        tft.print("Aussen");
        tft.drawRect(390, 110, 85, 35, BLACK);

        tft.setCursor(90, 120);
        tft.print("Temperatur: ");
        tft.print(tempoutside[0]);
        tft.print(" Grad C");
    
        tft.setCursor(90, 160);
        tft.print("Luftfeuchtigkeit: ");
        tft.print(humidoutside[0]);
        tft.print(" %");
    
        tft.setCursor(90, 200);
        tft.print("Luftdruck: ");
        tft.print(pressureoutside[0]);
        tft.print(" Bar");
    
        tft.setCursor(90, 240);
        tft.print("Windgeschwindigkeit: ");
        tft.print(windspeedoutside[0]);
        tft.print(" m/s");

    } else if (displayState == 1) {             // Anzeige von Daten in dem Plot (Temperaturverlauf der letzten 24 Stunden)
    
        if (refresh == 1) {
            refresh = 0;
            tft.fillRect(81, 0, 400, 320, WHITE);
            tft.setTextSize(2);
           
            StaticJsonDocument<capacity> doc;
            myFile = SD.open("data.txt", FILE_READ);
            deserializeJson(doc, myFile);
            myFile.close();
    
            float temp[24] {};
    
            for (int i = 0; i < 24; i++) {          // Anpassen der Wrte in dem Array, passend für die aktuelle Stunde
                temp[i] = doc[(hours + 25 + i) % 24]["temp"];
            }

            for (int i = 0; i < 24; i++) {
                temp[i] = (temp[i] + 21) * 0.38; // Umrechnung damit der Graph richtig skaliert auf dem Koordinatensystem liegt
            }
            float otemp[24] {};
            for (int i = 0; i < 24; i++) {          // Anpassen der Wrte in dem Array, passend für die aktuelle Stunde
                otemp[i] = doc[(hours + 25 + i) % 24]["otemp"];
            }
            for (int i = 0; i < 24; i++) {
                otemp[i] = (otemp[i] + 21) * 0.38; // Umrechnung damit der Graph richtig skaliert auf dem Koordinatensystem liegt
            }
            // Erstellung der DataArrayXY Variablen. Werden für den Plot benötigt
            auto tempdata = DataArrayXY<float>(temp, 24, { 0, 24 });
            auto otempdata = DataArrayXY<float>(otemp, 24, { 0, 24 });

            // Zeichnen der Temperaturverläufe
            plot.line(tempdata.x(), tempdata.y(), black, { { 0.265, 0.93 }, { 0, 1 } });
            plot.line(otempdata.x(), otempdata.y(), blue, { { 0.265, 0.93 }, { 0, 1 } });
    
            int yAxisLength = tft.height() - 10; // Verschiebt das System um 10 Pixel nach oben
            int tempRange = 40 - (-20); // Temperaturbereich: 60 Grad
    
            // Berechnet die Pixel pro Grad
            int pixelsPerDegree = yAxisLength / tempRange;
            int yZero = pixelsPerDegree * 20; // Y-Position für 0 Grad
    
            // Zeichnet die X-Achse
            tft.drawFastHLine(125, yAxisLength - yZero, tft.width() - 125, BLACK);
    
            // Zeichnet die Y-Achse mit drawFastVLine
            tft.drawFastVLine(125, 0, yAxisLength, BLACK);
    
            // Zeichnet 24 Markierungen für die Stunden des Tages auf der X-Achse
            int xStart = 125;
            int xAxisLength = tft.width() - 125;
            int xStep = xAxisLength / 24; // Berechnet den Abstand zwischen den Markierungen
    
            int i = hours;
            for (int hour = 0; hour < 24; hour++) {
                int x = xStart + hour * xStep;
                tft.drawFastVLine(x, yAxisLength - yZero - 5, 10, BLACK); // Zeichnet die Markierung
                if (hour % 3 == 0) { // Optional: Beschriftung alle 3 Stunden
                    tft.drawFastVLine(x, yAxisLength - yZero - 10, 20, BLACK); // Zeichnet die Markierung für die langen striche
                    tft.setCursor(x - 6, yAxisLength - yZero + 15); // Setzt den Cursor für die Stunde
                    tft.print((hours + 25 + hour) % 24); // Druckt die Stunde
                }
            }
    
            // Zeichnet Markierungen und Beschriftungen für die Temperaturwerte auf der Y-Achse
            for (int temp = -20; temp <= 40; temp += 5) { // Schritte von 5 Grad
                int y = yAxisLength - (yZero + temp * pixelsPerDegree);
                tft.drawFastHLine(120, y, tft.width() - 125, BLACK); // Kleine Markierung für die Temperatur
                tft.setCursor(83, y - 7); // Setzt den Cursor für die Temperaturbeschriftung
                tft.print(temp); // Druckt den Temperaturwert
            }
    
            // Zeichnet die Überschrift
            tft.setTextSize(1);
            tft.setCursor(130, 5); // Positioniert den Cursor für die Überschrift
            tft.print("Temperatur in Grad Celsius"); // Druckt die Überschrift
            tft.setTextSize(2);
        }
        if (previousTime != newTime)
            refresh = 1;
    }
    else if (displayState == 2) {           // Anzeige von speziellen Klimadaten wie Taupunkt, Hitzeindex und gefühlte Temperatur.
        // Taupunkt Berechnung
        // Konstanten für die Berechnungsformel
        const double a = 17.27;
        const double b = 237.7;
        double alpha = ((a * tempoutside[0]) / (b + tempoutside[0])) + log(humidoutside[0] / 100.0);
        double Taupunkt = (b * alpha) / (a - alpha);
        
        tft.setCursor(90, 20);
        tft.print("Taupunkt: ");
        tft.print(Taupunkt);
        tft.print(" Grad C");

        tft.setCursor(90, 60);
        tft.print("Hitzeindex: ");
        tft.print(heatindex[0]);
        tft.print(" Grad C");

        int windchill = 13.12 + 0.6215 * tempoutside[0] - 11.37 * pow(windspeedoutside[0], 0.16) + 0.3965 * tempoutside[0] * pow(windspeedoutside[0], 0.16);
        tft.setCursor(90, 100);
        tft.print("Gefuehlte Temperatur: ");
        tft.print(windchill);
        tft.print(" Grad C");
    }
    // Erfassen von Touchscreen-Eingaben.
    TSPoint p { ts.getPoint() };
    
    long x, y;
    x = map(p.y, TS_LEFT, TS_RT, 0, 480);
    y = map(p.x, TS_TOP, TS_BOT, 0, 320);
    
    // Einstellen der Pinmodi für den Touchscreen.
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
    // Verarbeiten von Touchscreen-Eingaben und Ändern des Displayzustands basierend auf der Position des Touches.
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        Serial.print("x: ");
        Serial.print(p.x);
        Serial.print("\ty: ");
        Serial.print(p.y);
        Serial.print("\tPressure: ");
        Serial.println(p.z);
    
        // Ändern des Displayzustands abhängig von der Touch-Position.
        if (x < 80 && y > 240) {
            displayState = 0;
        } else if (x < 80 && y > 120 && y < 200) {
            displayState = 1;
            refresh = 1;
        } else if (x < 80 && y < 80) {
            displayState = 2;
        }
        // Bildschirm neuzeichnen bei Änderung des Displays
        tft.fillRect(81, 0, 400, 320, WHITE);
    }

#endif
/* Output_END */
}

void TouchDisplay_Update_wrapper(const real32_T *temp,
                                 const real32_T *humid,
                                 const uint32_T *time,
                                 const real32_T *windspeedoutside,
                                 const real32_T *tempoutside,
                                 const real32_T *humidoutside,
                                 const real_T *pressureoutside,
                                 const real32_T *heatindex,
                                 real_T *xD)
{
/* Update_BEGIN */

/* Update_END */
}

void TouchDisplay_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/*
 * Custom Terminate code goes here.
 */
/* Terminate_END */
}


nRF24L01_1 Wireless Modul (Empfänger)
/* Includes_BEGIN */
/* Includes_BEGIN */
/***************************************************************************
%                   Hochschule Hamm-Lippstadt                             *
//**************************************************************************
% Modul	          :                                                       *
%                                                                         *
% Datum           : 15.01.2024                                            *
%                                                                         *
% Funktion        : Treiberfunktionalität für NRF24L01+ als Empfänger     *
%                                                                         *
% Implementation  : MATLAB/Simulink 2023b                                 *
%                                                                         *
% Req. Toolbox    : ------                                                *
%                                                                         *
% Author          : Daniel Hilger und Daniel Block                        *
%                                                                         *
% Bemerkung       :                                                       *
%                                                                         *
% Letzte Änderung : 15-Jan-2024                                           *
%                                                                         *
%**************************************************************************/
#ifndef MATLAB_MEX_FILE

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>

RF24 radio(22, 23); // CE, CSN
// Erstellung des Structs, welches Empfangen wird
struct Data {
  float temp = 0;
  float humid = 0;
  double pressure = 0;
  float windspeed = 0;  
};
// Anlegen einer Variablen von dem Struct
Data data;
#endif
/* Includes_END */

/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */

void nRF24L01_1_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    // Definieren der Adresse für das NRF24L01 Modul. Diese Adresse wird verwendet, um Kommunikation zwischen zwei Modulen zu ermöglichen.
    const byte address[6] = "00001";
    // Starten des NRF24L01 Moduls.
    radio.begin();
    // Öffnen eines Lese-Kanals auf dem NRF24L01 Modul.
    // '0' ist die Nummer des Kanals und 'address' ist die Adresse des Kanals.
    radio.openReadingPipe(0, address);
    // Setzen der Leistungsstufe des Funkmoduls.
    // RF24_PA_HIGH ist eine hohe Leistungsstufe, die eine größere Reichweite ermöglicht, aber mehr Energie verbraucht.
    radio.setPALevel(RF24_PA_HIGH);
    // Starten des Zuhörmodus auf dem Funkmodul.
    // In diesem Modus kann das Modul Daten empfangen, die an seine Adresse gesendet werden.
    radio.startListening();
    #endif
/* Start_END */
}

void nRF24L01_1_Outputs_wrapper(real32_T *windspeed,
                                real32_T *temp,
                                real32_T *humid,
                                real_T *pressure,
                                const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    // Überprüfen, ob Daten vom NRF24L01 Modul verfügbar sind.
    if (radio.available()) {
        radio.read(&data, sizeof(Data)); // Read the whole data and store it into the 'data' structure
    }
    // Extrahieren der Messdaten aus der empfangenen 'data' Struktur und Ausgabe der einzelnen Messdaten
    temp[0] = data.temp;
    humid[0] = data.humid;
    pressure[0] = data.pressure;
    windspeed[0] = data.windspeed;

  
#endif
/* Output_END */
}

void nRF24L01_1_Update_wrapper(real32_T *windspeed,
                               real32_T *temp,
                               real32_T *humid,
                               real_T *pressure,
                               real_T *xD)
{
/* Update_BEGIN */

/* Update_END */
}

void nRF24L01_1_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/*
 * Custom Terminate code goes here.
 */
/* Terminate_END */
}


DS3231 Block ( Echtzeituhr)
/* Includes_BEGIN */
/***************************************************************************
%                   Hochschule Hamm-Lippstadt                             *
//**************************************************************************
% Modul	          :                                                       *
%                                                                         *
% Datum           : 15.01.2024                                            *
%                                                                         *
% Funktion        : Treiberfunktionalität für den DS3231 RTC              *
%                                                                         *
% Implementation  : MATLAB/Simulink 2023b                                 *
%                                                                         *
% Req. Toolbox    : ------                                                *
%                                                                         *
% Author          : Daniel Hilger und Daniel Block                        *
%                                                                         *
% Bemerkung       :                                                       *
%                                                                         *
% Letzte Änderung : 15-Jan-2024                                           *
%                                                                         *
%**************************************************************************/
#ifndef MATLAB_MEX_FILE
#include "DS3231.h"

// Deklaration der benötigten Variablen
DS3231 myRTC;
DateTime myDT;
#endif
/* Includes_END */

/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */

void DS3231_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    // I2C Funktionalität
    Wire.begin();
#endif
/* Start_END */
}

void DS3231_Outputs_wrapper(uint32_T *time,
                            const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    myDT = RTClib::now();   // Aktuelles Datum + Uhrzeit
    time[0] = myDT.hour();  // Ausgabe der aktuellen Stunde
#endif
/* Output_END */
}

void DS3231_Update_wrapper(uint32_T *time,
                           real_T *xD)
{
/* Update_BEGIN */

/* Update_END */
}

void DS3231_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/*
 * Custom Terminate code goes here.
 */
/* Terminate_END */
}


Innenstation

Abbildung 5.18: Simulink Modell Innenstation Datei:Wetterstation Innen ZIP.zip


Außenstation

Abbildung 5.19: Simulink Modell Außenstation Datei:Wetterstation Außen ZIP.zip


nRF24L01_1 Wireless Modul (Sender)
/* Includes_BEGIN */
/***************************************************************************
%                   Hochschule Hamm-Lippstadt                             *
//**************************************************************************
% Modul	          :                                                       *
%                                                                         *
% Datum           : 15.01.2024                                            *
%                                                                         *
% Funktion        : Treiberfunktionalität für NRF24L01+ als Sender        *
%                                                                         *
% Implementation  : MATLAB/Simulink 2023b                                 *
%                                                                         *
% Req. Toolbox    : ------                                                *
%                                                                         *
% Author          : Daniel Hilger und Daniel Block                        *
%                                                                         *
% Bemerkung       :                                                       *
%                                                                         *
% Letzte Änderung : 15-Jan-2024                                           *
%                                                                         *
%**************************************************************************/
#ifndef MATLAB_MEX_FILE

#define ARDUINO 100

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#include <Wire.h>

RF24 radio(7, 6); // CE, CSN
// Erstellung des Structs, welches gesendet wird
struct Data {
  float temp = 0;
  float humid = 0;
  double pressure = 0;
  float windspeed = 0;  
};
// Anlegen einer Variablen von dem Struct
Data sendData;

#endif
/* Includes_END */

/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */

void nRF24L01_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
    Serial.begin(9600);
    // Definieren der Adresse für das NRF24L01 Modul. Diese Adresse wird verwendet, um Kommunikation zwischen zwei Modulen zu ermöglichen.
    const byte address[6] = "00001";
    // Starten des NRF24L01 Moduls.
    radio.begin();
    // Öffnen eines Schreibkanals auf dem NRF24L01 Modul.
    // Die Verwendung von 'address' legt fest, an welche Adresse gesendet wird.
    radio.openWritingPipe(address);
    // Festlegen der Sendeleistung des Funkmoduls.
    // RF24_PA_HIGH ist eine hohe Leistungsstufe, die eine größere Reichweite ermöglicht.
    radio.setPALevel(RF24_PA_HIGH);
    // Beenden des Zuhörmodus.
    // Da das Modul in diesem Fall zum Senden von Daten verwendet wird, sollte es nicht gleichzeitig zuhören.
    radio.stopListening();
#endif
/* Start_END */
}

void nRF24L01_Outputs_wrapper(const real32_T *temp,
                              const real32_T *humid,
                              const real_T *pressure,
                              const real32_T *windspeed,
                              const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
    // Zuweisung von Sensordaten zu einer Struktur namens 'sendData'.
    // Diese Struktur wird dann über das NRF24L01 Modul gesendet.
    sendData.temp = temp[0];
    sendData.humid = humid[0];
    sendData.pressure = pressure[0];
    sendData.windspeed = windspeed[0];
    // Senden der 'sendData' Struktur über das NRF24L01 Funkmodul.
    // Die 'write' Funktion nimmt die Adresse der zu sendenden Daten und deren Größe.
    // Sie sorgt dafür, dass die gesamte Struktur korrekt übertragen wird.
    radio.write(&sendData, sizeof(Data));
#endif
/* Output_END */
}

void nRF24L01_Update_wrapper(const real32_T *temp,
                             const real32_T *humid,
                             const real_T *pressure,
                             const real32_T *windspeed,
                             real_T *xD)
{
/* Update_BEGIN */

/* Update_END */
}

void nRF24L01_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/*
 * Custom Terminate code goes here.
 */
/* Terminate_END */
}


S-Function Tutorial


Komponententest

Teilanforderungen
Nr. Beschreibung Testmethode Zuständigkeit Testergebnis
1 Das Gehäuse für die Außenstation muss wetterfest sein. Außenstation wurde für 2 Tage draußen bei Regen/Wind getestet. Block, Hilgers Bestanden
2 Die Reichweite der Wetterstation soll mindestens 10 Meter durch Wände betragen. Funkverbindung wurde über ca. 20m durch Wände hinweg getestet Block, Hilgers Bestanden
3 Die Außenstation muss mit einem Akku betrieben werden. Außenstation wird mit einer 18650 LiIon Akkuzelle betrieben. Block, Hilgers Bestanden
4 Die Innenstation soll mit einem kabelgebundenen Netzteil betrieben werden. Innenstation wird mit einem externen Netzteil betrieben. Block, Hilgers Bestanden
5 Die Wetterstation muss Temperatur, Luftfeuchtigkeit, Luftdruck und Windgeschwindigkeit messen. Die Wetterstation misst Temperatur, Luftfeuchtigkeit, Luftdruck und Windgeschwindigkeit. Block, Hilgers Bestanden
6 Das Programm Simulink muss für die Programmierung verwendet werden. Das Programm Simulink wurde für die Programmierung verwendet. Block, Hilgers Bestanden
7 Die Messdaten müssen auf einem Display in Echtzeit angezeigt werden. Die Messdaten werden auf einem Display in Echtzeit angezeigt. Block, Hilgers Bestanden
8 Die Messdaten sollen spätestens alle 15 Minuten aktualisiert werden. Die Messdaten werden direkt aktualisiert. Block, Hilgers Bestanden
9 Die Messdaten sollen gespeichert und über die Zeit dargestellt werden. Die Messwertspeicherung funktioniert teilweise. Messdaten werden teilweise gelöscht. Block, Hilgers nicht Bestanden
10 Die Wetterstation soll folgende Prognosen anzeigen: gefühlte Temperatur, Hitzeindex, Taupunkt. Es werden gefühlte Temperatur, Hitze Index und Taupunkt angezeigt. Block, Hilgers Bestanden

Ergebnis

Das Projekt zur Entwicklung einer kabellosen Wetterstation an der HSHL im Fachgebiet der Mechatronik führte zu einer erfolgreichen Implementierung und Funktion der Station außer der Messdatenspeicherung. Die Wetterstation ist in der Lage, Messdaten sowohl von der Innen- als auch von der Außenstation zu verarbeiten und anzuzeigen. Diese Daten umfassen Windgeschwindigkeit, Temperatur, Luftfeuchtigkeit, Taupunkt, Hitzeindex und gefühlte Temperatur, wobei die Außenstation die Informationen drahtlos an die Innenstation übermittelt. Ein besonderes Merkmal der Station hätte die Speicherung von Temperaturwerten stündlich über einen Zeitraum von 24 Stunden sein sollen. Diese sollten dann in einem Plot visualisiert werden können. Die Erstellung des Plots funktioniert ohne Probleme, jedoch verliert die Innenraumstation in unregelmäßigen nicht reproduzierbaren Abständen die Messdaten. Dies führt zu einem Plot, der nur die "Null"-Linie darstellt. Die Wireless-Verbindung zwischen den Stationen zeichnet sich durch eine hohe Reichweite (>20m durch Wände) aus, was für den Einsatz im Außenbereich essenziell ist. Insgesamt funktioniert die Wetterstation zuverlässig nach den vorgegebenen Anforderungen und liefert präzise Wetterdaten im Rahmen des beabsichtigten Einsatzbereichs.

Zusammenfassung

Lessons Learned

Das Projekt zur Entwicklung einer kabellosen Wetterstation umfasste mehrere Phasen: Planung, Beschaffung der Komponenten, Implementierung, Umsetzung und Dokumentation.

Eines der ersten Learnings war die Erkenntnis, dass Simulink für das Projekt nicht optimal geeignet war. Ursprünglich für die Regelungstechnik gedacht, erwies sich Simulink als wenig nützlich für die Verarbeitung von Messdaten, da die verwendeten Sensoren die Messverarbeitung intern durchführen. Die Implementierung wäre einfacher gewesen, wenn sie direkt in der Arduino IDE stattgefunden hätte. Trotzdem bot die Nutzung von Simulink eine wertvolle Lernerfahrung, insbesondere im Umgang mit S-Function-Blöcken.

Ein weiterer wichtiger Aspekt waren die programmiertechnischen Herausforderungen. Die Speicherung der Messdaten und die grafische Darstellung des Temperaturverlaufs in einem Plot waren komplexer und zeitaufwändiger als ursprünglich angenommen. Dies unterstreicht die Bedeutung einer realistischen Einschätzung von Aufwand und Komplexität bei der Planung von Softwareprojekten.

Die Konstruktion des Gehäuses stellte sich ebenfalls als sehr umfangreich heraus. Das Gehäuse besteht aus mehreren Teilen und musste sorgfältig entworfen und produziert werden, um den unterschiedlichen Anforderungen der Innen- und Außenstation gerecht zu werden. Hierbei wurde besonderer Wert auf Wetterfestigkeit, Ästhetik und Benutzerfreundlichkeit gelegt. Die Verwendung von 3D-Druck und die Auswahl geeigneter Materialien wie ASA für das Außengehäuse waren entscheidend für die Langlebigkeit und Funktionalität der Station.

Das Endergebnis des Projekts war eine funktionsfähige Wetterstation, die die Messdaten von Innen- und Außenstation erfasst und drahtlos übermittelt. Die Wetterstation kann Temperatur, Taupunkt, Hitzeindex und gefühlte Temperatur messen und anzeigen. Die Wireless-Verbindung zeichnet sich durch eine die Anforderungen übertreffende Reichweite aus, was für den Einsatz im Außenbereich elementar ist.

Ein weiteres zentrales Learning war die Bedeutung einer gründlichen Vorbereitung und Planung in allen Projektphasen. Die umfassende Recherche und sorgfältige Auswahl der Komponenten waren entscheidend für den Erfolg des Projekts. Insbesondere die Wahl der Sensoren und der Kommunikationsmodule spielte eine wichtige Rolle, um eine zuverlässige Datenerfassung und Übertragung zu gewährleisten.

Die Verwendung des Simulink Support Package für Arduino und die Anpassung des S-Function-Builders waren bei der Programmierung Schlüsselmomente, die das Projekt erst realisierbar machten. Die Möglichkeit, benutzerdefinierten C++-Code in die Simulink-Modelle zu integrieren, eröffnete neue Wege zur Steuerung und Erweiterung der Funktionalität der Hardware.

Ein weiterer Aspekt war die Bedeutung einer detaillierten Dokumentation. Durch die transparente Dokumentation des Quellcodes und der Projektprozesse wurde nicht nur das Verständnis innerhalb des Teams gefördert, sondern auch die Möglichkeit für zukünftige Verbesserungen und Anpassungen geschaffen.

Abschließend lässt sich sagen, dass das Projekt wertvolle Erkenntnisse über die Herausforderungen bei der Entwicklung einer kabellosen Wetterstation geliefert hat. Es hat gezeigt, dass sorgfältige Planung, Anpassungsfähigkeit und detaillierte Dokumentation entscheidend für den Erfolg eines solchen Vorhabens sind. Diese Erfahrungen können in zukünftigen Projekte in verschiedensten Bereichen einfließen und als Grundlage für weitere Innovationen und Verbesserungen dienen.

Projektunterlagen

Projektplan

Abbildung 9.1: Gantchart der Projektdurchführung Datei:GanttWirelessWeatherstation ZIP.zip


Projektdurchführung

Das Projekt "kabellose Wetterstation" wurde durchgeführt als Teil des GET-Fachpraktikums. Es konzentriert sich auf die Erfassung und Analyse wettertechnischer Daten, wie Temperatur und Luftfeuchtigkeit mithilfe von zwei Arduino Mega. Diese Arduinos, integriert in selbst entworfene 3D-gedruckte Gehäuse, kommunizieren drahtlos miteinander. Das Außengehäuse wurde speziell wasserabweisend konstruiert, um die interne Elektronik vor Regen und Feuchtigkeit zu schützen. Sowohl die Innen- als auch die Außenstation erfassen Messdaten, die dann auf einem Display in der Innenraum-Station visualisiert werden.

Die Entwicklung dieser kabellosen Wetterstation umfasste zwei Hauptbereiche: die Hardware- und die Softwareentwicklung.

In der Hardwareentwicklung lag der Fokus auf dem Design und der Konstruktion der physischen Komponenten. Dies beinhaltet die Auswahl geeigneter Materialien für die Gehäuse, die Integration von Sensoren und Mikrocontrollern sowie die Sicherstellung der Wetterfestigkeit und der drahtlosen Kommunikation. Wichtige Aspekte sind dabei die Robustheit der Außenstation gegenüber Witterungseinflüssen und die ergonomische sowie ästhetische Gestaltung der Innenstation. Im Innengehäuse ist ein 3,5-Zoll-Display verbaut, das die Lesbarkeit der Wetterdaten sicherstellt. Die Innenstation verfügt über ein Empfänger-Modul, Sensoren für Temperatur und Feuchtigkeit sowie eine RealtimeClock, diese sind alle im Gehäuse untergebracht. Beim Design des Innengehäuses wurde besonderer Wert auf Benutzerfreundlichkeit und einfache Wartung gelegt, es berücksichtigt aber ebenso eine gute Belüftung. Das Außengehäuse, das ohne Display gestaltet ist, besitzt neben dem Funkmodul und dem Temperatur- und Feuchtigkeitssensor auch ein Anemometer und ein Barometer. Es ist aus dem Material ASA (Acrylnitril-Styrol-Acrylat) 3D-gedruckt, ein Material, das sich durch seine UV- und Witterungsbeständigkeit auszeichnet.

Auf der anderen Seite steht die Softwareentwicklung, die sich mit der Programmierung der Mikrocontroller, der Entwicklung der Benutzeroberfläche, der Implementierung der Datenverarbeitung und Datenanzeige befasst, alles unter Verwendung von MATLAB/Simulink. Hierbei spielte MATLAB/Simulink, das als Vorgabe des Praktikums zu verwenden war, eine zentrale Rolle. Es wurden zwei unterschiedliche Simulink-Modelle erstellt, um die spezifischen Anforderungen der separat agierenden Arduino-Controller für den Innen- und Außenbereich zu erfüllen. Unter Verwendung von Simulink S-Function-Blöcken wurde C++-Code in die Simulink-Modelle integriert. Dies ermöglichte verschiedene Arduino-Bibliotheken für spezifische Funktionen zu nutzen, die sonst nicht verfügbar gewesen wären.

Das Projektmanagement beinhaltete die Erstellung eines Gantt-Charts und des Programmablaufplans, die die zeitliche Planung und wichtige Meilensteine des Projekts darstellen. Diese Diagramme ermöglichten es uns, bereits im Vorhinein eine solide Planung der einzelnen Abschnitte des Projektes anzustellen. Wir konnten durch sie konstant nachverfolgen, ob wir im Zeitplan liegen.

Insgesamt zeigt dieses Projekt eine umfassende Kombination aus technischen und praktischen Anwendungen in der Wetterüberwachung.

Zur Funktionsüberprüfung wurden nach dem Zusammenbau ein Versuch durchgeführt. Dieser zeigte, dass die Messdaten und die Ausgabe übereinstimmen. Ebenso wurde die Korrektheit der Messdaten überprüft.

Abschließend wurde ein YouTube Video, das die Funktionsweise darstellt gedreht, geschnitten und Online zur Verfügung gestellt.

Projektdaten

Hier finden sie alle Projektdaten, außer die Bibliotheken für die Simulinkprojekte, hinterlegt in einem ZIP-Archiv: Datei:164 Kabellose Wetterstation.zip
Die Bibliotheken wurden wegen hoher Speichernutzung nicht beigefügt. Sie finden unter "Weblinks" alle genutzten Bibliotheken. Diese müssen Sie in dem jeweiligen Unterordner "libs" speichern.

YouTube Video

In dem folgenden YouTube-Video werden die Funktionen der kabellosen Wetterstation gezeigt:

Video 1: Funktion der kabellosen Wetterstation

Weblinks

Verwendete Bibliotheken für die Innenstation:
https://github.com/adafruit/Adafruit_BusIO
https://github.com/adafruit/Adafruit_TouchScreen
https://github.com/adafruit/Adafruit-GFX-Library
https://github.com/arduino/ArduinoCore-avr
https://github.com/bblanchon/ArduinoJson
https://github.com/NorthernWidget/DS3231
https://github.com/cattanimarco/Grafici-GFX
https://github.com/prenticedavid/MCUFRIEND_kbv
https://github.com/nRF24/RF24
https://github.com/arduino-libraries/SD

Verwendete Bibliotheken für die Außenstation:
https://github.com/arduino/ArduinoCore-avr
https://github.com/NorthernWidget/DS3231
https://github.com/nRF24/RF24

Literatur


→ zurück zur Übersicht: WS 23/24: Angewandte Elektrotechnik (BSE)