Pompsturing vertraagd - analogread

Beste specialisten,
Ik lees een voltage van 0-5V uit via de analoge pin op de arduino en print dit op een LCD-scherm.
Nu wil ik een relais sturen onder volgende voorwaarden:

  • Als het voltage <1 dan schakelt de relais uit.
  • Als het voltage >=1 dan schakelt de relais in.
  • Als het voltage opnieuw onder 1 zakt dan moet de relais nog 5sec aan blijven alvorens terug uit te schakelen.
    Het voltage moet ten allen tijde op het scherm blijven verschijnen.

Ik heb al vanalles geprobeerd (zoals while en do while) maar deze functies blokkeren na 1 uitlezing van de analoge pin.
Kan iemand mijn code eens bekijken en zeggen wat ik fout doe aub? (de vertraging van 5 seconden zit nog niet in de code verwerkt)

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);

int sensorValue = 0;         // variable to store the value coming from the sensor
int sensorPin = A0;          // select the input pin
float voltage = 0;

// the setup routine runs once when you press reset:
void setup() {
  // configuratie pins (groene led van de relais is uit bij HIGH en aan bij LOW)
  pinMode(13, OUTPUT);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Pompsturing");
  lcd.setCursor(0,1);
  lcd.print("Zonnepanelen");
  lcd.setCursor(0,2);
  lcd.print("By Gorres");
  delay(2000);
  lcd.clear();
}

// the loop routine runs over and over again forever:
void loop() {
  int sensorValue = analogRead(sensorPin);                      //readpin and convert to real voltage value
  float voltage = sensorValue * (5.0 / 1023.0);
  voltage = 0.92*voltage;
  
  while(voltage>=1)  {                    // as long as voltage>=1 switch relais LOW and print the voltage                         
  digitalWrite(13, LOW);
  lcd.setCursor(0,2);
  lcd.print("Pomp: AAN");
  lcd.setCursor(0,0);
  lcd.print("V(0-5)   :");
  lcd.print(voltage);
  lcd.print("V");
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.print("V(0-10)  :");
  lcd.print(voltage*20/10.0);
  lcd.print("V");
  lcd.print(" ");
  delay(500);
  int sensorValue = analogRead(sensorPin);
  float voltage = sensorValue * (5.0 / 1023.0);
  voltage = 0.92*voltage;
  }
                                           // as long as voltage<1 switch relais HIGH and print the voltage  
  while(voltage < 1)  {                     
  digitalWrite(13, HIGH);
  lcd.setCursor(0,2);
  lcd.print("Pomp: UIT");
  lcd.setCursor(0,0);
  lcd.print("V(0-5)   :");
  lcd.print(voltage);
  lcd.print("V");
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.print("V(0-10)  :");
  lcd.print(voltage*20/10.0);
  lcd.print("V");
  lcd.print(" ");
  delay(500);
  int sensorValue = analogRead(sensorPin);
  float voltage = sensorValue * (5.0 / 1023.0);
  //voltage = 0.9653*voltage + 0.0155;
  voltage = 0.92*voltage;
  }
  }

Je hoeft je relais maar 1 keer aan of uit te doen. While moet dus if worden. delay(500) zorgt al voor obstructie. Gebruik dit alleen in een setup waar je bijvoorbeeld een scherm x tijd wil laten zien. Voor de rest gebruiken met heel veel terughoudendheid. Een vertraging maak je beter met millis.

if(voltage <1 && !digitalRead(13)){
  digitalWrite(13, HIGH);
  lcd.setCursor(0,2);
  lcd.print("Pomp: AAN");
}

if(voltage >= 1 && digitalRead(13)){
  digitalWrite(13, LOW);
  lcd.setCursor(0,2);
  lcd.print("Pomp: UIT");
}

lcd.setCursor(0,0);
  lcd.print("V(0-5)   :");
  lcd.print(voltage);
  lcd.print("V");
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.print("V(0-10)  :");
  lcd.print(voltage*20/10.0);
  lcd.print("V");
  lcd.print(" ");

Goede dag

Om te voorkomen dat het relais heen en weer schakelt in het werkpunt, kun je ook een schakelhysterese invoegen.

Nog een fijne dag en veel plezier met coderen in C++.

Bedankt voor de uitleg, ik begrijp het nu. Ik heb de code gewijzigd en mijn project wat overzichtelijker gemaakt :+1:t2:
Ook het gebruik van millis, daar heb ik nu enkele introductiefilmpjes van bekeken en zal ik in de toekomst trachten gebruiken ipv delay.
Bedankt voor de tips buckfast_beekeeper :smiley:

Hey Paulpaulson,
Kan je me daar wat meer info over bezorgen?
Of de code aanpassen zodat de relais met een vertraging van 5sec uit gaat?
Want nu praat je een andere taal denk ik :expressionless:

je definitie van sensorpin :int sensorpin=A0 klopt niet maak er eens 14 van wellicht werkt dat wel, je kunt het zien omdat elk getal is netjes blauw behalve A0 en terecht.

A0 is niet altijd pin 14; hangt maar net af van de Arduino.

Verder zegt de kleur weinig; syntax highlighting op het forum kan best wel eens anders werken dan in de IDE.

Eerst enkele bedenkingen. Een pomp associeer ik met water. Maar dat heeft niks met een analoge spanning. Tenzij je een temperatuur gaat meten met een ntc of ptc. Is het dan niet handiger de temperatuur te meten met een DS18B20? Heb je ineens een digitale temperatuur. Een analoge meting is volledig afhankelijk van de precisie van je referentiespanning.

5 seconden delay, is de pomp daar gelukkig mee? In het slechtste geval is het 5 seconden draaien en 5 seconden stilstand.

Ik heb ook je originele code nog eens beter bekeken. Waar gaat het echt fout?

In je loop declareer je 4 keer int sensorValue = analogRead(sensorPin);
Hetzelfde doe je met float voltage.
De eerste blijft altijd bestaan want die werd gedeclareerd voor je setup werd uitgevoerd. Die bestaat ook in al je andere functies en procedures. De volgende maak je met dezelfde naam aan in je loop. Deze blijft bestaan binnen de ganse loop. Daarna doe je hetzelfde in je while. Uiteraard weet de compiler niet meer over welke sensorValue je het hebt. Die int en float moeten dus uit je loop verdwijnen.

In het begin van je loop vraag je de sensorValue op. Maar dat doe je terug in je while. Denk je dat die binnen enkele tikken zal wijzigen?

voltage = sensorValue * (5 / 1023); Daarna voltage = 0.92 * voltage. Waarom niet

voltage = sensorValue * 5 / 1023 * 0.92;

De haken zijn ook niet nodig volgorde van de bewerkingen staan vermenigvuldigen en delen op gelijk niveau.

Het kan nog korter

voltage = analogRead(sensorPin) * 5 / 1023 * 0,92;

Nu code met 5 seconden meet delay.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);

//int sensorValue = 0;         // variable to store the value coming from the sensor
const int sensorPin = A0;          // select the input pin
const int pompPin = 13;
const bool AAN = HIGH;
const bool UIT = LOW;
float voltage = 0;
float oldVoltage;
unsigned long readTime;
const unsigned long READ_DELAY = 5000; // wachttijd voor het meten. Zo snel gaat water niet in temperatuur veranderen

// the setup routine runs once when you press reset:
void setup() {
  // configuratie pins (groene led van de relais is uit bij HIGH en aan bij LOW)
  pinMode(13, OUTPUT);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Pompsturing");
  lcd.setCursor(0, 1);
  lcd.print("Zonnepanelen");
  lcd.setCursor(0, 2);
  lcd.print("By Gorres");
  delay(2000);
  lcd.clear();
}

// the loop routine runs over and over again forever:
void loop() {
  if(readTime <= millis()){
    readTime = millis() + READ_DELAY;
    voltage = analogRead(sensorPin) * 5.0 / 1023.0 * 0.92;
  }
  
  if (voltage != oldVoltage) {// wordt alleen uitgevoerd als de waarde wijzigt
    oldVoltage = voltage;
    if (voltage < 1 && digitalRead(pompPin) == UIT) {
      digitalWrite(pompPin, AAN);
      lcd.setCursor(0, 2);
      lcd.print("Pomp: AAN");
    }

    if (voltage >= 1 && digitalRead(pompPin) == AAN) {
      digitalWrite(pompPin, UIT);
      lcd.setCursor(0, 2);
      lcd.print("Pomp: UIT");
    }

    lcd.setCursor(0, 0);
    lcd.print("V(0-5)   :");
    lcd.print(voltage);
    lcd.print("V");
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print("V(0-10)  :");
    lcd.print(voltage * 20 / 10.0);
    lcd.print("V");
    lcd.print(" ");
  }
}

Op dezelfde wijze kan je een delay toevoegen voor het op en af zetten.

Wanneer je een water sensor voor je plantenbak hebt (een printje met wat ongeïsoleerde printsporen naast elkaar die je in de grond steekt), dan meet je dus het water nivo met een analoge spanning.

Ik denk niet dat dit hier aan de orde is.

Ik denk hierdoor eerder aan een zonneboiler.

Niet geïsoleerde printsporen zullen in die vochtige, meestal iets wat zure, omgeving snel corroderen. Ook dan klopt de gemeten waarde niet meer.

:grin: het betreft inderdaad een zelfgemaakte zonneboiler. Hier de gedetailleerde uitleg van mijn project:
Een module genaamd GPControl leest de slimme elektriciteitsmeter uit. Vanaf dat er elektriciteit naar het net vloeit, gaat de GPControl een stuurspanning van 0-10V verhogen tot er geen elektriciteit meer naar het net vloeit. De stuurspanning wordt door een CarloGavazi omgezet naar 220V die een verwarmingselement stuurt van 3KW. Dit verwarmingselement hangt in een watervatje aangesloten op de CV. De GPControl stuurt zo 2 CarloGavazi's aan dus in totaal 6KW vermogen warm water op de CV. (Met buffervat) Een spanningsdeler (2X10K) zet de stuurspanning van de GPControl om in een 0-5V leesbare spanning op de A0 poort van de Arduino. De relais op de Arduino (Pin13) zet de waterpomp aan of uit vanaf het moment dat er spanning komt op het verwarmingselement. Om te voorkomen dat deze waterpomp constant aan/uit knippert wanneer er 'schapenwolkjes' zijn die de spanning even naar beneden halen, dien ik een vertraging in te bouwen op het uitzetten van de waterpomp. In mijn schets heb ik voorlopig 5 seconden genomen om het systeem te kunnen testen. Uiteraard dien in het in de praktijk verder af te stellen.
Leuk dat jullie mee denken :+1:t2:

Hopelijk houd je ook de watertemperatuur in het oog.

Op de verwarmingselementen staat een ingebouwde instelbare thermostaat (ingesteld op 60°).
Als het systeem werkt, dan ben ik van plan om ook nog een bijkomende thermostaat te plaatsen (80°) als extra beveiliging van het watervat.

Carlo Gavazzi is een merk dat PLC's (en/of diens componenten) produceert, dus voor degenen die dat niet herkennen, vervang de merknaam door "PLC".

buckfast,

Mijn code ziet er momenteel dus zo uit:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);

int sensorValue = 0;         // variable to store the value coming from the sensor
int sensorPin = A0;          // select the input pin
float voltage = 0;
const unsigned long timer_1 = 5000;
unsigned long currentMillis;
unsigned long setTimer;

////////////////////// SETUP ///////////////////////////////////
void setup() {
  pinMode(13, OUTPUT);          // configuratie pin13 (groene led van de relais is uit bij HIGH en aan bij LOW)
  lcd.init();                   // Startup display
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Pompsturing");
  lcd.setCursor(0,1);
  lcd.print("Zonnepanelen");
  lcd.setCursor(0,2);
  lcd.print("By Gorres");
  delay(2000);
  lcd.clear();
}

////////////////////// VOID LOOP ///////////////////////////////////
void loop() {
  int sensorValue = analogRead(sensorPin);              //Read and calculate voltage
  float voltage = sensorValue * (5.0 / 1023.0);
  voltage = 0.92*voltage;

  lcd.setCursor(0,0);                                   //Print voltage to LCD
  lcd.print("V(0-5)   :");
  lcd.print(voltage);
  lcd.print("V");
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.print("V(0-10)  :");
  lcd.print(voltage*20/10.0);
  lcd.print("V");
  lcd.print(" ");
    
  if(voltage <1 && !digitalRead(13)){                   //Zet pomp UIT <1V
    digitalWrite(13, HIGH);
    lcd.setCursor(0,2);
    lcd.print("Pomp: UIT");
    }
  
  if(voltage >= 1 && digitalRead(13)){                   //Zet pomp AAN >=1V
    digitalWrite(13, LOW);
    lcd.setCursor(0,2);
    lcd.print("Pomp: AAN");
}
delay(500);                                              //vertraag het programma een halve seconde zodat het LCD kan volgen
}

Ik begrijp de millis maar ik krijg ze van geen kanten in mijn project om de relais met 5 seconden vertraging te laten uitvallen terwijl de gelezen spanningen netjes blijven verschijnen op het scherm :weary:
Ik heb al vanalles geprobeerd maar het lukt me niet. PLEASE HELP :face_with_spiral_eyes:

je hebt wel een variabele gedeclareerd om een tijd bij te houden maar je doet er niets mee.

Wat je zou kunnen doen is in

 if(voltage <1 && !digitalRead(13))    //Zet pomp UIT <1V
{   currentMillis = millis(); // hier lees je de systeemteller en geef je de variabele deze waarde
    do // hier begin je een lus
    {  }  // In de lus doe je niets
    while (currentMillis + timer_1 <= millis());  // hier controleer je of je aan de voorwaarde voldoet om de lus te verlaten. in dit geval of de 5000 milliseconde zijn verstreken na het bewaren van currentMillis
    lcd.setCursor(0,2);
    lcd.print("Pomp: UIT");
    digitalWrite(13, HIGH); // je hebt de lus verlaten en zet je relais hoog
 
}

Nog een algemene opmerking. Aangezien je eigenlijk een eenvoudige vraag stelt vermoed ik dat je weinig tot geen programeer kennis en ervaring hebt. Om dan met die weinige kennis aan iets complex te gaan sleutelen zoals warmte opslag van een zonneboiler in combinatie met PV waarbij veiligheid (gezien de vele branden) toch al enigszins onder druk staat, lijkt dat mij niet de meest verstandig aanpak.

1 Like

@Frits1956

Ik heb even de vrijheid genomen om de code tags aan te passen.

2 Likes

Thx, maakt het een heel stuk leesbaarder.

Hey Frits,

Alvast bedankt voor het meedenken. Ik heb inderdaad weinig ervaring met programmeren. Dat wil echter niet zeggen dat ik geen kennis heb over veiligheid. Natuurlijk bouw ik in mijn project good old-fashion mechanische veiligheden die de elektrische sturingen uiteindelijk nog overrulen bij het minste probleem. Hopelijk kan ik je hiermee gerust stellen. :wink:

Mijn "eenvoudige vraag" blijkt echter toch niet zo eenvoudig te zijn,... want het werkt niet :face_with_diagonal_mouth: Hij blijft gewoon schakelen zonder vertraging.
(Of heeft deze leek weer iets over het hoofd gezien?)

////////////////////// VOID LOOP ///////////////////////////////////
void loop() 
{ int sensorValue = analogRead(sensorPin);              //Read and calculate voltage
  float voltage = sensorValue * (5.0 / 1023.0);
  voltage = 0.92*voltage;

  lcd.setCursor(0,0);                                   //Print voltage to LCD
  lcd.print("V(0-5)   :");
  lcd.print(voltage);
  lcd.print("V");
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.print("V(0-10)  :");
  lcd.print(voltage*20/10.0);
  lcd.print("V");
  lcd.print(" ");
    
  if (voltage <1 && !digitalRead(13))                    //Zet pomp UIT <1V
  { currentMillis = millis();
    do {
    }
    while (currentMillis + timer_1 <= millis());          //Controleer of timer verstreken is
    digitalWrite(13, HIGH);
    lcd.setCursor(0,2);
    lcd.print("Pomp: UIT");
  }
  if (voltage >= 1 && digitalRead(13))                   //Zet pomp AAN >=1V
  {  digitalWrite(13, LOW);
    lcd.setCursor(0,2);
    lcd.print("Pomp: AAN");

Dit lijkt een moeilijke implementatie van delay() dus kun je net zo goed delay() gebruiken.

Verder is optellen een beetje uit den boze. Dit is de betere implementatie

while(millis(0 - currentMillis >= timer_1)

Maar dat zal je probleem nog niet oplossen.