Relay turns on, millis delay won't turn it off

G'day Ladies and gents,

First time posting here. I've been working on a temperature controller project for a few months now and everything is working except one of the relays turns on when the conditions are met but doesn't turn off once the specified time has elapsed. I reset the Arduino and it turns off untill the conditions are met.
I have used similar timing else where in the code and it works but not on this relay.
I have posted the code for the trouble relay below:

 void controlFreezer(){ 
    unsigned long currentFreezer = millis();
    if    (currentFreezer - previousMillisF > 60000) {
    previousMillisF = currentFreezer;
    digitalWrite (coldRelay, LOW);
    }
    else digitalWrite (coldRelay, HIGH);
}/code]

Let me know if any more information is required,

Thanks guys

How and where is previousMillisF declared ?

I assume that it is not used elsewhere in the program that you have not posted

You have not told us what relay you are using but most are configured to turn on when their input goes LOW. As most of the time when the function is called currentFreezer - previousMillisF will be greater than 60000 the relay will be turned on so the else clause is never executed to turn it off.

We don't do snippets here. I wanted to see the rest of the code, especially how previousMillisF was declared. I don't see anything obviously wrong here which suggests that the problem is in the part of the code that you have chosen NOT to show.

A wiring diagram might be helpful also.

Always

Use CTRL T to format your code.
Attach your ‘complete’ sketch between code tags, use the </> icon in the posting menu.
[code]Paste your sketch here[/code]

Show us a good schematic of your circuit.
Show us a good image of your wiring.
Give links to components.
Posting images:
https://forum.arduino.cc/index.php?topic=519037.0

That is not the way to use a single shot timer with millis().
Maybe one of my examples will help.

We like to help, but as you noticed, you can make it easier for us.
No snippets, there is even a website for that : https://snippets-r-us.com/. The problem is often in the part that someone refuses to show us :o
I have even made up a "law" for that: "Fifty percent chance that the problem is in the section that was ignored from the beginning, because you thought that the problem could not be caused by that section".
The others have not asked enough questions :wink: I also want to know which Arduino board you use :smiley_cat:

Hey guys,

Sorry I only pasted a snippet but I was posting from my phone and the full code wasn't exactly for public viewing (I was hoping to avoid the forums).

Koepel:
That is not the way to use a single shot timer with millis().
Maybe one of my examples will help.

We like to help, but as you noticed, you can make it easier for us.
No snippets, there is even a website for that : https://snippets-r-us.com/. The problem is often in the part that someone refuses to show us :o
I have even made up a "law" for that: "Fifty percent chance that the problem is in the section that was ignored from the beginning, because you thought that the problem could not be caused by that section".
The others have not asked enough questions :wink: I also want to know which Arduino board you use :smiley_cat:

I tried something similar to this originally but changed it because I thought it might of been the problem. I implemented your code and the coldRelay works once or twice but then will remain on.

All other functions work whilst the coldRelay is frozen.

I have commented out all the other functions in the loop and nothing changes.

I have tried using the relay with the BWOD example and it turns on and off so I have a hard time imagining its the wiring.

The main code below is with Koepel example implemented.

#include <SD.h>
// #include <RTClib.h>
#include <PID_v1.h>
#include <DallasTemperature.h>


double Setpoint, Input, Output;
int one_wire_bus = 5 ;
int hotRelay = 6;
int fanRelay = 7;
int coldRelay = 8;
int CS_pin = 10;
int setPoint = 22;
double consKp=500, consKi=0, consKd=0;
int windowSize = 10000;
long interval = 10000;
unsigned long windowStartTime;
unsigned long previousMillisH = 0;
unsigned long previousMillisF = 0;
unsigned long previousMillisS = 0;
bool enabled = false;
unsigned long previousHour = 0;
float currentFreezerTemp;
float currentHeaterTemp;


File data_file;

//RTC_DS1307 rtc;

PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
OneWire oneWire(one_wire_bus);
DallasTemperature sensors(&oneWire);

void setup() {
  initPins();
  initSerial();
  initSensors();
  
    
  windowStartTime = millis ();
  Setpoint = setPoint-1;
  myPID.SetOutputLimits(0, windowSize);
  myPID.SetMode(AUTOMATIC);
  
  sensors.begin();
  Input = currentHeaterTemp;

  printSerial();
  printData();

}

void loop() {
  initSensors();
  Input = currentHeaterTemp;
  
  if (Input<(Setpoint-1));{
  controlHeater();}
    
  if (Input>(Setpoint+1)){
    controlFreezer();
  }
  if (currentHeaterTemp != currentFreezerTemp){
    digitalWrite (fanRelay, HIGH);}
    else {digitalWrite (fanRelay, LOW);} 
        
    unsigned long currentS = millis();
    if    (currentS - previousMillisS >= 30000) {
    previousMillisS = currentS;
   printSerial();
   printData();
   
   }
 } 


void initPins(){
  pinMode (fanRelay, OUTPUT);
  pinMode(hotRelay, OUTPUT);
  pinMode(coldRelay, OUTPUT);  
  pinMode(CS_pin, OUTPUT);
}
void initSerial(){
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
    if (!SD.begin(CS_pin)) {
    Serial.println("Card failed, or not present");
    while (1) ;
    }
    Serial.println("card initialized.");
  data_file = SD.open("datalog.txt", FILE_WRITE);
    if (! data_file) {
    Serial.println("error opening datalog.txt");
    while (1) ;
    }
    else data_file.close();
    
 /* if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1)
  }*/
}
void initSensors(){
  sensors.requestTemperatures();
  currentHeaterTemp = sensors.getTempCByIndex(0);
  currentFreezerTemp= sensors.getTempCByIndex(1);
}
void controlHeater(){
  myPID.SetTunings(consKp, consKi, consKd);
   
  myPID.Compute();
  
  unsigned long relayNow = millis();
    if (relayNow - windowStartTime > windowSize){
    windowStartTime += windowSize;
    }
    if (Output > relayNow - windowStartTime){ 
    digitalWrite(hotRelay, HIGH);}
    else {digitalWrite(hotRelay, LOW);}
    
  unsigned long current = millis();
    if    (current - previousMillisH > interval) {
    previousMillisH = current;}

}
void controlFreezer(){
    
  unsigned long currentFreezer = millis();
  
  if( digitalRead( coldRelay) == LOW)  // low is active
  {
    digitalWrite( coldRelay, HIGH);  // turn on led
    previousMillisF = currentFreezer;
    enabled = true;        // turn on software timer
  }
  
  
  if( enabled)      // software timer is active ?
  {
    if( currentFreezer - previousMillisF >= 6000)
    {
      digitalWrite( coldRelay, LOW);  // turn off led
      enabled = false;     // stop software timer
    }
  }
}

void printSerial (){
 // DateTime now = rtc.now();
    
  /*Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);*/
  Serial.print("\t");
  Serial.print("hTem=");
  Serial.print("\t");
  Serial.print(currentHeaterTemp, 1);
  Serial.print("\t");
  Serial.print("ftem=");
  Serial.print("\t");
  Serial.print(currentFreezerTemp, 1);
  Serial.print("\t");
  Serial.print("o=");
  Serial.print("\t");
  Serial.print(Output / windowSize *100);
  Serial.print("\t");
  Serial.print("Set =");
  Serial.print("\t");
  Serial.println(Setpoint);
    }
void printData(){
/*  DateTime now = rtc.now();

unsigned long currentHour = now.minute();
if (currentHour != previousHour)        {
  previousHour = currentHour ;*/

   data_file = SD.open("datalog.txt", FILE_WRITE);
   if (data_file) {;
   data_file.print(currentHeaterTemp);
   data_file.print("\t");
   data_file.print("airTemp = ");
   data_file.print("\t");
   data_file.print("freezeTemp=");
   data_file.print("\t");
   data_file.print(currentFreezerTemp);
   data_file.print("output = ");
   data_file.println(Output / windowSize*100);
   data_file.close();
   }
  }
  • I originally had a real time clock controlling the timing but got rid of it because of a new design but plan to use at a later time

Also I am using lillypad for the board

Which Arduino Lilipad board ? There are a few versions. I prefer a link to where you bought it.

larryd wrote: "Use CTRL T to format your code".
After using Ctrl+T (or Auto Format in the menu), check your code and make it look good. Look at every indent, every space, every comma, every bracket, every empty line (or not), and so on.

You did not use my example.
To turn it off, I have that part running in the loop(). So it will be turned off at the right moment.
Therefor it may not be behind a if-statement as you have. Get that part out of the function ControlFreezer() and put it in the loop().

This:

if (currentHeaterTemp != currentFreezerTemp)

is often avoided. Because it is not possible to test if two floating point numbers are the same or not. One could be 1.000000 and the other one could be 0.999999.

Koepel you're an absolute legend!!! I now understand what was happening and it works.

How else could I go about controlling the fan?

There is a TimeAlarms library to do certain things at certain times.
There is also a TimerOne library to use Timer1.
When using millis() to keep the sketch going, there is no other way as far as I know.
Did you have a look at a few of my examples ? They work in the same way. The value of millis() is stored in 'previousMillis' (sometimes I call that a "timestamp"), and later the difference with the current millis value is calculated. When it is used that way, there is no problem during the rollover, when millis() turns from 0xFFFFFFFF to 0x00000000 after 50 days.

Fun fact: The Serial.println() rounds a floating point variable to the nearest value. When "1.00" is printed, the value could be 0.999999.