How to restart after if statement sets to 0

I'm building a rain gauge using a tipping bucket sensor which is just a NO switch. I'm using an UNO and DS3231 rtc. The end result will show rain for hour, day and week. This code, cut down to relevant parts, works up to the point of starting the relevant count again after it has been set to 0.

#include "RTClib.h"
#include <TimeLib.h>

RTC_DS3231 rtc;

#define BucketSize 0.016115

volatile unsigned long tipCount = 0;
volatile unsigned long tipCountMinute = 0;
volatile unsigned long tipCountHour = 0;
volatile unsigned long tipCountDay = 0;
volatile unsigned long tipCountWeek = 0;
volatile unsigned long contactTime = 0;
volatile unsigned long previousTime = 0;


char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup () {




  Serial.begin(9600);

  rtc.begin();       // start the RTC
  DateTime now = rtc.now();
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), isr_rg, FALLING);


  //+++++  NAME OF SKETCH  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  Serial.println("    sketch is -- rain_gauge_10_minimum");
  Serial.println("");
  //++ use to set time clock    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
void loop() {

  // times are too short for testing only
  
  if (second() >= 20) {
    tipCountMinute = 0;
  }

  if (minute() >= 1) {
    tipCountHour = 0;
  }



  DateTime now = rtc.now();
  char time_format1[] = "hh:mm:ss";
  //+++++++++++++++++++++++++++++++++++++++++++++++
  if (millis() - 500 >= previousTime) {
    Serial.println(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.println(now.toString(time_format1));
    Serial.println(tipCount);

    Serial.print("Minute ");
    Serial.print(tipCountMinute  * BucketSize);
    Serial.println(" inches");

    Serial.print("Hour ");
    Serial.print(tipCountHour * BucketSize);
    Serial.println(" inches");

    Serial.print("Day  ");
    Serial.print(tipCountDay * BucketSize);
    Serial.println(" inches");

    Serial.print("Week ");
    Serial.print(tipCountDay * BucketSize);
    Serial.println(" inches");



    previousTime = millis();

    //////////////////////////////////////
    delay(5000);

  }

}

void isr_rg() {
  if ((millis() - contactTime) > 500) {
    tipCount++;
    tipCountMinute++;
    tipCountHour++;
    tipCountDay++;
    tipCountWeek++;



    contactTime = millis();
  }


}

This bit does the reset, I'm stuck on what to add to get it to start again.

  // times are too short for testing only
  
  if (second() >= 20) {
    tipCountMinute = 0;
  }

  if (minute() >= 1) {
    tipCountHour = 0;
  }

End result should be something like this on the serial monitor.

Minute 0.01 inches
Hour 0.03 inches
Day 0.09 inches
Week 0.12 inches

I've tried modifying the if statement and adding an else statement but, haven't found the right thing yet.

I've spent days researching weather stations, rtc math, and if/else statements. Nothing that I've found quite addresses what I am trying to do.

I'm don't understand the question. When the rain gauge tips, the ISR should increment those variables.

That said, the ISR actions do not make sense to me. Please explain these actions:

void isr_rg() {
  if ((millis() - contactTime) > 500) {
    tipCount++;
    tipCountMinute++;
    tipCountHour++;
    tipCountDay++;
    tipCountWeek++;
    contactTime = millis();
  }

If I were to write this ISR, I would increment only tipCount.

Guessing - those variables are reset every minute, hour, day, week in the mainline code.

You failed to implement critical sections in the mainline code, to ensure an atomic read of the ISR variables.

Generally, millis() and delay() can't be used together. The delay() calls will upset the millis() timing.

I'm sure there are more elegant ways of doing this, this is logical to me but probably not to a coder.
From the beginning, they all do the same thing. After I set "Minute 0.01 inches" to 0, by using this

  if (second() >= 20) {
    tipCountMinute = 0;
  }

hour, day, and week keep adding to their totals until the next one is stopped by this

  if (minute() >= 1) {
    tipCountHour = 0;
  }

At that point minute and hour read 0.00 and stay that way.

How do I get them to start counting again until it is again set to 0?

Generally, millis() and delay() can't be used together. The delay() calls will upset the millis() timing.

That was a left over from something I tried. Took it out with no change in anything.

I'll look into that to see if I can find what I need.

Post evidence that they are not counting.

I don't know how I could possibly show that.
I start the sketch and tip the bucket a couple of times. All four show 0.03. That's correct.
After 20 seconds Minute shows 0.00. That's correct.
Tip the bucket twice minute still shows 0.00, hour, day and week show 0.06. Hour, day and week are correct but, minute should now show 0.03.
When one minute has elapsed minute and hour now both show 0.00. They never show any tips again.
They may still be counting but, it isn't showing on the serial monitor.

Put in Serial.print() statements to reveal values of different variables, as you tip the bucket. Post the results.

As @anon57585045 mentioned above, you need to protect variables shared with an interrupt routine from being corrupted during access.

Do that as follows (example):

noInterrupts();
unsigned long tipCount_copy = tipCount;  //make a copy in main loop
interrupts();
Serial.print("Tip count" );
Serial.println(tipCount_copy);

It would be far, far easier to just report single tips in your ISR and do the counting in your mainline program.

You're checking for second to be >= 20, but second then continues counting to 59 and wraps around; for that 40 seconds, you're blind because you're jamming 0 into the value. Same goes for minutes, you can only see tips in the first minute of the hour, the way I read it.

I'd move the counting to loop(), and only reset the counters when the particular time value rolls over, for example, when secondsnow<secondslast, reset the minute counter, ditto for the other times.
But YMMV.
C

Is the OP using a ESP32?

UNO and DS3231 rtc.

Even those back-to-back calls to millis() should be moved out of the ISR.

I have a tipping bucket that counts the rain fall on a 24 hours basis and then resets at midnight for the new days count.

here is the bucket code written for an ESP32, perhaps the code can be converted for an Uno's use.

void fRainFall( void *pvParemeters )
{
  int16_t click = 0; //count tipping bucket clicks
  pcnt_counter_pause( PCNT_UNIT_1 );
  pcnt_counter_clear( PCNT_UNIT_1 );
  pcnt_counter_resume( PCNT_UNIT_1 );
  for  (;;)
  {
    xEventGroupWaitBits (eg, evtRainFall, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( (rtc.getHour(true) == 23) && (rtc.getMinute() == 59) )
    {
      pcnt_counter_pause( PCNT_UNIT_1 );
      rain = 0.0f;
      pcnt_counter_clear( PCNT_UNIT_1 );
      pcnt_counter_resume( PCNT_UNIT_1 );
    } else {
      pcnt_counter_pause( PCNT_UNIT_1 );
      pcnt_get_counter_value( PCNT_UNIT_1, &click );
      if ( click != 0 )
      {
        rain = rain + (0.2794f * (float)click);// 0.2794mm of rain per click
        pcnt_counter_clear( PCNT_UNIT_1 );
        log_i( "count %d, rain rain = %f mm", click, rain );
      }
      pcnt_counter_resume( PCNT_UNIT_1 );
      click = 0;
    }
  }
  vTaskDelete ( NULL );
}

@somewhereinusa Since there's an expectation that your bucket will only tip 2x per second (those millis() checks), this really isn't an application for an interrupt anyway, though it's good brain food to work on it.
C

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.