Weather Station - Pluviometer Problems

Hello there! I'm making a weather station that reads air temperature, soil temperature, air humidity, CO2 levels, soil humidity and amount of rain, while using a datalogger shield.
Ive managed to make all the sensors work together, but the pluviometer. I believe that its a code problem, id be so glad if you could help me! Thank you!

#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <DHT.h>
#define DHTPIN 7     
#define DS18B20 8
OneWire ourWire(DS18B20);
DallasTemperature sensors(&ourWire);
#define DHTTYPE DHT22  
DHT dht(DHTPIN, DHTTYPE); 
#define anInput     A0                        //analog feed from MQ135
#define digTrigger   2                        //digital feed from MQ135
#define co2Zero     11                        //calibrated CO2 0 level
int chk;
float hum; 
float temp; 
int chipSelect = 53;
File mySensorData;
const int REED = 9;              //The reed switch outputs to digital pin 9
int val = 0;                    //Current value of reed switch
int old_val = 0;                //Old value of reed switch
int REEDCOUNT = 0; 


String time ;   
tmElements_t tm; 


 

String Now(){
 String time = "";
 if (RTC.read(tm)) {
       //time = String(tm.Hour+":"+tm.Minute+":"+tm.Secnd+" DAY : "+tm.Day+"/"+tm.Month+"/"+tmYearToCalendar(tm.Year));
   time+=tm.Hour;
   time+=":";

   time+=tm.Minute;
   time+=":";

   time+=tm.Second;
   time+=" DIA:";

   time+=tm.Day;
   time+="/";

   time+=tm.Month;
   time+="/";

   time+=tmYearToCalendar(tm.Year);
 } 
 else {
   time = "NO";
   if (RTC.chipPresent()) {
     Serial.println("The DS1307 is stopped.  Please run the SetTime");
     Serial.println("example to initialize the time and begin running.");
     Serial.println();
   } 
   else {
     Serial.println("DS1307 read error!  Please check the circuitry.");
     Serial.println();
   }
 }
 return time;
}

void setup()
{

 Serial.begin(9600);
 pinMode (REED, INPUT_PULLUP); //This activates the internal pull up resistor
 sensors.begin(); 
 dht.begin();
 pinMode(anInput,INPUT);                     //MQ135 analog feed set for input
 pinMode(digTrigger,INPUT);                  //MQ135 digital feed set for input
 pinMode(53, OUTPUT);
 SD.begin(chipSelect);
 digitalWrite(9,HIGH);

 
 
}

void loop()
{
   mySensorData= SD.open("test.txt", FILE_WRITE);
   if (mySensorData) {
              time = Now()+" Sensor Values: ";
              Serial.println(time);       
   val = digitalRead(REED);      //Read the status of the Reed swtich           
   hum = dht.readHumidity();
   temp= dht.readTemperature();
   Serial.print("Humidade do Ar: ");
   Serial.print(hum);
   Serial.print("%, Temperatura do Ar: ");
   Serial.print(temp);
   Serial.println("ºC");
   sensors.requestTemperatures();//SOLICITA QUE A FUNÇÃO INFORME A TEMPERATURA DO SENSOR
   Serial.print("Temperatura do Solo: "); //IMPRIME O TEXTO NA SERIAL
   Serial.print(sensors.getTempCByIndex(0)); //IMPRIME NA SERIAL O VALOR DE TEMPERATURA MEDIDO
   Serial.println("ºC"); //IMPRIME O TEXTO NA SERIAL
   int co2now[10];                               //int array for co2 readings
   int co2raw = 0;                               //int for raw value of co2
   int co2comp = 0;                              //int for compensated co2 
   int co2ppm = 0;                               //int for calculated ppm
   int zzz = 0;                                  //int for averaging

   for (int x = 0;x<10;x++){                   //sample co2 10x over 2 seconds
   co2now[x]=analogRead(A0);
   
 }

   for (int x = 0;x<10;x++){                     //add samples together
   zzz=zzz + co2now[x];
   
 }
   co2raw = zzz/10;                            //divide samples by 10
   co2comp = co2raw - co2Zero;                 //get compensated value
   co2ppm = map(co2comp,0,1023,400,5000);      //map value for atmospheric levels

   Serial.print("CO2 Level: ");               //print title
   Serial.print(co2ppm);                      //print co2 ppm
   Serial.println(" PPM");                      //print units
   
   mySensorData.print(time);
   mySensorData.print(temp);
   mySensorData.print(", ");
   mySensorData.print(hum);
   mySensorData.print(", ");
   mySensorData.print(sensors.getTempCByIndex(0));
   mySensorData.print(", ");
   mySensorData.println(co2ppm);
   mySensorData.close();
   delay(5000);
   
   {
if ((val == LOW) && (old_val == HIGH)){    //Check to see if the status has changed

  delay(10);                   // Delay put in to deal with any "bouncing" in the switch.

  REEDCOUNT = REEDCOUNT + 1;   //Add 1 to the count of bucket tips

  old_val = val;              //Make the old value equal to the current value
      Serial.print(time);
      Serial.print("Medida de chuva (contagem): ");
      Serial.print(REEDCOUNT);//*0.2794); 
      Serial.println(" pulso");
      Serial.print("Medida de chuva (calculado): ");
      Serial.print(REEDCOUNT*0.25); 
      Serial.println(" mm");
      
      } 

    else {

  old_val = val;              //If the status hasn't changed then do nothing
    }
  

}
}  
}

nosa.ino (4.98 KB)

First of all: edit your post and insert code tags!

Post a link to your pluviometer!

My guess is that you don't get the changes on the reed contact because your other sensors need too much time to read. You either have to restructure the code to read that input pin much more often or use an interrupt to count those changes. But depending on the construction of the meter this might not be necessary, most cheap rain gauges only give a short pulse so you need that.

The forum software has made a bit of a mess of your improperly posted code. Read the forum guidelines to see how to post code. Please use the IDE autoformat tool (ctrl-t or Tools, Auto Format) before posting code.

Have you written a small program that reads the pluviometer, only, to make sure that it works in isolation?

My rain gauge uses an interrupt so as not to miss pulses.

pylon:
First of all: edit your post and insert code tags!

Post a link to your pluviometer!

My guess is that you don't get the changes on the reed contact because your other sensors need too much time to read. You either have to restructure the code to read that input pin much more often or use an interrupt to count those changes. But depending on the construction of the meter this might not be necessary, most cheap rain gauges only give a short pulse so you need that.

.

Tried to do an interrupt but came out with nothing :u

#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <DHT.h>
#define DHTPIN 7     
#define DS18B20 8
OneWire ourWire(DS18B20);
DallasTemperature sensors(&ourWire);
#define DHTTYPE DHT22  
DHT dht(DHTPIN, DHTTYPE); 
#define anInput     A0                        //analog feed from MQ135
#define digTrigger   2                        //digital feed from MQ135
#define co2Zero     11                        //calibrated CO2 0 level
int chk;
float hum; 
float temp; 
int chipSelect = 53;
File mySensorData;
const int REED = 3;              //The reed switch outputs to digital pin 9
long int val = 0;                    //Current value of reed switch
long int old_val = 0;                //Old value of reed switch
long int REEDCOUNT = 0; 


String time ;   
tmElements_t tm; 

void chovendoPluvi();
  

String Now(){
  String time = "";
  if (RTC.read(tm)) {
        //time = String(tm.Hour+":"+tm.Minute+":"+tm.Secnd+" DAY : "+tm.Day+"/"+tm.Month+"/"+tmYearToCalendar(tm.Year));
    time+=tm.Hour;
    time+=":";

    time+=tm.Minute;
    time+=":";

    time+=tm.Second;
    time+=" DIA:";

    time+=tm.Day;
    time+="/";

    time+=tm.Month;
    time+="/";

    time+=tmYearToCalendar(tm.Year);
  } 
  else {
    time = "NO";
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } 
    else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
  }
  return time;
}

void setup()
{
 
  Serial.begin(9600);
  pinMode (REED, INPUT_PULLUP); //This activates the internal pull up resistor
  sensors.begin(); 
  dht.begin();
  pinMode(anInput,INPUT);                     //MQ135 analog feed set for input
  pinMode(digTrigger,INPUT);                  //MQ135 digital feed set for input
  pinMode(53, OUTPUT);
  SD.begin(chipSelect);
  digitalWrite(3,HIGH);
  attachInterrupt(digitalPinToInterrupt(REED), chovendoPluvi, CHANGE);
  
  
}

void loop()
{
    mySensorData= SD.open("test.txt", FILE_WRITE);
    if (mySensorData) {
               time = Now()+": ";
               Serial.println(time);       
    val = digitalRead(REED);      //Read the status of the Reed swtich           
    hum = dht.readHumidity();
    temp= dht.readTemperature();
    Serial.print("Humidade do Ar: ");
    Serial.print(hum);
    Serial.print("%, Temperatura do Ar: ");
    Serial.print(temp);
    Serial.println("ºC");
    sensors.requestTemperatures();//SOLICITA QUE A FUNÇÃO INFORME A TEMPERATURA DO SENSOR
    Serial.print("Temperatura do Solo: "); //IMPRIME O TEXTO NA SERIAL
    Serial.print(sensors.getTempCByIndex(0)); //IMPRIME NA SERIAL O VALOR DE TEMPERATURA MEDIDO
    Serial.println("ºC"); //IMPRIME O TEXTO NA SERIAL
    int co2now[10];                               //int array for co2 readings
    int co2raw = 0;                               //int for raw value of co2
    int co2comp = 0;                              //int for compensated co2 
    int co2ppm = 0;                               //int for calculated ppm
    int zzz = 0;                                  //int for averaging

    for (int x = 0;x<10;x++){                   //sample co2 10x over 2 seconds
    co2now[x]=analogRead(A0);
    
  }

    for (int x = 0;x<10;x++){                     //add samples together
    zzz=zzz + co2now[x];
    
  }
    co2raw = zzz/10;                            //divide samples by 10
    co2comp = co2raw - co2Zero;                 //get compensated value
    co2ppm = map(co2comp,0,1023,400,5000);      //map value for atmospheric levels

    Serial.print("CO2 Level: ");               //print title
    Serial.print(co2ppm);                      //print co2 ppm
    Serial.println(" PPM");                      //print units
    
    mySensorData.print(time);
    mySensorData.print(temp);
    mySensorData.print(", ");
    mySensorData.print(hum);
    mySensorData.print(", ");
    mySensorData.print(sensors.getTempCByIndex(0));
    mySensorData.print(", ");
    mySensorData.println(co2ppm);
    mySensorData.close();
    delay(5000);

    }
}
   
void chovendoPluvi() {

if ((val == LOW) && (old_val == HIGH)){    //Check to see if the status has changed

   delay(10);                   // Delay put in to deal with any "bouncing" in the switch.

   REEDCOUNT = REEDCOUNT + 1;   //Add 1 to the count of bucket tips

   old_val = val;              //Make the old value equal to the current value
       Serial.print(time);
       Serial.print("Medida de chuva (contagem): ");
       Serial.print(REEDCOUNT);//*0.2794); 
       Serial.println(" pulso");
       Serial.print("Medida de chuva (calculado): ");
       Serial.print(REEDCOUNT*0.25); 
       Serial.println(" mm");
       
       } 
 
     else {

   old_val = val;              //If the status hasn't changed then do nothing
     }
   

 }

In an interrupt handler you must not use the Serial object or any other function the depends on interrupts (as interrupts are disabled inside interrupt handlers) such as delay().

You don't need to check the old value as the interrupt will only fire if there was a change in the signal state. So remove everything from the handler except that line:

   REEDCOUNT = REEDCOUNT + 1;   //Add 1 to the count of bucket tips

and declare the used variable volatile:

volatile long int REEDCOUNT = 0;

otherwise it might be optimized away.

void chovendoPluvi()
{
   if ((val == LOW) && (old_val == HIGH))     //Check to see if the status has changed
   {
      delay(10);                   // Delay put in to deal with any "bouncing" in the switch.
      REEDCOUNT = REEDCOUNT + 1;   //Add 1 to the count of bucket tips

      old_val = val;              //Make the old value equal to the current value
      Serial.print(time);
      Serial.print("Medida de chuva (contagem): ");
      Serial.print(REEDCOUNT);//*0.2794);
      Serial.println(" pulso");
      Serial.print("Medida de chuva (calculado): ");
      Serial.print(REEDCOUNT * 0.25);
      Serial.println(" mm");
   }
   else
   {
      old_val = val;              //If the status hasn't changed then do nothing
   }
}

There is a lot wrong with that ISR. Any variable that is changed in an ISR should be declared volatile. You should not use delay() in an ISR. You should not print in an ISR. An ISR should be very short. Increment the count and set a flag that tells loop() that the ISR fired. Then, in loop(), do the processing and clear the flag. In loop() you need to guard against the ISR variable from changing while you read it. Disable interrupts just long enough to read or copy the variable and then enable interrupts.

pylon:
In an interrupt handler you must not use the Serial object or any other function the depends on interrupts (as interrupts are disabled inside interrupt handlers) such as delay().

You don't need to check the old value as the interrupt will only fire if there was a change in the signal state. So remove everything from the handler except that line:

   REEDCOUNT = REEDCOUNT + 1;   //Add 1 to the count of bucket tips

and declare the used variable volatile:

volatile long int REEDCOUNT = 0;

otherwise it might be optimized away.

What you mean by "handler"?

groundFungus:

void chovendoPluvi()

{
  if ((val == LOW) && (old_val == HIGH))    //Check to see if the status has changed
  {
      delay(10);                  // Delay put in to deal with any "bouncing" in the switch.
      REEDCOUNT = REEDCOUNT + 1;  //Add 1 to the count of bucket tips

old_val = val;              //Make the old value equal to the current value
      Serial.print(time);
      Serial.print("Medida de chuva (contagem): ");
      Serial.print(REEDCOUNT);//*0.2794);
      Serial.println(" pulso");
      Serial.print("Medida de chuva (calculado): ");
      Serial.print(REEDCOUNT * 0.25);
      Serial.println(" mm");
  }
  else
  {
      old_val = val;              //If the status hasn't changed then do nothing
  }
}




There is a lot wrong with that ISR. Any variable that is changed in an ISR should be declared volatile. You should not use delay() in an ISR. You should not print in an ISR. An ISR should be very short. Increment the count and set a flag that tells loop() that the ISR fired. Then, in loop(), do the processing and clear the flag. In loop() you need to guard against the ISR variable from changing while you read it. Disable interrupts just long enough to read or copy the variable and then enable interrupts.

I'm having some troubles to understand this:

Increment the count and set a flag that tells loop() that the ISR fired. Then, in loop(), do the processing and clear the flag. In loop() you need to guard against the ISR variable from changing while you read it. Disable interrupts just long enough to read or copy the variable and then enable interrupts.

Here is a demo to show what I meant. Tested on my Uno with a pushbutton switch attached to pin 2 to simulate a reed switch. Switch is hardware debounced with a 0.1uF cap across the switch. For a reed switch, software debouncing would probably be better as the contacts on a reed switch are very small and could be subject to arcing with the cap.

const byte rainPin = 2;
volatile boolean rainFlag = false;
volatile unsigned long rainCount = 0;

void setup()
{
   Serial.begin(115200);
   Serial.println("rain count interrpt demo \n\n");
   pinMode(rainPin, INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(2), rainISR, FALLING);
}

void loop()
{
   if(rainFlag == true)
   {
      noInterrupts();
      unsigned long rainCountCopy = rainCount;
      interrupts();
      Serial.print("rain total  ");
      Serial.println(rainCountCopy);
      rainFlag = false;
   }
}

void rainISR()
{
   rainCount++;
   rainFlag = true;
}

What you mean by "handler"?

chovendoPluvi() is your interrupt handler routine, it's the routine that handles the interrupt.

groundFungus:
Here is a demo to show what I meant. Tested on my Uno with a pushbutton switch attached to pin 2 to simulate a reed switch. Switch is hardware debounced with a 0.1uF cap across the switch. For a reed switch, software debouncing would probably be better as the contacts on a reed switch are very small and could be subject to arcing with the cap.

const byte rainPin = 2;

volatile boolean rainFlag = false;
volatile unsigned long rainCount = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println("rain count interrpt demo \n\n");
  pinMode(rainPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), rainISR, FALLING);
}

void loop()
{
  if(rainFlag == true)
  {
      noInterrupts();
      unsigned long rainCountCopy = rainCount;
      interrupts();
      Serial.print("rain total  ");
      Serial.println(rainCountCopy);
      rainFlag = false;
  }
}

void rainISR()
{
  rainCount++;
  rainFlag = true;
}

Dude, thank you!! This helped me a lot!!