// Het programma is zo opgebouwt dat het mogelijk is om de sensoren samen te gebruiken, of los van elkaar.
// Je kan de sensoren los van elkaar bekijken door de code die niet bij deze sensor hoort te verwijderen.
// Vervolgens moet de hoofdfunctie van deze sensor van naam veranderen. Bvb. tempLoop -> loop.
//DEFINIEREN VAN VARIABELEN (ENKEL LEERKRACHT) ------------------------------------------------------------------------------
// parameters van de thermistor. Beta is de NTC, meetwaardes zijn bij minimale (-20°C) en maximale temperatuur (80°C).
// Deze waardes zijn afhankelijk van de sensor. Neem ze niet gewoon over maar kijk in de datasheet of test ze (zelfs tussen sensors van hetzelfde type kan verschil zijn)
const float BETA = 3950;
const int MINTEMPEL = 115;
const int MAXTEMPEL = 953;
// Parameters van photosensor. Gamma is heling, RL10 is lux bij 10ohm, meetwaardes zijn in het donkere en bij maximale verlichting.
// Deze waardes zijn afhankelijk van de sensor. Neem ze niet gewoon over maar kijk in de datasheet of test ze (zelfs tussen sensors van hetzelfde type kan verschil zijn)
const float GAMMA = 0.7;
const float RL10 = 50;
const int DONKERLUXEL = 8;
const int LICHTLUXEL = 1015;
// Parameters van vochtsensor. Dit zijn de meetwaardes in lucht en in water.
// Deze waardes zijn afhankelijk van de sensor. Neem ze niet gewoon over maar test ze eerst voor de gebruikte sensor (zelfs tussen sensors van hetzelfde type kan verschil zijn)
const int LUCHTVOCHTEL = 1023;
const int WATERVOCHTEL = 0;
// Definieer enum voor overzichtelijker gebruik van conversiefunctie
typedef enum{
LCD,
RGB,
SRV
} conversie;
// Definieer enum voor overzichtelijker gebruik van grensfunctie
typedef enum{
grensOK,
grensLaag,
grensHoog
} grens;
// Globale variabele die inschakelt wanneer een grens overschreden wordt. Hij schakelt uit wanneer alle paramters terug in de grenzen liggen.
// Deze is nodig om de LED's naar behoren te laten functioneren.
bool grenzenOverschreden=false;
//DEFINIEREN VAN VARIABELEN (LEERKRACHT EN LEERLING) ------------------------------------------------------------------------------
// Bvb. Verander op welke pinnen de verschillende componenten zijn aangesloten.
// Gebruik Liquidcrystal library om LCD aan te sturen
#include <LiquidCrystal.h>
// Geeft verbindingen aan lcd(RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(13, 12, 11, 10, 8, 7);
// Gebruik servo library om servo aan te sturen (de gebruikte servo kan tussen 0° en 180° bewegen)
#include <Servo.h>
// Geef aan hoe de servo heet en welke pin van de arduino deze mee verbonden is
// (zeer belangrijk wanneer je meerdere servo's wilt gebruiken)
Servo servo1;
const int pinServo1 = 9;
// Definieer overige pinnen
const int pinR = 3;
const int pinG = 5;
const int pinB = 6;
const int pomp = 4;
const int schakelaar1 = 2;
const int schakelaar2 = 1;
const int tempSensor = A0;
const int photoSensor = A1;
const int vochtSensor = A2;
// Stel grenswaarden voor biotoop in (in °C, lux en % vochtigheid)
const int GRENSTEMPKOUD = -20;
const int GRENSTEMPWARM = 75;
const double GRENSPHOTODONKER = 10;
const double GRENSPHOTOLICHT = 90000; // Maximale waarde van int = 2^16 = 65536. Een double kan veel verder gaan (maar kost ook meer geheugen)
const int GRENSVOCHTIGLAAG = 5;
const int GRENSVOCHTIGHOOG = 95;
//KLAARMAKEN VAN ARDUINO ------------------------------------------------------------------------------
// Dit wordt uitgevoerd wanneer de Arduino zich reset
void setup() {
// Verbind pin aan servo en beweeg naar beginpositie (ergens tussen 0 en 180°)
servo1.attach(pinServo1);
servo1.write(90); // Hier is gekozen voor 90° als beginpositie
// Geef aan hoe overige pinnen gebruikt worden
pinMode(pinR, OUTPUT);
pinMode(pinG, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(pomp, OUTPUT);
pinMode(schakelaar1, INPUT_PULLUP); // Interne weerstand naar 5V geschakeld
pinMode(schakelaar2, INPUT_PULLUP); // Interne weerstand naar 5V geschakeld
pinMode(tempSensor, INPUT);
pinMode(photoSensor,INPUT);
pinMode(vochtSensor, INPUT);
// Hoeveel karakters heeft het scherm
lcd.begin(16,2);
// Begin seriele communicatie met baudrate van 9600 bits/s
Serial.begin(9600);
}
//CODE VAN TEMPERATUURSENSOR ------------------------------------------------------------------------------
// Conversie voor aansturing LED, servo en LCD
float tempConversie(int sensorwaarde, conversie keuze) {
if (keuze == LCD) {
return 1 / (log(1 / (1023.0 / sensorwaarde - 1)) / BETA + 1.0 / 298.15) - 273.15; // Deze sensor heeft geen lineaire omzetting. Er moet dus een complexe functie gebruikt worden. Indien een andere sensor gebruikt word, moet deze functie ook wijzigen.
}
else if (keuze == RGB){ // Nodig om de kleuren van de LED te regelen
return map(sensorwaarde, MINTEMPEL, MAXTEMPEL, 0, 255); // Sensorwaarde ligt normaal tussen 0 en 1023, maar serial geeft tussen 115 en 953 aan.
}
else if (keuze == SRV){
return map(sensorwaarde, MINTEMPEL, MAXTEMPEL, 0, 180); // Sensorwaarde ligt normaal tussen 0 en 1023, maar serial geeft tussen 115 en 953 aan.
}
}
// Ga na of de ingestelde grenzen niet overschreden zijn.
grens tempGrens(int sensorwaarde) {
float temp = 1 / (log(1 / (1023. / sensorwaarde - 1)) / BETA + 1.0 / 298.15) - 273.15;
if (temp > GRENSTEMPWARM) {
return grensHoog;
}
else if (temp < GRENSTEMPKOUD) {
return grensLaag;
}
else {
return grensOK;
}
}
// Loop voor de temperatuursensor
int tempLoop(bool visualiseer) {
// photosensor meting (waarde van 0-1023)
int sensorwaarde = analogRead(tempSensor);
// Controleer of een grens overschreden is.
grens grensOverschreden = tempGrens(sensorwaarde);
// Toon meetwaardes (op verschillende manieren) enkel wanneer schakelaars juist staan en er in de huidige en voorgaande sensoren geen fouten waren.
if (visualiseer && grensOverschreden == grensOK && !grenzenOverschreden) {
// Vul LCD in
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Temperatuur");
lcd.setCursor(0,1);
lcd.print("Waarde : ");
lcd.print(tempConversie(sensorwaarde, LCD));
lcd.print("C");
// Schrijf waardes naar RGB LED, enkel G en B worden momenteel gebruikt
analogWrite(pinR, 0);
analogWrite(pinG, 255-tempConversie(sensorwaarde, RGB));
analogWrite(pinB, tempConversie(sensorwaarde, RGB));
// Schrijf waarde naar Servo
servo1.write(tempConversie(sensorwaarde, SRV));
// Print ter controle van LCD
Serial.print(sensorwaarde); Serial.print(" El"); Serial.print(" - "); Serial.print(tempConversie(sensorwaarde, LCD) , 2); Serial.print(" C");
Serial.println("");
// Geef aan dat er geen fout is.
return 0;
}
if (grensOverschreden == grensHoog || grensOverschreden == grensLaag) {
// Laat rode LED knipperen
analogWrite(pinR, (millis() / 500) % 2);
analogWrite(pinG, 0);
analogWrite(pinB, 0);
// Print ter controle van LCD
Serial.print(sensorwaarde); Serial.print(" El"); Serial.print(" - "); Serial.print(tempConversie(sensorwaarde, LCD) , 2); Serial.print(" C");
Serial.println("");
// Zet de overschreden grens op de LCD
lcd.clear();
lcd.setCursor(0,1);
lcd.print("TEMP:");
lcd.print(tempConversie(sensorwaarde, LCD));
lcd.print("C");
// Geef aan dat er een fout is.
return 1;
}
}
//CODE VAN LICHTSENSOR ------------------------------------------------------------------------------
// Conversie voor aansturing LED, servo en LCD
float photoConversie(int sensorwaarde, conversie keuze) {
if (keuze == LCD) {
float voltage = sensorwaarde / 1024.0 * 5;
float resistance = 2000 * voltage / (1 - voltage / 5);
return pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA)); // Deze sensor heeft geen lineaire omzetting. Er moet dus een complexe functie gebruikt worden. Indien een andere sensor gebruikt word, moet deze functie ook wijzigen.
}
else if (keuze == RGB) { // Nodig om de kleuren van de LED te regelen
return map(sensorwaarde, DONKERLUXEL, LICHTLUXEL, 0, 255); // sensorwaarde normaal tussen 0 en 1023. Serial geeft tussen 8 en 1015 aan.
}
else if (keuze == SRV) {
return map(sensorwaarde, DONKERLUXEL, LICHTLUXEL, 0, 180); // sensorwaarde normaal tussen 0 en 1023. Serial geeft tussen 8 en 1015 aan.
}
}
// Ga na of de ingestelde grenzen niet overschreden zijn.
grens photoGrens(int sensorwaarde) {
float voltage = sensorwaarde / 1024.0 * 5;
float resistance = 2000 * voltage / (1 - voltage / 5);
float photo = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
if (photo > GRENSPHOTOLICHT) {
return grensHoog;
}
else if (photo < GRENSPHOTODONKER) {
return grensLaag;
}
else {
return grensOK;
}
}
// Loop voor de photosensor
int photoLoop(bool visualiseer) {
// photosensor meting (waarde van 0-1023)
int sensorwaarde = analogRead(photoSensor);
// Controleer of een grens overschreden is.
grens grensOverschreden = photoGrens(sensorwaarde);
// Toon meetwaardes (op verschillende manieren) enkel wanneer schakelaars juist staan en er in de huidige en voorgaande sensoren geen fouten waren.
if (visualiseer && grensOverschreden == grensOK && !grenzenOverschreden) {
// Vul LCD in
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Lumen photo");
lcd.setCursor(0,1);
lcd.print("Waarde:");
lcd.print(photoConversie(sensorwaarde, LCD));
lcd.print("Lux");
// Schrijf waardes naar RGB LED, enkel G en B worden momenteel gebruikt
analogWrite(pinR, 0);
analogWrite(pinG, 255- photoConversie(sensorwaarde, RGB));
analogWrite(pinB, photoConversie(sensorwaarde, RGB));
// Schrijf waarde naar Servo
servo1.write(photoConversie(sensorwaarde, SRV));
//Print ter controle van LCD
Serial.print(sensorwaarde); Serial.print(" El"); Serial.print(" - "); Serial.print(photoConversie(sensorwaarde, LCD) , 2); Serial.print(" Lux");
Serial.println("");
// Geef aan dat er geen fout is.
return 0;
}
if (grensOverschreden == grensHoog || grensOverschreden == grensLaag) {
// Laat rode LED knipperen
analogWrite(pinR, (millis() / 500) % 2);
analogWrite(pinG, 0);
analogWrite(pinB, 0);
//Print ter controle van LCD
Serial.print(sensorwaarde); Serial.print(" El"); Serial.print(" - "); Serial.print(photoConversie(sensorwaarde, LCD) , 2); Serial.print(" Lux");
Serial.println("");
// Zet de overschreden grens op de LCD
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Licht:");
lcd.print(photoConversie(sensorwaarde, LCD));
lcd.print("Lux");
// Geef aan dat er een fout is.
return 1;
}
}
//CODE VAN VOCHTSENSOR ------------------------------------------------------------------------------
// Conversie voor aansturing LED, SERVO en LCD
float vochtConversie(int sensorwaarde, conversie keuze) {
if (keuze == LCD) {
return map(sensorwaarde, LUCHTVOCHTEL, WATERVOCHTEL, 0, 100); // Deze sensor heeft een lineaire omzetting, map kan dus gebruikt worden. Indien een andere sensor gebruikt word, moet deze functie ook wijzigen.
}
else if (keuze == RGB) { // Nodig om de kleuren van de LED te regelen
return map(sensorwaarde, LUCHTVOCHTEL, WATERVOCHTEL, 0, 255); // sensorwaarde normaal tussen 0 en 1023. Serial geeft tussen 8 en 1015 aan.
}
else if (keuze == SRV) {
return map(sensorwaarde, LUCHTVOCHTEL, WATERVOCHTEL, 0, 180); // sensorwaarde normaal tussen 0 en 1023. Serial geeft tussen 8 en 1015 aan.
}
}
// Ga na of de ingestelde grenzen niet overschreden zijn.
grens vochtGrens(int sensorwaarde) {
float vocht = map(sensorwaarde, LUCHTVOCHTEL, WATERVOCHTEL, 0, 100);
if (vocht > GRENSVOCHTIGHOOG) {
return grensHoog;
}
else if (vocht < GRENSVOCHTIGLAAG) {
return grensLaag;
}
else {
return grensOK;
}
}
// Loop voor de vochtsensor
int vochtLoop(bool visualiseer) {
// vochtsensor meting (waarde van 0-1023)
int sensorwaarde = analogRead(vochtSensor);
grens grensOverschreden = vochtGrens(sensorwaarde);
// Toon meetwaardes (op verschillende manieren) enkel wanneer schakelaars juist staan en er in de huidige en voorgaande sensoren geen fouten waren.
if (visualiseer && grensOverschreden == grensOK && !grenzenOverschreden) {
// Vul LCD in
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Rel vochtigheid");
lcd.setCursor(0,1);
lcd.print("Waarde:");
lcd.print(vochtConversie(sensorwaarde, LCD));
lcd.print("%");
// Schrijf waardes naar RGB LED, enkel G en B worden momenteel gebruikt
analogWrite(pinR, 0);
analogWrite(pinG, 255-photoConversie(sensorwaarde, RGB));
analogWrite(pinB, photoConversie(sensorwaarde, RGB));
// Schrijf waarde naar Servo
servo1.write(tempConversie(sensorwaarde, SRV));
//Print ter controle van LCD (Wokwi heeft een bug waardoor het niet altijd mogelijk is om deze sensorwaarde te tonen. In een echte setting werkt dit wel altijd.)
Serial.print(sensorwaarde); Serial.print(" El"); Serial.print(" - "); Serial.print(vochtConversie(sensorwaarde, LCD) , 2); Serial.print(" %");
Serial.println("");
// Geef aan dat er geen fout is.
return 0;
}
if (grensOverschreden == grensHoog || grensOverschreden == grensLaag) {
// Laat rode LED knipperen
analogWrite(pinR, (millis() / 500) % 2);
analogWrite(pinG, 0);
analogWrite(pinB, 0);
//Print ter controle van LCD (Wokwi heeft een bug waardoor het niet altijd mogelijk is om deze sensorwaarde te tonen. In een echte setting werkt dit wel altijd.)
Serial.print(sensorwaarde); Serial.print(" El"); Serial.print(" - "); Serial.print(vochtConversie(sensorwaarde, LCD) , 2); Serial.print(" %");
Serial.println("");
// Zet de overschreden grens op de LCD
lcd.clear();
lcd.setCursor(0,1);
lcd.print("VOCHT:");
lcd.print(vochtConversie(sensorwaarde, LCD));
lcd.print("%");
// Indien de grond te droog is moet de pomp geactiveerd worden
if (grensLaag) {
digitalWrite(pomp, HIGH);
}
// Geef aan dat er een fout is.
return 1;
}
}
//ALGEMENE LOOP ------------------------------------------------------------------------------
// Bevat de drie loops zodat deze samen geactiveerd worden wanneer de biotoop aan staat.
void activeerSensoren(bool visualiseerTemp, bool visualiseerPhoto, bool visualiseerVocht) {
int fouten;
// Tel het aantal fouten op.
fouten = fouten + tempLoop(visualiseerTemp);
fouten = fouten + photoLoop(visualiseerPhoto);
fouten = fouten + vochtLoop(visualiseerVocht);
// Zeg het aantal fouten. Dit is noodzakelijk omdat er meerdere fouten tegelijkertijd kunnen optreden.
if (fouten >= 1) {
lcd.setCursor(0,0);
lcd.print("Overschreden: ");
lcd.print(fouten);
grenzenOverschreden = true;
}
else {
// Zet deze globale parameter terug op false indien alle grenzen in orde zijn.
grenzenOverschreden = false;
}
}
// Deze code wordt continu uitgevoerd.
void loop() {
// Afhankelijk van de stand van de schakelaars wordt 1 van deze "true". Dit bepaald welke info getoond wordt.
bool visualiseerTemp = false;
bool visualiseerPhoto = false;
bool visualiseerVocht = false;
// Vier verschillende standen van de biotoop.
if (digitalRead(schakelaar1) && digitalRead(schakelaar2)) {
visualiseerTemp = true;
activeerSensoren(visualiseerTemp, visualiseerPhoto, visualiseerVocht);
}
else if (!digitalRead(schakelaar1) && digitalRead(schakelaar2)) {
visualiseerPhoto = true;
activeerSensoren(visualiseerTemp, visualiseerPhoto, visualiseerVocht);
}
else if (digitalRead(schakelaar1) && !digitalRead(schakelaar2)) {
visualiseerVocht = true;
activeerSensoren(visualiseerTemp, visualiseerPhoto, visualiseerVocht);
}
else if (!digitalRead(schakelaar1) && !digitalRead(schakelaar2)) { // Arduino staat in "slaapstand"
// zet LCD uit
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Toestel uit");
lcd.setCursor(0,1);
// zet RGB uit
analogWrite(pinR, 0);
analogWrite(pinG, 0);
analogWrite(pinB, 0);
// zet servo uit
servo1.write(90);
}
// Nooit een goed idee om hardware op maximale snelheid te laten draaien. Door delay wacht hij een aantal ms tussen elke loop.
delay(200);
}