DE PROGRAMMEERBARE PLANTENKAS // SENSORDATA OPGESLAGEN IN EEN CSV-BESTAND OP EEN SD KAART VOORZIEN VAN DATA EN TIJD MET EEN REAL TIME CLOCK MODULE
In deze tutorial laten we zien hoe je sensordata die in een CSV-bestand opgeslagen op een microSD kaart wordt met een Arduino microcontroller of een andere microcontroller kan voorzien van een datum en tijd door een Real Time Clock module te gebruiken.
Aansluiten
Wij hebben er voor gekozen om in onze tutorials te werken met een Grove Base Shield en Grove verbindingskabels. Op die manier kunnen de verschillende tutorials makkelijk met elkaar gecombineerd worden. De Real Time Clock met een DS3231 chip wordt meestal geleverd met female of male pinnen voor de verschillende verbindingen. In ons voorbeeld hebben wij een sensor waar uitstekende, ofwel mannelijke, pinnen op zitten. Om deze sensor op de Grove Base Shield aan te sluiten, hebben wij dus een Grove kabel met vrouwelijke, ofwel female, aansluitingen nodig.
Het aansluiten is erg simpel: Je zet de zwarte kabel van de Grove connector op de GND pin, de rode kabel op de VCC pin, de witte kabel op de SDA pin en de gele kabel op de SCL pin. De zwarte kabel is de aarde, terwijl de rode kabel 5 volt naar de sensor toe stuurt. De witte en gele kabel brengen informatie over de datum en tijd over naar Arduino, via een I2C verbinding. De Grove connector sluit je dan ook aan op een I2C port van de Grove Base Shield.
Programmeren
De code voor dit programma bestaat uit twee delen: Het creëren van een CSV-bestand op een SD kaart en het instellen en activeren van een Real Time Clock module. In het artikel "De Programmeerbare Plantenkas: Sensordata opslaan in een CSV-bestand op een SD kaart", hebben we uitgebreidt uit gelegd hoe je data een CSV-bestand op een SD kaart op slaat met een microcontroller. Deze uitleg laten we in deze tutorial daarom weg, om het niet onnodig lang te maken.
Om een Real Time Clock module uit te lezen, maken we gebruik van een bibliotheek die RTClib heet. Deze bibliotheek, die via de Arduino IDE te downloaden is, is eenvoudig in gebruik. Om de bibliotheek in onze code the
activeren, geven we het commando #include "RTClib.h"
. Vervolgens geven we het commando RTC_DS3231 rtc;
om de bibliotheek te vertellen dat wij onze klok "rtc" gaan
noemen. Uiteraard kun je elke naam gebruiken die je wilt.
In dit voorbeeld bestaat ons CSV-bestand uit twee kolommen met data, namelijk eentje waar de datum in komt te staan, en eentje waar de tijd in komt te staan. Hiervoor maken we de variabelen
datum en tijd aan met het commando String datum, tijd;
. Om deze twee kolommen makkelijk af te printen, slaan we de informatie die in een nieuwe rij moet komen op in de variabele
csvRij. Deze variabele maken we aan met het commando String csvRij;
.
In de setup fase van het programma moeten we de communicatie tussen de microcontroller en de klok module aanzetten. Dit doen we met het commando rtc.begin();
. Vervolgens
synchroniseren we de datum en tijd van de klok module met die van de computer, met het commando rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
. Zo weten we zeker dat we de juiste
datum en tijd registeren.
Het ophalen van de datum en tijd uit de klok module doen we in een aparte functie. Om de functie te maken, geven we eerst het commando <code>String datumtijdRTC()</code>. Vervolgens zetten we tussen de {} de commando's die de functie moet uitvoeren als de functie in de loop fase wordt geactiveerd.
Het eerste wat we doen in onze functie is vijf tijdelijke variabelen aan maken, met het commando String dag, maand, jaar, uren, minuten;
. Hierin slaan we alle losse "onderdelen" op
van de datum en de tijd. Daarna geven we het commando DateTime now = rtc.now();
. Dit zorgt ervoor dat de datum en tijd uit de klok module wordt opgehaald.
Om alle losse stukjes informatie over de datum op te slaan, geven we de commando's dag = now.day();
, maand = now.month();
en jaar = now.year();
. Dit zijn
commando's uit de bibliotheek die de dag, de maand en het jaar uit de klok module halen. Vervolgens willen we deze drie stukjes informatie samen voegen tot een datum. Dit doen we met het commando
datum = String(dag) + "-" + String(maand) + "-" + String(jaar);
. Dit plakt dus de dag als een cijfer, dan een streepje, dan de maand als een cijfer, dan weer een streepje, en
vervolgens het jaar aan elkaar tot één regel.
Om de tijd op te slaan doen we ongeveer hetzelfde. We beginnen weer met het aantal uren en minuten op te slaan, met het commando uren = now.hour();
en het commando minuten =
now.minute();
. Eventueel kun je hier ook nog seconden aan toevoegen, door aan het begin van de functie en variabele voor seconden te creëren en dan het commando seconden =
now.seconds();
te geven. Om deze losse delen samen te voegen tot een tijd geven we het commando tijd = String(uren) + ":" + String(minuten);
.
In de loop fase beginnen we met het resetten van de variabelen csvRij, door het commando csvRij = "";
te geven. Vervolgens activeren we de functie die we net gemaakt hebben, met het
commando datumtijdRTC();
. Wij hebben er in dit voorbeeld voor gekozen om csvRij in het loop gedeelte te "vullen", omdat je dan makkelijk data van sensoren die met andere functies
kunt toevoegen. Om de variabele csvRij van een nieuwe rij data te voorzien geven we eerst het commando csvRij += datum;
. Dit voegt de datum die we in onze functie hebben gemaakt toe.
Vervolgens geven we het commando csvRij += ",";
. Dit zet een komma achter de datum. Bij een CSV-bestand worden enters gebruikt om aan te geven dat er een nieuwe rij begint, en
komma's om aan te geven dat de volgende kolom begint. Vervolgens geven we het commando csvRij += tijd;
om de tijd toe te voegen. De variabele csvRij bevat nu dus de datum en tijd,
gescheiden door een komma, bijvoorbeeld 01-09-2021,10:22.
Vervolgens willen we de csvRij afprinten in ons CSV-bestand. Dit doen we door eerst het SD bestand te openen met het commando File dataFile = SD.open("bestand.csv", FILE_WRITE);
.
Daarna printen we csvRij af op een nieuwe rij, met het commando dataFile.println(csvRij);
. Om de nieuwe rij op te slaan in het bestand, sluiten we af met het commando
dataFile.close();
.
Uiteraard is het de bedoeling dat er nog extra informatie over sensoren wordt toegevoegd aan het CSV-bestand, zodat je later kan analyseren hoe en bepaalde variabele, zoals de hoeveelheid licht
of de temperatuur, veranderd. Deze data voeg je simpelweg toe aan de variabele csvRij door eerst het commando csvRij += ","
te geven, zodat de gegevens in aparte kolommen terecht
komen, en dan het commando csvRij += naam_variabele_met_sensordata
te geven. Het is aan te raden om niet constant nieuwe data in het CSV-bestand te zetten, maar om een delay toe
te voegen, zodat er wat tijd tussen de verschillende metingen zit. Hoeveel tijd dit moet zijn, hangt helemaal af van jouw project.
ARDUINO IDE CODE
/* Voorbeeld code gemaakt door www.foodplanting.com voor de Programmeerbare Plantenkas serie. Deze code is gemaakt voor een Real Time Clock module (DS3231 of DS1307) en een Ethernet Shield met microSD kaart houder. Deze code maakt gebruikt van de SD bibliotheek. Meer info over deze bibliotheek vindt je hier: https://www.arduino.cc/en/Reference/SD Deze code maakt ook gebruik van de RTClib bibliotheek. Meer info over deze bibliotheek vindt je hier: https://github.com/adafruit/RTClib Deze code is zeer minimalistisch, omdat het idee is dat deze code gecombineerd wordt met codes voor andere modules. Zo wordt de tijd bijvoorbeeld niet in de loop fase, maar in een aparte functie op geroepen en wordt de tijd niet in de Serial Monitor af geprint. */ // Voorbereiding: #include "RTClib.h" // Dit laadt de bibliotheek die nodig is om de klok te lezen. RTC_DS3231 rtc; // Dit verteld de bibliotheek hoe we de klok gaan noemen. String datum, tijd; // Dit creëert globale variabelen waarin de datum en tijd wordt opgeslagen. #include <SD.h> // Dit laadt de bibliotheek die nodig is om de SD kaart te bedienen. const int chipSelect = 4; // Vertel op welke pin de SD kaart zit aangesloten, bij de Arduino UNO en MEGA die wij gebruiken is dit pin 4. String csvRij; // Dit creëert globale variabelen waarin de rij komt die in de CSV wordt geprint. // Setup fase: void setup() { rtc.begin(); // Zet de communicatie tussen de microcontroller en de klok aan. rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // // Synchroniseer de tijd van de klok met die van de computer. SD.begin(chipSelect); // Zet de communicatie tussen de microcontroller en de microSD kaart aan. File dataFile = SD.open("bestand.csv", FILE_WRITE); // Open een (nieuw) CSV bestand op de microSD kaart. String header = "Datum,Tijd"; // Header (eerste rij) van CSV bestand met namen van kolommen. dataFile.println(header); // Print de header in het CSV bestand. dataFile.close(); // Sluit het CSV bestand om de wijzigingen op te slaan. } // Loop fase: void loop() { csvRij = ""; // Reset de informatie voor de nieuwe rij. datumtijdRTC(); // Vraag de microcontroller om de functie die de tijd en temperatuur uit de klok ophaalt uit te voeren. csvRij += datum; // Voeg de datum toe aan de rij. csvRij += ","; // Een komma zorgt ervoor dat Excel of een ander data programma weet wat in welke kolom hoort. csvRij += tijd; // Voeg de tijd toe aan de rij. File dataFile = SD.open("bestand.csv", FILE_WRITE); // Open het CSV bestand op de microSD kaart. dataFile.println(csvRij); // Print een nieuwe rij met de tijd. dataFile.close(); // Sluit het CSV bestand om de wijzigingen op te slaan. } // Functie voor klok: String datumtijdRTC() { String dag, maand, jaar, uren, minuten; // Dit creëert vijf tijdelijke variabelen om de losse informatie over de datum en tijd in op te slaan. DateTime now = rtc.now(); // Lees de tijd af uit de klok. dag = now.day(); // Sla de dag op. maand = now.month(); // Sla de maand op. jaar = now.year(); // Sla het jaartal op. datum = String(dag) + "-" + String(maand) + "-" + String(jaar); // Voeg de dag, maand en jaar samen tot een datum. uren = now.hour(); // Sla het uur op. minuten = now.minute(); // Sla de minuten op. tijd = String(uren) + ":" + String(minuten); // Voeg de minuten en uren samen tot een tijd. return datum, tijd; }
Alternatieven
In vergelijking met sensoren is er niet heel veel keus als het om Real Time Clock modules gaat. Wij hebben ook de Real Time Clock met een DS1307 chip uit geprobeerd. Deze sluit je net zoals een Real Time Clock met een DS3132 chip aan op een IC2 port van de Grove Base Shield en werkt ook met de code die we hierboven hebben uitgelegd. Het enige verschil tussen de Grove Real Time Clock met de DS1307 chip en de Real Time Clock met de DS3132 chip is dat de Grove versie geen temperatuursensor heeft.
Het voordeel van deze module is dat er een Grove connector op zit, waardoor het nog minder moeite kost om de module aan te sluiten. Het nadeel is dat de CR1225 batterij die in de module moet niet meegeleverd wordt en niet de meest standaard batterij is. Ook is de Grove Real Time Clock module meestal iets duurder dan een "gewone" module.
Vragen en opmerkingen
We proberen de serie DE PROGRAMMEERBARE PLANTENKAS zo toegankelijk mogelijk te maken voor iedereen. Toch zijn sommige concepten best wel ingewikkeld, omdat er kennis van heel veel verschillende domeinen, zoals natuurkunde, elektrotechniek en computerwetenschappen, samen komen. Het kan daarom best zijn dat we iets niet goed uitgelegd hebben. Mocht er iets niet duidelijk zijn of iets niet zo werken zoals we het in deze tutorial uitgelegd hebben, stuur dan gerust een berichtje via de Disqus op deze pagina. Je kunt de Disqus vinden door naar beneden te scrollen, tot onder de advertenties.