Een betrouwbare Arduino-gebaseerde draadloze weerstation bouwen
In deze tutorial leer je hoe je een Arduino-gebaseerd draadloos weerstation maakt. Je kunt de volgende video bekijken of de geschreven tutorial hieronder lezen.
Overzicht
De buitentemperatuur en -vochtigheid worden gemeten met de DHT22-sensor en deze data wordt draadloos verstuurd naar de binnenunit met behulp van NRF24L01-transceivermodules. Aan de binnenunit zit ook een DHT22-sensor voor het meten van de binnentemperatuur en -vochtigheid, evenals een DS3231 Real Time Clock-module die de tijd bijhoudt zelfs als de Arduino stroom verliest. Al deze data wordt weergegeven op een 0,96" OLED-display.

Arduino draadloos weerstation schakelschema
Laten we kijken naar het schakelschema en hoe dit project werkt. Let op dat ik al gedetailleerde tutorials heb over hoe elk van deze modules werkt, dus voor meer details kun je ze bekijken: NRF24L01 Tutorial, DHT22 Tutorial, DS3231 Tutorial.

Je kunt de benodigde componenten voor dit project via de onderstaande links verkrijgen:
- NRF24L01 Transceiver Module
- DHT22 Sensor
- DS3231 Real Time Clock
- Arduino Nano
Zowel de real-time clock-module als het OLED-display gebruiken het I2C-protocol voor communicatie met de Arduino, dus ze zijn aangesloten op de I2C-pennen of analoge pennen 4 en 5 op de Arduino Nano. Recht naast de NRF24L01-transceiver zit een condensator om de voeding stabieler te maken. Er zit ook een pull-up-weerstand op de datapin van de DHT22 zodat de sensor correct werkt.
Wat de voeding betreft: ik gebruikte een 12V DC-adapter voor de binnenunit, en voor de buiteneenheid twee Li-ion-batterijen die samen ongeveer 7,5V leveren. Met deze configuratie kan de buiteneenheid ongeveer 10 dagen draaien voordat de batterijen leeg zijn, omdat we periodiek data versturen en de Arduino in de tussentijd in slaapmodus zetten, waarbij de stroomverbruik slechts ongeveer 7mA bedraagt.
Custom design PCB
Om de elektronische componenten georganiseerd te houden, heb ik volgens het schakelschema een custom PCB ontworpen met de gratis online ontwerpsoftware EasyEDA. We kunnen zien dat dezelfde PCB voor zowel de binnen- als buiteneenheid kan worden gebruikt, alleen de Arduino moet anders geprogrammeerd worden.

Zodra het ontwerp klaar is, exporteren we het Gerber-bestand dat gebruikt wordt voor de PCB-fabricage. Je kunt de EasyEDA-projectbestanden van het Arduino draadloze weerstation hier bekijken.
Vervolgens bestellen we de PCB bij JLCPCB, de sponsor van deze video.

We slepen het Gerber-bestand in de uploader, controleren de PCB in de Gerber-viewer, selecteer de gewenste eigenschappen en bestellen tegen een redelijke prijs. Let op: bij je eerste bestelling bij JLCPCB kun je tot 10 PCBs voor slechts $2 krijgen.

Na enkele dagen zijn de PCBs aangeleverd. De kwaliteit is geweldig en alles klopt precies met het ontwerp.

Ik begon met het assembleren door pinheaders op de PCB te solderen, zodat we componenten gemakkelijk kunnen aansluiten en loskoppelen.

Daarna soldeerde ik de condensator en de pull-up-weerstand. Met deze stap klaar, kunnen we de componenten op de pinheaders van de PCB plaatsen.

Vervolgens maakte ik de behuizingen. Ik gebruikte 8mm dik MDF-bord en zaagde alle stukken op maat met een cirkelzaag.

Voor nauwkeurige metingen moeten de zijkanten van de behuizingen lucht doorlaten. Ik boorde en raspt meerdere sleuven in de zijpaneelen van zowel de binnen- als buiteneenheid.

Ik maakte ook een sleuf voor het OLED-display op het frontpaneel en zaagde een klein aluminiumstukje op maat voor decoratie.


Voor het samenstellen gebruikte ik houtlijm, klemmen en schroeven. Ik schilderde de behuizingen met spuitbusverf: wit voor de buiteneenheid, zwart voor de binnenunit. Na het drogen plaatste ik de PCBs in de behuizingen.


Aan de achterkant van de binnenunit monteurde ik een voedingsjack en een aan/uitschakelaar, en aan de buiteneenheid gebruikte ik een simpele jumper-draad als schakelaar. En klaar is ons Arduino draadloze weerstation, maar we moeten nog kijken hoe de code werkt.
Arduino draadloos weerstation code
Buiteneenheid (Zender) code
/* Arduino Draadloze Communicatie Tutorial Buiteneenheid - Zender by Dejan Nedelkovski, www.HowToMechatronics.com Bibliotheken: NRF24L01 - TMRh20/RF24, https://github.com/tmrh20/RF24/ DHT22 - DHTlib, https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib LowPower - https://github.com/rocketscream/Low-Power */
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>
#include <LowPower.h>
#define dataPin 8 // DHT22 datapin
dht DHT; // Maak DHT-object aan
RF24 radio(10, 9); // CE, CSN
const byte address[6] = "00001";
char thChar[32] = "";
String thString = "";
void setup() {
radio.begin();
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
}
void loop() {
int readData = DHT.read22(dataPin); // Lees data van sensor
int t = DHT.temperature; // Temperatuur
int h = DHT.humidity; // Vochtigheid
thString = String(t) + String(h);
thString.toCharArray(thChar, 12);
// Verstuur data draadloos naar binnenunit
for (int i = 0; i <= 3; i++) { // Verstuur 3 keer voor zekerheid
radio.write(&thChar, sizeof(thChar));
delay(50);
}
// Slaap 2 minuten (15 * 8s = 120s)
for (int sleepCounter = 15; sleepCounter > 0; sleepCounter--) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
}
Beschrijving: De buiteneenheid is de zender. We includeren de RF24-, DHT- en LowPower-bibliotheek (voor slaapmodus). Na het definiëren van instanties, pinnen en variabelen, initialiseren we in setup het draadloze communicatie-adres. In de loop lezen we temperatuur en vochtigheid van de DHT22. Deze gehele getallen converteren we naar één String, plaatsen ze in een character-array en versturen ze met radio.write(). We sturen 3 keer om te zorgen dat de ontvanger de data ontvangt, zelfs als hij bezig is. Ten slotte zetten we de Arduino 2 minuten in slaapmodus om stroom te besparen.
Binnenunit (Ontvanger) code
/* Arduino Draadloze Communicatie Tutorial Binnenunit - Ontvanger by Dejan Nedelkovski, www.HowToMechatronics.com Bibliotheken: DS3231 - https://www.rinkydinkelectronics.com/library.php?id=73 U8G2 - https://github.com/olikraus/u8g2 */
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>
#include <DS3231.h>
#include <U8g2lib.h>
#include <Wire.h>
#define dataPin 8 // DHT22 sensor
dht DHT;
DS3231 rtc(SDA, SCL);
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
RF24 radio(10, 9);
const byte address[6] = "00001";
char text[6] = "";
int readDHT22, t, h;
String inTemp, inHum, outTemp, outHum;
String rtcTime, rtcDate;
int draw_state = 0;
unsigned long previousMillis = 0;
long interval = 3000;
#define Temperature_20Icon_width 27
#define Temperature_20Icon_height 47
static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0xe1, 0x00, 0x00,
0xe0, 0xc0, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00,
0x60, 0x80, 0x79, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03,
0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x8c, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00,
0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00,
0x60, 0x9e, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03,
0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x70, 0x9e, 0x03, 0x00,
0x38, 0x1e, 0x07, 0x00, 0x18, 0x3e, 0x0e, 0x00, 0x1c, 0x3f, 0x0c, 0x00, 0x0c, 0x7f, 0x18, 0x00,
0x8c, 0xff, 0x18, 0x00, 0x8e, 0xff, 0x38, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00,
0xc6, 0xff, 0x31, 0x00, 0x8e, 0xff, 0x38, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x0c, 0x7f, 0x1c, 0x00,
0x3c, 0x1c, 0x0e, 0x00, 0x78, 0x00, 0x06, 0x00, 0xe0, 0x80, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00,
0x80, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#define Humidity_20Icon_width 27
#define Humidity_20Icon_height 47
static const unsigned char Humidity_20Icon_bits[] U8X8_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
0x00, 0xf8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x00,
0x00, 0x86, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x07, 0x00, 0x80, 0x03, 0x06, 0x00,
0x80, 0x01, 0x0c, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0xc0, 0x00, 0x18, 0x00, 0xe0, 0x00, 0x38, 0x00,
0x60, 0x00, 0x30, 0x00, 0x70, 0x00, 0x70, 0x00, 0x30, 0x00, 0xe0, 0x00, 0x38, 0x00, 0xc0, 0x00,
0x18, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0x80, 0x01, 0x0c, 0x00, 0x80, 0x03, 0x0e, 0x00, 0x80, 0x03,
0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x06,
0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06,
0x63, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0xe3, 0x00, 0x00, 0x06, 0xc7, 0x00, 0x00, 0x06,
0xc6, 0x01, 0x00, 0x07, 0x86, 0x03, 0x00, 0x03, 0x0e, 0x1f, 0x00, 0x03, 0x0e, 0x1e, 0x80, 0x01,
0x1c, 0x00, 0xc0, 0x01, 0x38, 0x00, 0xe0, 0x00, 0x78, 0x00, 0x70, 0x00, 0xf0, 0x00, 0x38, 0x00,
0xe0, 0x07, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
void setup() {
radio.begin();
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_MIN);
radio.startListening();
u8g2.begin();
rtc.begin();
}
void loop() {
if (radio.available()) {
radio.read(&text, sizeof(text));
outTemp = String(text[0]) + String(text[1]) + char(176) + "C";
outHum = String(text[2]) + String(text[3]) + "%";
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
u8g2.firstPage();
do {
switch (draw_state) {
case 0: drawDate(); break;
case 1: drawInTemperature(); break;
case 2: drawInHumidity(); break;
case 3: drawOutTemperature(); break;
case 4: drawOutHumidity(); break;
}
} while (u8g2.nextPage());
draw_state++;
if (draw_state > 4) draw_state = 0;
}
}
void drawDate() {
String dowa = rtc.getDOWStr();
dowa.remove(3);
rtcDate = dowa + " " + rtc.getDateStr();
u8g2.setFont(u8g2_font_timB14_tr);
u8g2.setCursor(0, 15);
rtcTime = rtc.getTimeStr();
rtcTime.remove(5);
u8g2.print(rtcDate);
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(8, 58);
u8g2.print(rtcTime);
}
void drawInTemperature() {
readDHT22 = DHT.read22(dataPin);
t = DHT.temperature;
inTemp = String(t) + char(176) + "C";
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(24, 15);
u8g2.print("INDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(inTemp);
u8g2.drawXBMP(0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits);
}
void drawInHumidity() {
h = DHT.humidity;
inHum = String(h) + "%";
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(24, 15);
u8g2.print("INDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(inHum);
u8g2.drawXBMP(0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits);
}
void drawOutTemperature() {
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(12, 15);
u8g2.print("OUTDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(outTemp);
u8g2.drawXBMP(0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits);
}
void drawOutHumidity() {
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(12, 15);
u8g2.print("OUTDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(outHum);
u8g2.drawXBMP(0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits);
}
Beschrijving: Aan de ontvangerkant (binnenunit) includeren we twee extra bibliotheken: één voor de DS3231 real-time clock en één voor het OLED-display (U8G2-bibliotheek). Op dezelfde manier definiëren we instanties, pinnen en variabelen. Ook definiëren we de temperatuur- en vochtigheidspictogrammen als bitmaps.
Voor het maken van bitmaps kun je GIMP gebruiken (gratis afbeeldingseditor), waarin je alles kunt tekenen en exporteren als bitmap (.xbm). Open dit bestand in Kladblok en kopieer de bitmapdata in de Arduino-code. Let op dat we de bitmap als constant definiëren met PROGMEM, zodat deze in de flash-geheugen wordt opgeslagen in plaats van SRAM.
static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM // Opslaan in Flash-geheugen static unsigned char Temperature_20Icon_bits[] // Opslaan in SRAM
In setup initialiseren we de draadloze communicatie, het OLED-display en de real-time clock.
In de loop controleren we constant of er binnenkomende data beschikbaar is via de NRF24L01-modules. Zo ja, lezen we deze met radio.read() en slaan de eerste twee karakters op in de temperatuur-String, de volgende twee in de vochtigheid-String.
We gebruiken millis() om de verschillende data op het display weer te geven op intervallen (3 seconden). We gebruiken millis() in plaats van delay() zodat de rest van de code herhaald kan worden uitgevoerd; met delay() zou het programma wachten en we zouden binnenkomende data van de buiteneenheid kunnen missen.
Met de firstPage() en nextPage()-functies van de U8G2-bibliotheek printen we de vijf verschillende schermen die gedefinieerd zijn in custom functies.
De drawDate()-functie haalt datum en tijd op van de RTC-module en print het op het display. De drawInTemperature()-functie leest de binnentemperatuur en print deze. Dezelfde methode wordt gebruikt voor alle schermen.
Dat was het voor deze tutorial. Ik hoop dat je ervan hebt genoten en iets nieuws hebt geleerd. Stel gerust vragen in de reacties hieronder.
Productieproces
- DIY Zonne-energie Weerstation Met Raspberry Pi
- Een buitenweerstation bouwen met Raspberry Pi 2 en ADS-WS1
- Een Raspberry Pi-weerstation bouwen dat dagelijkse weergegevens e-mailt
- Geavanceerd Weerstation v2.0: Real-time Temperatuur, Druk, Vochtigheid & Hoogte Monitoring
- Arduino Audio Frequentie Detector – Meet de luidste geluidspieken met hoge gevoeligheid
- Slimme Draadloze Lichtschakelaar Controller: Arduino-gebaseerde Remote Switch Manipulator
- Arduino Boter-Kaas-Eieren met MAX7219 LED Matrix en Kartonnen Behuizing
- Bouw een Betrouwbare Arduino Afteltimer met SparkFun 7‑Segment Display
- Bouw een $10 Draagbare Arduino Weerstation (AWS) – Eenvoudige DIY met Nano, DHT22, BMP180 & LCD
- eDOT: Precieze Arduino-klok & weerstation met ingebouwde IR-remote
- Realtime Weerstation met Arduino & ThingSpeak IoT