MKR1000 Multi-Sensor-Deck: Blitz, Gas, UV, Temp, Feuchte & Druck – Umweltmonitoring
Komponenten und Zubehör
| Arduino MKR1000 | × | 1 |
| MOD-1016 Blitzsensor (AS3935) | × | 1 |
| DFRobot MQ-9 Gassensor (CO/Entzündbare Gase) | × | 1 |
| Adafruit HTU21D-F Temperatur- & Feuchtesensor (I2C) | × | 1 |
| Adafruit BMP085/BMP180 Druck-/Höhen-/Temperatursensor (I2C) | × | 1 |
| SparkFun ML8511 UV-Sensor (analog) | × | 1 |
| ChronoDot RTC (DS3231, I2C, batteriegepuffert) | × | 1 |
| SparkFun Photon Weather Shield (Platzhalter für Wind/Regen) | × | 1 |
| Adafruit NeoPixel (WS2812B) | × | 1 |
| Steckbrett & Jumperkabel | × | 1 |
Projektbeschreibung
Ich liebe Wetterbeobachtung und wollte mehr als nur Temperatur/Feuchte. Kommerzielle Stationen zeigen oft nur „Jetzt“-Werte. Mit dem Arduino MKR1000 konnte ich endlich alle gewünschten Sensoren gleichzeitig betreiben – dank 8 Hardware-Interrupts (normale Arduinos haben nur 2).
Sensoren auswählen: Drei Kategorien
- Analog: Licht (IR, UV), Windrichtung, Gase, Lastzellen…
- I2C: Temperatur, Feuchte, Luftdruck, Beschleunigung, Gyro…
- Interrupts: Regensensor (Kippwippe), Windgeschwindigkeit (Impulse/Umdrehung), Blitzdetektor, Timer…
Der MKR1000 bietet genügend Pins für alle drei Typen.
WICHTIG – Spannungspegel: MKR1000 arbeitet mit 3,3 V Logik. Sensoren mit 5 V Pegel benötigen Level-Shifter an I2C/Interrupt-Leitungen.
Die verwendeten Sensoren sind gängig (Adafruit, SparkFun, Element14), kosten 5–20 USD. Blitzdetektor (MOD-1016, AS3935) ca. 26 USD. Windmesser (Anemometer) vom Photon Weather Shield geplant. Bodentemperatur/Moisture später ergänzbar.
Pin-Belegung planen
Vor dem Aufbau auf Papier (und als Kommentar im Code) festlegen:
| Pin | Funktion | Typ |
|---|---|---|
| A0 | reserviert (DAC) | Analog |
| A1 | ML8511 UV-Sensor | Analog |
| A2 | Sichtbarer Lichtsensor (TEMT6000) | Analog |
| A3 | TMP36 lokaler Temperatursensor | Analog |
| A4 | MQ-9 Gassensor | Analog |
| A5 | Bodenfeuchte-Sensor | Analog |
| A6 | Windgeschwindigkeit (analog?) | Analog |
| 0 | Taster (Interrupt) | HW-Interrupt |
| 1 | AS3935 Blitzdetektor (Interrupt) | HW-Interrupt |
| 2 | Wind-Anemometer (Interrupt/Umdrehung) | HW-Interrupt |
| 3 | Regensensor Kippwippe (Interrupt) | HW-Interrupt |
| 4,5 | frei | – |
| 6 | Piezo-Summer (geteilt mit Onboard-LED) | Digital Out |
| 7 | NeoPixel Datenleitung | Digital Out |
| 11 | I2C SDA | I2C |
| 12 | I2C SCL | I2C |
Erste Schritte: Sensor für Sensor testen
- Jeweils einen Sensor anschließen, Beispielcode laden, Bibliothek installieren.
- Pin-Zuordnung im Code anpassen, Testen per Serial Monitor.
- Wenn alle einzeln laufen, zum Gesamtsketch zusammenfügen.
Ich nutze zusätzlich eine ChronoDot RTC (DS3231), da der MKR1000-eigene RTC bei reiner Batteriepufferung bei mir nicht zuverlässig lief.
Auf dem Steckbrett: Orangene Jumper = 3,3 V-Versorgung pro Sensor (einzeln abziehbar zum Deaktivieren).
Bibliotheken & Kompatibilität
Einige ältere Bibliotheken funktionieren nicht out-of-the-box mit MKR1000 / Arduino IDE 1.6.7+ (z. B. entfernte ATOMIC_*-Makros in AVR-libc). Fehlermeldungen (orange) genau lesen: Steht der Fehler in einer Bibliothek? Websuche mit „arduino“ + Fehlermeldung. Autor kontaktieren. Besser: Fertigmodule von Adafruit/SparkFun kaufen – diese pflegen ihre Bibliotheken.
WLAN & Verschlüsselung
Der MKR1000 hat onboard WiFi und eine Hardware-Krypto-Engine (ATECC508A) für sichere TLS-Verbindungen – essenziell für IoT. In diesem Projekt noch nicht genutzt, aber für „Version 2“ geplant.
Tipp: Unbedingt die neueste WiFi101-Bibliothek nutzen (GitHub), sonst erkennt der Sketch das WiFi-Modul nicht. Dank an Charif Mahmoudi für den Hinweis in seinem „Getting Started with MKR1000“-Tutorial.
Tipps für Analog-Sensoren
- Meist einfache Spannung (0–3,3 V) →
analogRead(). - Umrechnung via
map()oder Formel (Datenblatt). - Widerstandsbasierte Sensoren (NTC, Feuchte) benötigen Spannungsteiler.
- Potentiometer zum Feinjustieren der Betriebsspannung hilfreich.
- TMP36:
Temp°C = (Spannung - 0,5 V) × 100. - Sehr kleine Signale (Lastzellen, Beschleunigung) → Modul mit integriertem Operationsverstärker kaufen.
Tipps für I2C-Geräte
- Zwei Leitungen: SDA (Daten), SCL (Takt) + gemeinsames GND + VCC.
- Jedes Gerät hat eine 7-Bit-Hex-Adresse. Doppelte Adressen vermeiden! (Bei Bedarf Enable/Shutdown-Pin nutzen, aber nicht VCC trennen – Parasitärversorgung über SDA/SCL möglich).
- Pull-up-Widerstände an SDA/SCL am letzten Gerät am Bus (oft auf Modulen schon vorhanden).
- Zusätzliche 220 Ω Reihenwiderstände an SDA & SCL (nah am MCU) verbessern Signalgüte bei 3,3 V-Systemen deutlich (bei 5 V 330 Ω).
Was tun mit den Daten?
Aktuell: Serial Monitor. Erweiterbar: LCD, SD-Karte, Cloud-Upload (WiFi). Vision: Mehrere Stationen mit GPS → Blitzortung durch Triangulation der Empfangssignale.
UPDATE 2017-11-29: Hardware-Interrupts auf MKR1000 funktionieren noch nicht zuverlässig. Ich nutze das Projekt nun für einen 9. Klassen-Kurs (Adalogger M0 + SD-Karte + WiFi-Modul). Lehrmaterial: arduinoclass.pbworks.com
Idea: IKEA SODERSVIK Lampe mit 20 NeoPixels + IR-Empfänger → Wind = ziehende Wolken, Farbe = Temperatur, Fernbedienung zeigt Trendwerte.
Code-Beispiele
1. Haupt-Sketch (Monitoring aller Sensoren)
Vollständiger, kommentierter Code (NeoPixel & Blitzsensor auskommentiert wegen Interrupt-Bibliotheks-Problemen).
/* RTC-Weather-Sensors_v6_MKR1000 by Zonker Harris Spring 2016
* MKR1000: 8 HW-Interrupts + WiFi + Crypto (wichtig für IoT!)
* Viele Kommentare = keine Speicherkosten, aber Verständnis später!
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_HTU21DF.h>
// #include <Adafruit_NeoPixel.h> // Interrupt-Konflikt, aktuell deaktiviert
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10180);
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
// Pin-Zuordnungen (siehe Tabelle oben)
int UVOUT = A1, lightOut = A2, tmp36out = A3, mq9out = A4;
int sounderPin = 6, neopixelPin = 7;
// ChronoDot RTC Variablen (BCD-Register)
int addrRTC = 0x68;
int seconds, minutes, hours, day, date, month, years;
int temprtc, tempfrtc;
void setup() {
Serial.begin(9600); delay(1000);
Serial.println("i2c Sensor Deck");
pinMode(UVOUT, INPUT); pinMode(lightOut, INPUT); pinMode(tmp36out, INPUT);
pinMode(sounderPin, OUTPUT); pinMode(neopixelPin, OUTPUT);
if (!bmp.begin()) { Serial.println("BMP085/180 nicht gefunden!"); while(1); }
displaySensorDetails();
if (!htu.begin()) { Serial.println("HTU21D nicht gefunden!"); while(1); }
// RTC initial setzen (einmalig auskommentieren, hochladen, wieder kommentieren)
// seconds=0; minutes=41; hours=20; day=7; date=3; month=1; years=16; initChrono();
}
void loop() {
beep(50, 2); // Start-Signal
// 1. ChronoDot RTC auslesen (I2C 0x68)
Wire.beginTransmission(0x68); Wire.write(0); Wire.endTransmission();
Wire.requestFrom(0x68, 13);
while(Wire.available()) {
seconds = Wire.read(); minutes = Wire.read(); hours = Wire.read();
day = Wire.read(); date = Wire.read(); month = Wire.read(); years = Wire.read();
// Alarme, Status, Aging, Temp übersprungen für Kürze
temprtc = Wire.read(); tempfrtc = Wire.read();
}
// BCD → Dezimal konvertieren
int s10 = (seconds & 0xF0)>>4, s1 = seconds & 0x0F;
int m10 = (minutes & 0xF0)>>4, m1 = minutes & 0x0F;
int h10 = ((hours & 0x20)>>5)*2 + ((hours & 0x10)>>4)*1; // 24h-Modus
int h1 = hours & 0x0F;
years += 2000;
temprtc = (temprtc & 0x7F) + ((tempfrtc & 0xC0)>>6)*0.25;
get_date(); // Wochentag aktualisieren
Serial.print("ChronoDot - ");
Serial.print(h10); Serial.print(h1); Serial.print(":");
Serial.print(m10); Serial.print(m1); Serial.print(":");
Serial.print(s10); Serial.print(s1); Serial.print(" 20");
Serial.print(years); Serial.print(" "); Serial.print(month);
Serial.print(" "); Serial.print(date); Serial.print("\t");
Serial.print(temprtc); Serial.println(" C");
delay(100);
// 2. BMP180 (I2C 0x77) – Druck & Temp
sensors_event_t event; bmp.getEvent(&event);
float BMPtemp; bmp.getTemperature(&BMPtemp);
Serial.print("Temp: "); Serial.print(BMPtemp); Serial.print(" C (");
Serial.print(BMPtemp*1.8+32); Serial.print(" F) \t");
if (event.pressure) {
Serial.print("BMP180 - Pres: "); Serial.print(event.pressure); Serial.print(" hPa\t");
float seaLevel = SENSORS_PRESSURE_SEALEVELHPA; // 1013.25 hPa Standard
Serial.print("Alt: "); Serial.print(bmp.pressureToAltitude(seaLevel, event.pressure)); Serial.println(" m");
} else Serial.println("Sensor error");
delay(100);
// 3. HTU21D-F (I2C 0x40) – Feuchte & Temp
float HTUtemp = htu.readTemperature();
Serial.print("HTU21DF - Temp: "); Serial.print(HTUtemp); Serial.print(" C (");
Serial.print(HTUtemp*1.8+32); Serial.print(" F)\tHum: ");
Serial.print(htu.readHumidity()); Serial.println("%");
delay(100);
// 4. TMP36 (Analog A3) – lokale Temp
int reading = averageAnalogRead(tmp36out);
float voltage = 0.0032258064516129 * reading; // 3.3V/1023
float tempC = (voltage - 0.5) * 100;
Serial.print("TMP36 - temp: "); Serial.print(tempC); Serial.print(" C \t");
Serial.print(tempC*9/5+32); Serial.print(" F, out: "); Serial.print(voltage); Serial.println("v");
delay(100);
// 5. TEMT6000 (Analog A2) – sichtbares Licht
int vLevel = averageAnalogRead(lightOut);
float vVolts = 0.0032258064516129 * vLevel;
Serial.print("TEMT6000 out: "); Serial.println(vLevel);
delay(100);
// 6. ML8511 (Analog A1) – UV-Index
int uvLevel = averageAnalogRead(UVOUT);
float uvVolts = 0.0032258064516129 * uvLevel;
float uvIndex = mapfloat(uvVolts, 0.99, 2.8, 0.0, 15.0);
Serial.print("ML8511 UV out: "); Serial.print(uvLevel);
Serial.print(" / UV Intensity (mW/cm²): "); Serial.println(uvIndex);
delay(100);
// 7. MQ-9 (Analog A4) – Gas (roher ADC-Wert, Kalibrierung nötig)
int mq9val = analogRead(mq9out);
Serial.print("MQ-9 Gas: "); Serial.println(mq9val, DEC);
delay(100);
Serial.println(); delay(3500); // ~5s Loop-Zeit
}
// Hilfsfunktionen: averageAnalogRead, mapfloat, beep, RTC-Funktionen, I2C-Scanner...
// (siehe vollständigen Code auf GitHub / untenstehende Snippets)
2. Mittelwertbildung für Analog-Reads (Rauschunterdrückung)
int averageAnalogRead(int pin) {
byte n = 8; unsigned int sum = 0;
for (byte i = 0; i < n; i++) sum += analogRead(pin);
return sum / n;
}
3. I2C-Bus-Scanner (Adressen finden)
#include <Wire.h>
void setup() { Wire.begin(); Serial.begin(9600); Serial.println("\nI2C Scanner"); }
void loop() {
byte error, addr; int n = 0;
Serial.println("Scanning...");
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device at 0x"); if (addr<16) Serial.print("0");
Serial.print(addr, HEX);
// Bekannte Sensoren benennen
if (addr == 0x03) Serial.print(" - AS3935 Blitz");
if (addr == 0x40) Serial.print(" - HTU21D Temp/Feuchte");
if (addr == 0x68) Serial.print(" - DS3231 RTC (ChronoDot)");
if (addr == 0x77) Serial.print(" - BMP180 Druck/Temp");
Serial.println(); n++;
} else if (error == 4) {
Serial.print("Unknown error at 0x"); if (addr<16) Serial.print("0");
Serial.println(addr, HEX);
}
}
if (n == 0) Serial.println("No I2C devices");
Serial.println("done"); delay(5000);
}
4. ML8511 UV-Sensor Demo (angepasst für 3,3 V MCU)
int UVOUT = A1;
void setup() { Serial.begin(9600); pinMode(UVOUT, INPUT); Serial.println("ML8511 example"); }
void loop() {
int uv = averageAnalogRead(UVOUT);
float volts = 0.0032258064516129 * uv; // 3.3V/1023
float uvIdx = mapfloat(volts, 0.99, 2.8, 0.0, 15.0);
Serial.print("ML8511 out: "); Serial.print(uv);
Serial.print(" / UV Index: "); Serial.println(uvIdx);
delay(100);
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
// averageAnalogRead() wie oben
Schaltplan (Mock-up, Fritzing unvollständig)
Herstellungsprozess
- Sensordaten in Raspberry Pi integrieren: GPS & MPU-9150 Hands-On Guide
- Line-Tracking-Sensor mit Raspberry Pi – Einfacher KY-033 Tür/Line Detektor
- Robuste Temperatur- & Sensor-API auf Raspberry Pi mit GY-91 Modul bauen
- Automatisiertes Aeroponik-System mit Raspberry Pi und Feuchtigkeitssensor bauen
- Raspberry Pi GPIO meistern: PIR-Bewegungsmelder an B+/Model 2 anschließen
- Acconeer A111 Pulsradar mit Raspberry Pi integrieren: Praktischer Leitfaden
- HC-SR501 PIR-Bewegungssensor an Raspberry Pi anschließen, kalibrieren und programmieren
- Python/MicroPython Sensor Logger: Sensordaten nahtlos in Google Sheets speichern
- Adafruit 10DOF IMU Daten von Raspberry Pi 2 an Azure Event Hubs senden (Windows 10 IoT Core)
- Sanftes Herunterfahren & Schlafmodus für Raspberry Pi – DIY Strommanagement-Schaltung