Nearly SOLVED Using While function is only giving a partial answer

Back for a little more advice. I have created a sketch that will eventually provide pre-set timed thermistor control of three heating zones. I have the timed section now functioning correctly and the thermistor control section also functions correctly. I am trying to use a While function to ensure that either normal heating is provided or frost protection at a lower temperature at all other times.
At present the system is stuck in the frost protection mode. I have tried various changes to the While function, with no positive results.

// Author : John Marchant G0RJM
// Created : 25/01/2024
// Description : Display the current date, time and temperature on the 20x4 LCD screen and create a thermostatic heating control of three zones
// Inspired from this code : File => Examples => RTClib => ds3231 along with parts borrowed from several other files/sketches in collaboration with several other authors

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "RTClib.h"
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS_1 3
#define ONE_WIRE_BUS_2 4
#define ONE_WIRE_BUS_3 5

OneWire oneWire_range(ONE_WIRE_BUS_1);
OneWire oneWire_club(ONE_WIRE_BUS_2);
OneWire oneWire_airgun(ONE_WIRE_BUS_3);

const byte range_relay = 9;  // Relay outputs
const byte club_relay = 10;
const byte airgun_relay = 11;
const byte boiler_relay = 12;
const byte normal_heat_out = A0;
const byte normal_heat_in = A1;
const byte frost_heat_out = A2;
const byte frost_heat_in = A3;

float range_temperature;
float club_temperature;
float airgun_temperature;

const float temperature_setpoint_range = 20.0;   // C
const float temperature_setpoint_club = 20.0;    // C
const float temperature_setpoint_airgun = 20.0;  // C
const float frost_setpoint = 24;                 // C
const float deadzone = 0.75;                     // C

DallasTemperature sensor_range(&oneWire_range);
DallasTemperature sensor_club(&oneWire_club);
DallasTemperature sensor_airgun(&oneWire_airgun);

// UNCHANGABLE PARAMATERS
#define Sunday 0
#define Monday 1
#define Tuesday 2
#define Wednesday 3
#define Thursday 4
#define Friday 5
#define Saturday 6

// byte Weekday[] = { 1, 2, 3, 4, 5, 6 };
// byte Sunday[] = { 0 };

const int OnHour_Normal = 16;  // Timeswitch settings
const int OnMin_Normal = 14;
const int OffHour_Normal = 22;
const int OffMin_Normal = 30;
const int OnHour_Sunday = 12;
const int OnMin_Sunday = 00;
const int OffHour_Sunday = 18;
const int OffMin_Sunday = 00;


LiquidCrystal_I2C lcd(0X27, 20, 4);
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
byte char_temp[8] = { B00100, B01010, B01010, B01110, B01110, B11111, B11111, B01110 };  // for thermometer icon

void setup() {

  pinMode(range_relay, OUTPUT);
  pinMode(club_relay, OUTPUT);
  pinMode(airgun_relay, OUTPUT);
  pinMode(boiler_relay, OUTPUT);
  pinMode(normal_heat_out, OUTPUT);
  pinMode(normal_heat_in, INPUT);
  pinMode(frost_heat_out, OUTPUT);
  pinMode(frost_heat_in, INPUT);

  rtc.begin();
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, char_temp);
  lcd.setCursor(4, 0);
  lcd.print("Take it easy!");
  lcd.setCursor(4, 1);
  lcd.print("Working on it");
  lcd.setCursor(2, 2);
  lcd.print("G0RJM Three Zone");
  lcd.setCursor(1, 3);
  lcd.print("Temperature Control");
  delay(3000);
  lcd.clear();
  if (rtc.lostPower()) {
    // When the time needs to be set up on a new device, or after a power loss, uncomment the
    // following line. This sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  {
    Serial.begin(9600);
    Serial.println("G0RJM Three zone Temperature Control");

    sensor_range.begin();
    sensor_club.begin();
    sensor_airgun.begin();
  }
  while (normal_heat_in == HIGH)
    ;

  while (frost_heat_in == HIGH)
    ;
}

//------------------------------Temperature control-----------------------------//

void loop() {

  DateTime now = rtc.now();

  {
    // Serial.print(now.year(), DEC);
    // Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    // Serial.print(now.hour(), DEC);
    // Serial.print(':');
    // Serial.print(now.minute(), DEC);
    // Serial.print(':');
    // Serial.print(now.second(), DEC);
    // Serial.println();
  }
  //-------------------Timed heating setting----------------------------//

  if ((now.hour() >= OffHour_Normal) && (now.minute() >= OffMin_Normal) && (now.dayOfTheWeek() != Sunday)
      || (now.hour() >= OffHour_Sunday) && (now.minute() >= OffMin_Sunday) && (now.dayOfTheWeek() == Sunday)) {

    digitalWrite(normal_heat_out, LOW);
    digitalWrite(frost_heat_out, HIGH);

  } else {

    if ((now.hour() >= OnHour_Normal) && (now.minute() >= OnMin_Normal) && (now.dayOfTheWeek() != Sunday)
        || (now.hour() >= OnHour_Sunday) && (now.minute() >= OnMin_Sunday) && (now.dayOfTheWeek() == Sunday))

      digitalWrite(normal_heat_out, HIGH);
    digitalWrite(frost_heat_out, LOW);
  }

  //--------------------Frost protection control-----------------------//
  while (frost_heat_in == HIGH) {
    if ((sensor_range.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
      digitalWrite(range_relay, HIGH);
      lcd.setCursor(15, 1);
      lcd.print("ON  F");
    } else {
      if ((sensor_range.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
        digitalWrite(range_relay, LOW);
      lcd.setCursor(15, 1);
      lcd.print("  OFF");
    }

    if ((sensor_club.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
      digitalWrite(club_relay, HIGH);
      lcd.setCursor(15, 2);
      lcd.print("ON  F");
    } else {
      if ((sensor_club.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
        digitalWrite(club_relay, LOW);
      lcd.setCursor(15, 2);
      lcd.print("  OFF");
    }

    if ((sensor_airgun.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
      digitalWrite(airgun_relay, HIGH);
      lcd.setCursor(15, 3);
      lcd.print("ON  F");
    } else {
      if ((sensor_airgun.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
        digitalWrite(airgun_relay, LOW);
      lcd.setCursor(15, 3);
      lcd.print("  OFF");
    }
  }

  //--------------------Normal temperature control--------------------//
  // while (normal_heat_in == HIGH) {
  if ((sensor_range.getTempCByIndex(0) < (temperature_setpoint_range - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
    digitalWrite(range_relay, HIGH);
    lcd.setCursor(15, 1);
    lcd.print("ON  T");
  } else {
    if ((sensor_range.getTempCByIndex(0) > (temperature_setpoint_range + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
      digitalWrite(range_relay, LOW);
    lcd.setCursor(15, 1);
    lcd.print("  OFF");
  }

  if ((sensor_club.getTempCByIndex(0) < (temperature_setpoint_club - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
    digitalWrite(club_relay, HIGH);
    lcd.setCursor(15, 2);
    lcd.print("ON  T");
  } else {
    if ((sensor_club.getTempCByIndex(0) > (temperature_setpoint_club + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
      digitalWrite(club_relay, LOW);
    lcd.setCursor(15, 2);
    lcd.print("  OFF");
  }

  if ((sensor_airgun.getTempCByIndex(0) < (temperature_setpoint_airgun - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
    digitalWrite(airgun_relay, HIGH);
    lcd.setCursor(15, 3);
    lcd.print("ON  T");
  } else {
    if ((sensor_airgun.getTempCByIndex(0) > (temperature_setpoint_airgun + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
      digitalWrite(airgun_relay, LOW);
    lcd.setCursor(15, 3);
    lcd.print("  OFF");
  }
  // }

  //lcd.setCursor(column,row);
  //------------------------------Date display-----------------------------//
  lcd.setCursor(0, 0);
  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.setCursor(3, 0);
  // lcd.print("Date:");
  lcd.print(":");
  lcd.setCursor(4, 0);
  if (now.day() <= 9) {
    lcd.print("0");
    lcd.setCursor(5, 0);
    lcd.print(now.day(), DEC);
  } else {
    lcd.print(now.day(), DEC);
  }
  lcd.setCursor(6, 0);
  lcd.print(":");
  lcd.setCursor(7, 0);
  if (now.month() <= 9) {
    lcd.print("0");
    lcd.setCursor(8, 0);
    lcd.print(now.month(), DEC);
  } else {
    lcd.print(now.month(), DEC);
  }
  lcd.setCursor(9, 0);
  lcd.print(":");
  lcd.setCursor(10, 0);
  lcd.print(now.year(), DEC);
  //------------------------------Time display-----------------------------//
  //  lcd.setCursor(0, 1);
  // lcd.print("Time:");
  lcd.setCursor(15, 0);
  if (now.hour() <= 9) {
    lcd.print("0");
    lcd.setCursor(16, 0);
    lcd.print(now.hour(), DEC);
  } else {
    lcd.print(now.hour(), DEC);
  }
  lcd.setCursor(17, 0);
  lcd.print(":");
  lcd.setCursor(18, 0);
  if (now.minute() <= 9) {
    lcd.print("0");
    lcd.setCursor(19, 0);
    lcd.print(now.minute(), DEC);
  } else {
    lcd.print(now.minute(), DEC);
  }
  lcd.setCursor(17, 0);
  lcd.print(":");
  lcd.setCursor(18, 0);

  // if (now.second() <=9 )
  //  {
  //   lcd.print("0");
  //   lcd.setCursor(13,1);
  //   lcd.print(now.second(),DEC);
  // }
  // else {lcd.print(now.second(),DEC);}
  //------------------------------Temperature display - -----------------------------//
  {
    Serial.print("Requesting temperatures...");
    sensor_range.requestTemperatures();
    sensor_club.requestTemperatures();
    sensor_airgun.requestTemperatures();
    Serial.println(" done");

    Serial.print("Range: ");
    Serial.println(sensor_range.getTempCByIndex(0));

    Serial.print("Club: ");
    Serial.println(sensor_club.getTempCByIndex(0));

    Serial.print("Airgun: ");
    Serial.println(sensor_airgun.getTempCByIndex(0));

    Serial.print("Frost In ");
    Serial.println(frost_heat_in);

    Serial.print("Heat In ");
    Serial.println(normal_heat_in);
  }

  {
    lcd.setCursor(0, 1);  // Range
    lcd.print("Range:");
    lcd.setCursor(7, 1);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_range.getTempCByIndex(0));

    lcd.setCursor(12, 1);
    lcd.write((char)223);
    lcd.setCursor(13, 1);
    lcd.print("C");
    // lcd.setCursor(18, 1);
    // lcd.print(char(0));

    lcd.setCursor(0, 2);  // Clubroom
    lcd.print("Club:");
    lcd.setCursor(7, 2);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_club.getTempCByIndex(0));

    lcd.setCursor(12, 2);
    lcd.write((char)223);
    lcd.setCursor(13, 2);
    lcd.print("C");
    // lcd.setCursor(14, 2);
    // lcd.print("    ");
    // lcd.print(char(0));

    lcd.setCursor(0, 3);  // Airgun Range
    lcd.print("Airgun:");
    lcd.setCursor(7, 3);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_airgun.getTempCByIndex(0));

    lcd.setCursor(12, 3);
    lcd.write((char)223);
    lcd.setCursor(13, 3);
    lcd.print("C");
    // lcd.setCursor(18, 3);
    // lcd.print(char(0));

    delay(5000);
  }
}


 while (normal_heat_in == HIGH)
    ;

This test will always return true because normal_heat_in will always be true, You need to use digitalRead() to read the state of the pin within the while loop

You are comparing a pin number with a digital state.
I think that actually the result of both comparisons is FALSE because both A1 or A3 is different from HIGH (¿1?).

while (normal_heat_in == HIGH) ; 

while (frost_heat_in == HIGH) ; 

As @UKHeliBob says you should use

while (digitalRead(normal_heat_in) == HIGH) ; 

The same in loop()

1 Like

Any value except zero is regarded as true. As the value of normal_heat_in is not zero it will be regarded as true

What is missing is a digitalRead() of the pin to get its state rather than using its value

Did someone see these aready?

Read pin 1 or 0:

(digitalRead(normal_heat_in == HIGH))

should most probably be

Read pin normal_heat_in and test to see if it is HIGH:

(digitalRead(normal_heat_in) == HIGH)

a7

Sorry to disagree, look

Only if the variable contains 1 will the equality with HIGH be true.

1 Like

Correct. From Arduino.h in the arduino\hardware\avr\1.8.6 core file

#define HIGH 0x1
#define LOW  0x0

You are right. What I had in my mind was a comparison with true or false which was not what was being done in this case

2 Likes

The day/time on/off now functions correctly thanks to the guidance received. The temperature display is correct in the Normal heating mode. However, when the system is in Frost protection mode, only the state of the heating output is shown. The area description, date and time are not shown and the temperature from the sensors is not shown.

I believe that the ‘while’ function is preventing any changes in the rest of the loop being executed.

I have tried changing the position of the groups of code within the Loop which made a small improvement to the Frost protection at the expense of the normal heating.

I have tried unsuccessfully to create sub routine loops to display the information to no avail.

Hopefully you might be kind enough to offer more guidance please.

// Author : John Marchant G0RJM
// Created : 25/01/2024
// Description : Display the current date, time and temperature on the 20x4 LCD screen and create a thermostatic heating control of three zones
// Inspired from this code : File => Examples => RTClib => ds3231 along with parts borrowed from several other files/sketches in collaboration with several other authors

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "RTClib.h"
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS_1 3
#define ONE_WIRE_BUS_2 4
#define ONE_WIRE_BUS_3 5

OneWire oneWire_range(ONE_WIRE_BUS_1);
OneWire oneWire_club(ONE_WIRE_BUS_2);
OneWire oneWire_airgun(ONE_WIRE_BUS_3);

const byte range_relay = 9;  // Relay outputs
const byte club_relay = 10;
const byte airgun_relay = 11;
const byte boiler_relay = 12;
const byte normal_heat_out = A0;
const byte normal_heat_in = A1;
const byte frost_heat_out = A2;
const byte frost_heat_in = A3;

float range_temperature;
float club_temperature;
float airgun_temperature;

const float temperature_setpoint_range = 25.0;   // C
const float temperature_setpoint_club = 25.0;    // C
const float temperature_setpoint_airgun = 25.0;  // C
const float frost_setpoint = 25.5;               // C
const float deadzone = 0.75;                     // C

DallasTemperature sensor_range(&oneWire_range);
DallasTemperature sensor_club(&oneWire_club);
DallasTemperature sensor_airgun(&oneWire_airgun);

// UNCHANGABLE PARAMATERS
#define Sunday 0
#define Monday 1
#define Tuesday 2
#define Wednesday 3
#define Thursday 4
#define Friday 5
#define Saturday 6

const int OnHour_Normal = 10;  // Timeswitch settings
const int OnMin_Normal = 10;
const int OffHour_Normal = 20;
const int OffMin_Normal = 30;
const int OnHour_Sunday = 12;
const int OnMin_Sunday = 00;
const int OffHour_Sunday = 22;
const int OffMin_Sunday = 00;

LiquidCrystal_I2C lcd(0X27, 20, 4);
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
byte char_temp[8] = { B00100, B01010, B01010, B01110, B01110, B11111, B11111, B01110 };  // for thermometer icon

void setup() {

  pinMode(range_relay, OUTPUT);
  pinMode(club_relay, OUTPUT);
  pinMode(airgun_relay, OUTPUT);
  pinMode(boiler_relay, OUTPUT);
  pinMode(normal_heat_out, OUTPUT);
  pinMode(normal_heat_in, INPUT);
  pinMode(frost_heat_out, OUTPUT);
  pinMode(frost_heat_in, INPUT);

  rtc.begin();
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, char_temp);
  lcd.setCursor(4, 0);
  lcd.print("Take it easy!");
  lcd.setCursor(4, 1);
  lcd.print("Working on it");
  lcd.setCursor(2, 2);
  lcd.print("G0RJM Three Zone");
  lcd.setCursor(1, 3);
  lcd.print("Temperature Control");
  delay(3000);
  lcd.clear();
  if (rtc.lostPower()) {
    // When the time needs to be set up on a new device, or after a power loss, uncomment the
    // following line. This sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  {
    Serial.begin(9600);
    Serial.println("G0RJM Three zone Temperature Control");

    sensor_range.begin();
    sensor_club.begin();
    sensor_airgun.begin();
  }
  while (digitalRead(normal_heat_in) == HIGH)
    ;

  while (digitalRead(frost_heat_in) == HIGH)
    ;
}

//--------------------------Temperature control--------------------------//

void loop() {

  DateTime now = rtc.now();

  {
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
  
  }

  //---------------------Timed heating setting--------------------------//
  if ((now.hour() >= OffHour_Normal) && (now.minute() >= OffMin_Normal) && (now.dayOfTheWeek() != Sunday)
      || (now.hour() >= OffHour_Sunday) && (now.minute() >= OffMin_Sunday) && (now.dayOfTheWeek() == Sunday)) {

    digitalWrite(normal_heat_out, LOW);
    digitalWrite(frost_heat_out, HIGH);

  } else {

    if ((now.hour() >= OnHour_Normal) && (now.minute() >= OnMin_Normal) && (now.dayOfTheWeek() != Sunday)
        || (now.hour() >= OnHour_Sunday) && (now.minute() >= OnMin_Sunday) && (now.dayOfTheWeek() == Sunday))

      digitalWrite(normal_heat_out, HIGH);
    digitalWrite(frost_heat_out, LOW);
  }

  //--------------------Frost protection control-----------------------//
  while (digitalRead(frost_heat_in) == HIGH) {
    if ((sensor_range.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
      digitalWrite(range_relay, HIGH);
      lcd.setCursor(15, 1);
      lcd.print("ON  F");
    } else {
      if ((sensor_range.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
        digitalWrite(range_relay, LOW);
      lcd.setCursor(15, 1);
      lcd.print("  OFF");
    }

    if ((sensor_club.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
      digitalWrite(club_relay, HIGH);
      lcd.setCursor(15, 2);
      lcd.print("ON  F");
    } else {
      if ((sensor_club.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
        digitalWrite(club_relay, LOW);
      lcd.setCursor(15, 2);
      lcd.print("  OFF");
    }

    if ((sensor_airgun.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
      digitalWrite(airgun_relay, HIGH);
      lcd.setCursor(15, 3);
      lcd.print("ON  F");
    } else {
      if ((sensor_airgun.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
        digitalWrite(airgun_relay, LOW);
      lcd.setCursor(15, 3);
      lcd.print("  OFF");
    }
  }

  //----------------------Normal temperature control--------------------//
  while (digitalRead(normal_heat_in) == HIGH) {
  if ((sensor_range.getTempCByIndex(0) < (temperature_setpoint_range - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
    digitalWrite(range_relay, HIGH);
    lcd.setCursor(15, 1);
    lcd.print("ON  T");
  } else {
    if ((sensor_range.getTempCByIndex(0) > (temperature_setpoint_range + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
      digitalWrite(range_relay, LOW);
    lcd.setCursor(15, 1);
    lcd.print("  OFF");
  }

  if ((sensor_club.getTempCByIndex(0) < (temperature_setpoint_club - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
    digitalWrite(club_relay, HIGH);
    lcd.setCursor(15, 2);
    lcd.print("ON  T");
  } else {
    if ((sensor_club.getTempCByIndex(0) > (temperature_setpoint_club + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
      digitalWrite(club_relay, LOW);
    lcd.setCursor(15, 2);
    lcd.print("  OFF");
  }

  if ((sensor_airgun.getTempCByIndex(0) < (temperature_setpoint_airgun - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
    digitalWrite(airgun_relay, HIGH);
    lcd.setCursor(15, 3);
    lcd.print("ON  T");
  } else {
    if ((sensor_airgun.getTempCByIndex(0) > (temperature_setpoint_airgun + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
      digitalWrite(airgun_relay, LOW);
    lcd.setCursor(15, 3);
    lcd.print("  OFF");
  }
}
  //------------------------------Date display--------------------------//
  lcd.setCursor(0, 0);
  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.setCursor(3, 0);
  // lcd.print("Date:");
  lcd.print(":");
  lcd.setCursor(4, 0);
  if (now.day() <= 9) {
    lcd.print("0");
    lcd.setCursor(5, 0);
    lcd.print(now.day(), DEC);
  } else {
    lcd.print(now.day(), DEC);
  }
  lcd.setCursor(6, 0);
  lcd.print(":");
  lcd.setCursor(7, 0);
  if (now.month() <= 9) {
    lcd.print("0");
    lcd.setCursor(8, 0);
    lcd.print(now.month(), DEC);
  } else {
    lcd.print(now.month(), DEC);
  }
  lcd.setCursor(9, 0);
  lcd.print(":");
  lcd.setCursor(10, 0);
  lcd.print(now.year(), DEC);

  //-------------------------Time display-------------------------------//
  lcd.setCursor(15, 0);
  if (now.hour() <= 9) {
    lcd.print("0");
    lcd.setCursor(16, 0);
    lcd.print(now.hour(), DEC);
  } else {
    lcd.print(now.hour(), DEC);
  }
  lcd.setCursor(17, 0);
  lcd.print(":");
  lcd.setCursor(18, 0);
  if (now.minute() <= 9) {
    lcd.print("0");
    lcd.setCursor(19, 0);
    lcd.print(now.minute(), DEC);
  } else {
    lcd.print(now.minute(), DEC);
  }
  lcd.setCursor(17, 0);
  lcd.print(":");
  lcd.setCursor(18, 0);

  //-----------------------Temperature display - -----------------------//
  {
    Serial.print("Requesting temperatures...");
    sensor_range.requestTemperatures();
    sensor_club.requestTemperatures();
    sensor_airgun.requestTemperatures();
    Serial.println(" done");

    Serial.print("Range: ");
    Serial.println(sensor_range.getTempCByIndex(0));

    Serial.print("Club: ");
    Serial.println(sensor_club.getTempCByIndex(0));

    Serial.print("Airgun: ");
    Serial.println(sensor_airgun.getTempCByIndex(0));

    Serial.print("Frost In ");
    Serial.println(frost_heat_in);

    Serial.print("Heat In ");
    Serial.println(normal_heat_in);
  }

  {
    lcd.setCursor(0, 1);  // Range
    lcd.print("Range:");
    lcd.setCursor(7, 1);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_range.getTempCByIndex(0));

    lcd.setCursor(12, 1);
    lcd.write((char)223);
    lcd.setCursor(13, 1);
    lcd.print("C");

    lcd.setCursor(0, 2);  // Clubroom
    lcd.print("Club:");
    lcd.setCursor(7, 2);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_club.getTempCByIndex(0));

    lcd.setCursor(12, 2);
    lcd.write((char)223);
    lcd.setCursor(13, 2);
    lcd.print("C");

    lcd.setCursor(0, 3);  // Airgun Range
    lcd.print("Airgun:");
    lcd.setCursor(7, 3);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_airgun.getTempCByIndex(0));

    lcd.setCursor(12, 3);
    lcd.write((char)223);
    lcd.setCursor(13, 3);
    lcd.print("C");
 
    delay(3000);
  }
}

const byte normal_heat_in = A1;
const byte frost_heat_in = A3;

pinMode(normal_heat_in, INPUT);
pinMode(frost_heat_in, INPUT);

What is connected to these pins and determines if the reading will be HIGH or LOW?
Do these pins have external pullups or pulldowns to prevent them from floating?

Why do you need the while loops? All your conditional statements within each while loop contain an && for the digitalRead condition, and I would think that would be sufficient.

Hi @cattledog, input pin A1 is difrectly connected to Output pin A0 to give a point whereby I can physically check the v oltage stae of the pin. The same applies to input pin A3 which is dirfectly linked to A2.
Earlier in this topic, it was suggested to use the 'while' function which is why they have now been included. I am quite prepared to comment these out and try the sketch.

I have just remembered the other reason for the 'while' function is at some later point in the project the permanent link between A0 and A1 or A2 abd A3 will be replaced with a remote safety control to prevent potential overheating.

I don't see that recommendation in this thread.

I am quite prepared to comment these out and try the sketch.
I would recommend you try with just the conditional controls.

Presently the A0 and A2 outputs are controlled by your timers. If they are controlled by external safety control it will make no difference.

In general, while loops are not recommended, and it is better to use conditional statements evaluated in loop().

Thanks @cattledog for your advice. I have gone back to the sketch and had a bit of a rethink taking out the 'while' function. I will start a new topic as quite a lot has changed.

The next stage in creating my three zone temperature controller with frost protection during silent hours. I have removed the previously include 'while' functions. The sytem now functions, however every three seconds it changes from normal control to frost protection and then back again. I do have two three second delays built into the sketch and presume as the loop continues, it reacts to these delays and then changes to the other temperature control function.
I have tried various ways of correcting this from using the 'while' function to attempting unsuccessfully to create sub routines.
I am hoping that someone might take the time to view the code and be kind enough to suggest what adjustment I should make.

// Author : John Marchant G0RJM
// Created : 25/01/2024
// Description : Display the current date, time and temperature on the 20x4 LCD screen and
// create a thermostatic heating control of three zones to include frost protection.
// Inspired from this code : File => Examples => RTClib => ds3231 along with
// parts borrowed from several other files/sketches in collaboration with several other authors

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "RTClib.h"
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS_1 3
#define ONE_WIRE_BUS_2 4
#define ONE_WIRE_BUS_3 5

OneWire oneWire_range(ONE_WIRE_BUS_1);
OneWire oneWire_club(ONE_WIRE_BUS_2);
OneWire oneWire_airgun(ONE_WIRE_BUS_3);

const byte range_relay = 9;  // Relay outputs
const byte club_relay = 10;
const byte airgun_relay = 11;
const byte boiler_relay = 12;
const byte normal_heat_out = A0;
const byte normal_heat_in = A1;
const byte frost_heat_out = A2;
const byte frost_heat_in = A3;

float range_temperature;
float club_temperature;
float airgun_temperature;

const float temperature_setpoint_range = 20.0;   // C
const float temperature_setpoint_club = 25.0;    // C
const float temperature_setpoint_airgun = 25.0;  // C
const float frost_setpoint = 25.5;               // C
const float deadzone = 0.75;                     // C

DallasTemperature sensor_range(&oneWire_range);
DallasTemperature sensor_club(&oneWire_club);
DallasTemperature sensor_airgun(&oneWire_airgun);

#define Sunday 0  // Unchangeable parameters
#define Monday 1
#define Tuesday 2
#define Wednesday 3
#define Thursday 4
#define Friday 5
#define Saturday 6

const int OnHour_Normal = 16;  // Timeswitch settings
const int OnMin_Normal = 00;
const int OffHour_Normal = 21;
const int OffMin_Normal = 30;
const int OnHour_Sunday = 16;
const int OnMin_Sunday = 00;
const int OffHour_Sunday = 17;
const int OffMin_Sunday = 30;

LiquidCrystal_I2C lcd(0X27, 20, 4);
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
byte char_temp[8] = { B00100, B01010, B01010, B01110, B01110, B11111, B11111, B01110 };  // for thermometer icon

void setup() {

  pinMode(range_relay, OUTPUT);
  pinMode(club_relay, OUTPUT);
  pinMode(airgun_relay, OUTPUT);
  pinMode(boiler_relay, OUTPUT);
  pinMode(normal_heat_out, OUTPUT);
  pinMode(normal_heat_in, INPUT);
  pinMode(frost_heat_out, OUTPUT);
  pinMode(frost_heat_in, INPUT);

  rtc.begin();
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, char_temp);
  lcd.setCursor(4, 0);
  lcd.print("Take it easy!");
  lcd.setCursor(4, 1);
  lcd.print("Working on it");
  lcd.setCursor(2, 2);
  lcd.print("G0RJM Three Zone");
  lcd.setCursor(1, 3);
  lcd.print("Temperature Control");
  delay(3000);
  lcd.clear();
  if (rtc.lostPower()) {
    // When the time needs to be set up on a new device, or after a power loss, uncomment the
    // following line. This sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  {
    Serial.begin(9600);
    Serial.println("G0RJM Three zone Temperature Control");

    sensor_range.begin();
    sensor_club.begin();
    sensor_airgun.begin();
  }
  // while (digitalRead(normal_heat_in) == HIGH)
  // ;

  // while (digitalRead(frost_heat_in) == HIGH)
  // ;
}

//---------------------------control--------------------------//
void loop() {

  DateTime now = rtc.now();

  {
    // Serial.print(now.year(), DEC);
    // Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
  }

  //---------------------Timed heating setting--------------------------//
  if ((now.hour() >= OffHour_Normal) && (now.minute() >= OffMin_Normal) && (now.dayOfTheWeek() != Sunday)
      || (now.hour() >= OffHour_Sunday) && (now.minute() >= OffMin_Sunday) && (now.dayOfTheWeek() == Sunday)) {

    digitalWrite(normal_heat_out, LOW);
    digitalWrite(frost_heat_out, HIGH);

  } else {

    if ((now.hour() >= OnHour_Normal) && (now.minute() >= OnMin_Normal) && (now.dayOfTheWeek() != Sunday)
        || (now.hour() >= OnHour_Sunday) && (now.minute() >= OnMin_Sunday) && (now.dayOfTheWeek() == Sunday))

      digitalWrite(normal_heat_out, HIGH);
    digitalWrite(frost_heat_out, LOW);
  }

  //--------------------Frost protection control-----------------------//
  // while (digitalRead(frost_heat_in) == HIGH) {
  if ((sensor_range.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
    digitalWrite(range_relay, HIGH);
    lcd.setCursor(15, 1);
    lcd.print("ON  F");
  } else {
    if ((sensor_range.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
      digitalWrite(range_relay, LOW);
    lcd.setCursor(15, 1);
    lcd.print("  OFF");
  }

  if ((sensor_club.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
    digitalWrite(club_relay, HIGH);
    lcd.setCursor(15, 2);
    lcd.print("ON  F");
  } else {
    if ((sensor_club.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
      digitalWrite(club_relay, LOW);
    lcd.setCursor(15, 2);
    lcd.print("  OFF");
  }

  if ((sensor_airgun.getTempCByIndex(0) < (frost_setpoint - deadzone)) && (digitalRead(frost_heat_in == HIGH))) {
    digitalWrite(airgun_relay, HIGH);
    lcd.setCursor(15, 3);
    lcd.print("ON  F");
  } else {
    if ((sensor_airgun.getTempCByIndex(0) > (frost_setpoint + deadzone)) && (digitalRead(frost_heat_in == HIGH)))
      digitalWrite(airgun_relay, LOW);
    lcd.setCursor(15, 3);
    lcd.print("  OFF");
  }
  //------------------------------Date display--------------------------//
  // void display() {
  lcd.setCursor(0, 0);
  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.setCursor(3, 0);
  lcd.print(":");
  lcd.setCursor(4, 0);
  if (now.day() <= 9) {
    lcd.print("0");
    lcd.setCursor(5, 0);
    lcd.print(now.day(), DEC);
  } else {
    lcd.print(now.day(), DEC);
  }
  lcd.setCursor(6, 0);
  lcd.print(":");
  lcd.setCursor(7, 0);
  if (now.month() <= 9) {
    lcd.print("0");
    lcd.setCursor(8, 0);
    lcd.print(now.month(), DEC);
  } else {
    lcd.print(now.month(), DEC);
  }
  lcd.setCursor(9, 0);
  lcd.print(":");
  lcd.setCursor(10, 0);
  lcd.print(now.year(), DEC);

  //-------------------------Time display-------------------------------//
  lcd.setCursor(15, 0);
  if (now.hour() <= 9) {
    lcd.print("0");
    lcd.setCursor(16, 0);
    lcd.print(now.hour(), DEC);
  } else {
    lcd.print(now.hour(), DEC);
  }
  lcd.setCursor(17, 0);
  lcd.print(":");
  lcd.setCursor(18, 0);
  if (now.minute() <= 9) {
    lcd.print("0");
    lcd.setCursor(19, 0);
    lcd.print(now.minute(), DEC);
  } else {
    lcd.print(now.minute(), DEC);
  }
  lcd.setCursor(17, 0);
  lcd.print(":");
  lcd.setCursor(18, 0);

  //-----------------------Temperature display - -----------------------//
  {
    lcd.setCursor(0, 1);  // Range
    lcd.print("Range:");
    lcd.setCursor(7, 1);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_range.getTempCByIndex(0));

    lcd.setCursor(12, 1);
    lcd.write((char)223);
    lcd.setCursor(13, 1);
    lcd.print("C");
    // lcd.setCursor(18, 1);
    // lcd.print(char(0));

    lcd.setCursor(0, 2);  // Clubroom
    lcd.print("Club:");
    lcd.setCursor(7, 2);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_club.getTempCByIndex(0));

    lcd.setCursor(12, 2);
    lcd.write((char)223);
    lcd.setCursor(13, 2);
    lcd.print("C");
    // lcd.setCursor(14, 2);
    // lcd.print("    ");
    // lcd.print(char(0));

    lcd.setCursor(0, 3);  // Airgun Range
    lcd.print("Airgun:");
    lcd.setCursor(7, 3);
    // lcd.print(rtc.getTemperature());
    lcd.print(sensor_airgun.getTempCByIndex(0));

    lcd.setCursor(12, 3);
    lcd.write((char)223);
    lcd.setCursor(13, 3);
    lcd.print("C");
    // lcd.setCursor(18, 3);
    // lcd.print(char(0));

    delay(3000);
    // }


    //----------------------Normal temperature control--------------------//
    // while (digitalRead(normal_heat_in) == HIGH) {
    if ((sensor_range.getTempCByIndex(0) < (temperature_setpoint_range - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
      digitalWrite(range_relay, HIGH);
      lcd.setCursor(15, 1);
      lcd.print("ON  T");
    } else {
      if ((sensor_range.getTempCByIndex(0) > (temperature_setpoint_range + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
        digitalWrite(range_relay, LOW);
      lcd.setCursor(15, 1);
      lcd.print("  OFF");
    }

    if ((sensor_club.getTempCByIndex(0) < (temperature_setpoint_club - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
      digitalWrite(club_relay, HIGH);
      lcd.setCursor(15, 2);
      lcd.print("ON  T");
    } else {
      if ((sensor_club.getTempCByIndex(0) > (temperature_setpoint_club + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
        digitalWrite(club_relay, LOW);
      lcd.setCursor(15, 2);
      lcd.print("  OFF");
    }

    if ((sensor_airgun.getTempCByIndex(0) < (temperature_setpoint_airgun - deadzone)) && (digitalRead(normal_heat_in == HIGH))) {
      digitalWrite(airgun_relay, HIGH);
      lcd.setCursor(15, 3);
      lcd.print("ON  T");
    } else {
      if ((sensor_airgun.getTempCByIndex(0) > (temperature_setpoint_airgun + deadzone)) && (digitalRead(normal_heat_in == HIGH)))
        digitalWrite(airgun_relay, LOW);
      lcd.setCursor(15, 3);
      lcd.print("  OFF");
    }
    // }
    {
      Serial.print("Requesting temperatures...");
      sensor_range.requestTemperatures();
      sensor_club.requestTemperatures();
      sensor_airgun.requestTemperatures();
      Serial.println(" done");

      Serial.print("Range: ");
      Serial.println(sensor_range.getTempCByIndex(0));

      Serial.print("Club: ");
      Serial.println(sensor_club.getTempCByIndex(0));

      Serial.print("Airgun: ");
      Serial.println(sensor_airgun.getTempCByIndex(0));

      Serial.print("Frost In ");
      Serial.println(frost_heat_in);

      Serial.print("Heat In ");
      Serial.println(normal_heat_in);
    }

    //------------------------------Date display--------------------------//

    lcd.setCursor(0, 0);
    lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
    lcd.setCursor(3, 0);
    lcd.print(":");
    lcd.setCursor(4, 0);
    if (now.day() <= 9) {
      lcd.print("0");
      lcd.setCursor(5, 0);
      lcd.print(now.day(), DEC);
    } else {
      lcd.print(now.day(), DEC);
    }
    lcd.setCursor(6, 0);
    lcd.print(":");
    lcd.setCursor(7, 0);
    if (now.month() <= 9) {
      lcd.print("0");
      lcd.setCursor(8, 0);
      lcd.print(now.month(), DEC);
    } else {
      lcd.print(now.month(), DEC);
    }
    lcd.setCursor(9, 0);
    lcd.print(":");
    lcd.setCursor(10, 0);
    lcd.print(now.year(), DEC);

    //-------------------------Time display-------------------------------//
    lcd.setCursor(15, 0);
    if (now.hour() <= 9) {
      lcd.print("0");
      lcd.setCursor(16, 0);
      lcd.print(now.hour(), DEC);
    } else {
      lcd.print(now.hour(), DEC);
    }
    lcd.setCursor(17, 0);
    lcd.print(":");
    lcd.setCursor(18, 0);
    if (now.minute() <= 9) {
      lcd.print("0");
      lcd.setCursor(19, 0);
      lcd.print(now.minute(), DEC);
    } else {
      lcd.print(now.minute(), DEC);
    }
    lcd.setCursor(17, 0);
    lcd.print(":");
    lcd.setCursor(18, 0);

    //-----------------------Temperature display - -----------------------//

    {
      lcd.setCursor(0, 1);  // Range
      lcd.print("Range:");
      lcd.setCursor(7, 1);
      // lcd.print(rtc.getTemperature());
      lcd.print(sensor_range.getTempCByIndex(0));

      lcd.setCursor(12, 1);
      lcd.write((char)223);
      lcd.setCursor(13, 1);
      lcd.print("C");
      // lcd.setCursor(18, 1);
      // lcd.print(char(0));

      lcd.setCursor(0, 2);  // Clubroom
      lcd.print("Club:");
      lcd.setCursor(7, 2);
      // lcd.print(rtc.getTemperature());
      lcd.print(sensor_club.getTempCByIndex(0));

      lcd.setCursor(12, 2);
      lcd.write((char)223);
      lcd.setCursor(13, 2);
      lcd.print("C");
      // lcd.setCursor(14, 2);
      // lcd.print("    ");
      // lcd.print(char(0));

      lcd.setCursor(0, 3);  // Airgun Range
      lcd.print("Airgun:");
      lcd.setCursor(7, 3);
      // lcd.print(rtc.getTemperature());
      lcd.print(sensor_airgun.getTempCByIndex(0));

      lcd.setCursor(12, 3);
      lcd.write((char)223);
      lcd.setCursor(13, 3);
      lcd.print("C");
      // lcd.setCursor(18, 3);
      // lcd.print(char(0));

      delay(3000);
    }
  }
}

I will start a new topic as quite a lot has changed.

Bad idea. You are going to be wasting your own time 'splaining things that have already been, and getting asked questions that are answered elsewhere.

Flag your own post and ask a moderator to move it back to the thread where your other problems are.

a7

Your new topic has been merged into this one to maintain the context of the question

Your two or more topics on the same or similar subject have been merged.

Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.

Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.

Repeated duplicate posting could result in a temporary or permanent ban from the forum.

Could you take a few moments to Learn How To Use The Forum

It will help you get the best out of the forum in the future.

Thank you.

You still have this issue spotted and solved upthread:

digitalRead(normal_heat_in == HIGH)

It's not the only one :face_with_raised_eyebrow:

Notice the different level of indentation there? You do not have an curly braces for your if() clause so only normal_heat_out is being set HIGH based on the conditional.

Setting frost_heat_out LOW will always happen.

This is unnecessarily complicate your logic.

You are the only one who ever writes to digital outputs, so you "know" what the value is on the pin should be is. In,escs you are fault checking the digital output, but if you worried about that, there's all kindsa things to worry about. Trust, and if verification is important, use you voltmeter or logic analyzer or whatever to confirm that the microprocessor is functioning accurately.

When you write to the normalheatout pin, write the same value to a flag variable that will hold the state of normal heat.

Same same the other signal.

Or you can actually just digital read a pin you want to interrogate. But a variable keeps the logic separate from the hardware.

I can't look at the code now, but it does seem like the delay is what is causing the periodic switching.

It is probably possible to loop and each time through check the inputs and the current activity, and use that to inform decisions about what or how the activity should be reported or changed.

This is the IPO model, see it described abstractly here

I am contractually obligated to give @paulpaulson a shout out if I mention this.

The other concept that should help here is called "state", a shorthand for referring to all the things that woukd go into unambiguously saying what the process is up to and what kind of progress along a set of steps, not necessarily in any order, it is making.

For reporting, you can do a generic LCD print and use a "blink without delay" pattern so no matter how fast the loop, the printing only happens when something changes, or every three seconds no matter nothing has changed or whatever.

a7