Specifying state of digital pin, but state fluctuates

Hello,

I'm a marine biologist, not a programmer, but I thought I had my code pretty well figured out until now. For a project, I am trying to control both a heater and a valve. At a particular time of day (low tide) I want the valve to open (letting water out) and the heater to come on.

The issue which arose this morning, but which hadn't been an issue before, has to do with controlling the valve (seemingly the easiest part of this project)

Some background on the code:

Currently, I enter the low tide start time in two parts such as (lowTideStartTimeHR = 10, lowTideStartTimeMIN = 30) for low tide starting at 10:30. I do the same for the end of the low tide. I then convert these two times to minutes (lowTideStartTime = lowTideStartTimeHR * 60 + lowTideStartTimeMIN) using the current time (from an RTC) and a series of "if else" statements to determine if it is low tide. This section of the code is shown below. There's the added complication that there are actually two low tides each day so there is both a "lowTideStartTime_1" and "lowTideStartTime_2", but they are specified in the same manner and the "if else" statements, if a bit long, are not actually that complicated.

void tideValve()
    {
    // Get current time, store in object 'now'
      DateTime now = RTC.now();
      
      if(now.hour()*60+now.minute() >= lowTideStartTime_1 && now.hour()*60+now.minute() < lowTideEndTime_1 || now.hour()*60+now.minute() >= lowTideStartTime_2 && now.hour()*60+now.minute() < lowTideEndTime_2 ) //if its low tide
     {
       digitalWrite(lowTideRelay, HIGH); //turn on Relay1 to power (open) valve
       digitalWrite(lowTide_LED, HIGH);   // turn on indicator LED
      }
       else if(now.hour()*60+now.minute() < lowTideStartTime_1 || now.hour()*60+now.minute() >= lowTideEndTime_1 || now.hour()*60+now.minute() < lowTideStartTime_2 || now.hour()*60+now.minute() >= lowTideEndTime_2) //if its high tide
              {
                digitalWrite(lowTideRelay, LOW);  //switch Relay1 (close valve)
                digitalWrite(lowTide_LED, LOW);    //turn off indicator LED
              }
    }

The issue I have run into is that "lowTideRelay" pin doesn't seem to stay HIGH or LOW during high or low tide periods, but switches "randomly".

I used the Serial port to see what's going on and posted a small section of it below. I printed additional output variables just to explore if the fluctuation is associated with some other change in the system.
The variables I have in the output posted below are: "DateTime", "Measured Temp", "Set Temp", "ValveState, which equals the relay pin", "Current Time", "LowTideStart", "LowTideEnd".

The primary column of interest is the Valve State. When the "Time" is between "LowTideStart" and "LowTideEnd", this state should be HIGH (1). It rarely is. I have attached a file where I followed this same timeline for longer (and across the switch from low tide to high tide) and you can see the state fluctuates back and forth from 0 to 1. Sometimes it seems to have a pattern, and then the gets random. When Time is greater than LowTideEnd (its no longer low tide and the state should be LOW (0)), the valve is more likely to be 1, but still fluctuates back and forth (see attached file).

I'm not sure what's going on here, but I need the valve/relay/pin to maintain one state during "low tides" (valve open) and the opposite state during "high tides" (valve closed) and right now it doesn't seem to be doing this.

Additionally, I'm not really happy with the way the timing of the tides is set currently because it restricts timing of low tides so that they cannot extend from one day to the next (over midnight). So, I am also very open to thoughts on how to avoid the whole mess, rewrite the code, and specify the timing of the tides in a completely different manner which may not result in the behavior I am seeing now.

I have attached my full code, as well as the longer Serial output, so its possible to see the Valve State switches.

Maybe this is some simple mistake of not properly specifying some initial state and I appreciate that feedback as well.

Thank you,
Nate

2014/3/18 12:11:51,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 731 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:11:54,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 731 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:11:58,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 731 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:01,    21.31 deg.C,   Set Temp: 13.10 ValveState: 1 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:04,    21.31 deg.C,   Set Temp: 13.10 ValveState: 1 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:08,    21.31 deg.C,   Set Temp: 13.10 ValveState: 1 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:11,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:14,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:18,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:21,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:24,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:28,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:31,    21.31 deg.C,   Set Temp: 13.10 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:34,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:38,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:41,    21.31 deg.C,   Set Temp: 13.15 ValveState: 1 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:44,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:48,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:51,    21.31 deg.C,   Set Temp: 13.15 ValveState: 1 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:54,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:12:58,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 732 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:13:01,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 733 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:13:04,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 733 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:13:08,    21.37 deg.C,   Set Temp: 13.15 ValveState: 1 Time: 733 LowTideStart: 360 LowTideEnd; 735
2014/3/18 12:13:11,    21.37 deg.C,   Set Temp: 13.15 ValveState: 0 Time: 733 LowTideStart: 360 LowTideEnd; 735

TempRampPID_LCD_1Wire_Arduino_2Tide.ino (12.2 KB)

SerialOutput_TideTest.txt (23.6 KB)

Ugghh...

Played around bit more and problem solved! Of course. The valve relay was on pin 1, which is also the TX pin. So every time data was printed to the LCD I was switching the state of the pin! Using a different pin now and all is resolved. Feeling rather stupid.

Thanks,
Nate

Feeling rather stupid.

No need for that. Now, if we'd pointed it out...

      if(now.hour()*60+now.minute() >= lowTideStartTime_1 &&
          now.hour()*60+now.minute() < lowTideEndTime_1 || 
          now.hour()*60+now.minute() >= lowTideStartTime_2 && 
          now.hour()*60+now.minute() < lowTideEndTime_2 ) //if its low tide

It would be better to store the hour and minute values in temporary variables, and doing the calculation once, rather than making up to 8 function calls, 4 multiplications, and 4 additions.

natemiller77:
Additionally, I'm not really happy with the way the timing of the tides is set currently because it restricts timing of low tides so that they cannot extend from one day to the next (over midnight).

End = start + length. The end hour, modulo 24, will give the correct time, even if it's the next day. E.g. start is at 23:00 and length is 3:25hrs so end will be 26:25. 26 modulo 24 = 2 gives you 02:25.

Thank you both for the great suggestions.

Henry_Best:

Is there a way to simply add 3:35 hrs to 23:00 and get 26:35? Or do I have to convert each time to an integer number, similar to how I converted all time values into minutes by multiplying the hours by 60 and then adding the minutes? It certainly would be simpler to have the code look something like this

startTime = 23:00;
duration = 6:00;
endTime = (startTime + duration) % 24;

Thanks for any additional thought on how best to add/compare times

Thank you,
Nate

natemiller77:
Thank you both for the great suggestions.

Henry_Best:

Is there a way to simply add 3:35 hrs to 23:00 and get 26:35? Or do I have to convert each time to an integer number, similar to how I converted all time values into minutes by multiplying the hours by 60 and then adding the minutes? It certainly would be simpler to have the code look something like this

startTime = 23:00;

duration = 6:00;
endTime = (startTime + duration) % 24;

Not quite. You'll have to add the hours separately from the minutes and check if the minutes are over 60

Hours =Hours + (minutes/60)  // will add zero if minutes are less than 60
minutes = minutes %60

Use hour(endTime) %24 to avoid mucking up the minutes. You can also do:day = hours(endTime) %24to also set a flag if the result goes over midnight into the next day. That may or may not be useful to you.
Alternately you could use your previous method of converting hours to minutes and using modulo 1440 (= 24 * 60) on the end result.
Whichever floats your boat :smiley: