Timer not shutting down

hi guys, need some help please, i have a relay controlling a steamer, i need it to shut down after the time is finished and i cant seem to achieve it, i am running 2 seperate programs and the programs are running the temp control is working but it is not shutting down after the time has elapsed please help

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

LiquidCrystal_I2C lcd(0X27, 20, 4); // Adjust the LCD size to 20x4

unsigned long previousMillis = 0;
const unsigned long interval = 1000;  // Update interval in milliseconds

#define COOKER  6
#define PROGRAM_PIN 4  // Pin to select program (HIGH: Program 1, LOW: Program 2)
#define bt_set    9
#define bt_up     10
#define bt_down   11
#define bt_start  12
bool exitProgram = false;
unsigned int gourmetTime_h = 0; // Set the desired time for Gourmet program
unsigned int gourmetTime_m = 0;
unsigned int gourmetTime_s = 30;

unsigned int magicsTime_h = 0;  // Set the desired time for Magics program
unsigned int magicsTime_m = 1;
unsigned int magicsTime_s = 0;

const float gourmetDesiredTemperature = 96.0; // Desired temperature for Gourmet program
const float magicsDesiredTemperature = 60.0;  // Desired temperature for Magics program

bool isTimerRunning = false;
unsigned long timerStartTime = 0;
unsigned long currentMillis = 0;

int thermoDO = A0;
int thermoCS = A1;
int thermoCLK = A2;
#define DS18B20_PIN 2  // Change this to the actual pin you're using
OneWire oneWire(DS18B20_PIN);
DallasTemperature ds18b20(&oneWire);

enum ProgramState {
  GOURMET,
  MAGICS
};

ProgramState currentProgram = GOURMET;

void setup() {
  // Initialize setup code here
  lcd.init();
  lcd.backlight();
  ds18b20.begin();
  pinMode(bt_set, INPUT_PULLUP);   // Set button with internal pull-up resistor
  pinMode(PROGRAM_PIN, INPUT_PULLUP); // Set program pin as input with pull-up
  pinMode(DS18B20_PIN, INPUT_PULLUP); // Set DS18B20 pin as input with pull-up
  pinMode(COOKER, OUTPUT);
  lcd.setCursor(0, 1);

  lcd.print("Welcome To Pasturizer");
  lcd.clear();  // Clear the screen
}

void loop() {
  updateProgramState();
  ds18b20.requestTemperatures();
  float currentTemperature = ds18b20.getTempCByIndex(0);  // Assuming only one sensor is connected

  lcd.setCursor(0, 0);
  lcd.print(currentProgram == GOURMET ? "Gourmet" : "Magics");
  lcd.setCursor(0, 3);
  lcd.print("Temp: ");
  lcd.print(currentTemperature);
  lcd.print("C");

  // Display the selected program time
  lcd.setCursor(0, 1);
  lcd.print("Time:");
  printSelectedProgramTime();

  currentMillis = millis();
  if (digitalRead(COOKER) == HIGH ){
    lcd.setCursor(9, 0);
    lcd.print("Heat");
  }
  else{    lcd.setCursor(9,0);
    lcd.print("Cool");
  }

  if (!isTimerRunning && currentTemperature >= getDesiredTemperature(currentProgram)) {
    startTimer();
  }

  if (isTimerRunning) {
    unsigned long elapsedMillis = currentMillis - timerStartTime;
    unsigned long remainingMillis = 0;

    if (currentProgram == GOURMET) {
      remainingMillis = (gourmetTime_h * 3600000UL + gourmetTime_m * 60000UL + gourmetTime_s * 1000UL) - elapsedMillis;
    } else if (currentProgram == MAGICS) {
      remainingMillis = (magicsTime_h * 3600000UL + magicsTime_m * 60000UL + magicsTime_s * 1000UL) - elapsedMillis;
    }

    lcd.setCursor(0, 2);
    lcd.print("Remaining:");
    printTime(remainingMillis);

    if (remainingMillis == 0) {
      stopTimer();
      digitalWrite(COOKER, LOW);
      // Turn off the cooker when the timer is done
    } else {
      controlCooker(currentTemperature);
    }
  }

  // Your code to control the timer and heating logic...
}

void updateProgramState() {
  if (digitalRead(PROGRAM_PIN) == LOW) {
    currentProgram = GOURMET;
  } else {
    currentProgram = MAGICS;
  }
}

float getDesiredTemperature(ProgramState program) {
  if (program == GOURMET) {
    return gourmetDesiredTemperature;
  } else if (program == MAGICS) {
    return magicsDesiredTemperature;
  }
  return 0.0; // Default
}

void startTimer() {
  timerStartTime = millis();
  isTimerRunning = true;
  digitalWrite(COOKER, HIGH);  // Turn on the cooker when the timer starts
}

void stopTimer() {
  isTimerRunning = false;
   stopTimer();
  digitalWrite(COOKER, LOW);  // Turn off the cooker when the timer stops
     exit(0);
}

void controlCooker(float currentTemperature) {
  float desiredTemp = getDesiredTemperature(currentProgram);

  if (!isTimerRunning) {
    // If timer is not running, keep the cooker on for warming up
    digitalWrite(COOKER, HIGH);
  } else if (currentTemperature < desiredTemp) {
    // Turn on the cooker if temperature is below the desired temperature
    digitalWrite(COOKER, HIGH);
  } else {
    // Turn off the cooker if temperature is at or above the desired temperature
    digitalWrite(COOKER, LOW);
  }
}







void printTime(unsigned long timeInMillis) {
  unsigned int hours = timeInMillis / 3600000UL;
  unsigned int minutes = (timeInMillis % 3600000UL) / 60000UL;
  unsigned int seconds = (timeInMillis % 60000UL) / 1000UL;

  if (hours < 10) lcd.print("0");
  lcd.print(hours);
  lcd.print(":");
  if (minutes < 10) lcd.print("0");
  lcd.print(minutes);
  lcd.print(":");
  if (seconds < 10) lcd.print("0");
  lcd.print(seconds);
}

void printSelectedProgramTime() {
  unsigned int programHours, programMinutes, programSeconds;

  if (currentProgram == GOURMET) {
    programHours = gourmetTime_h;
    programMinutes = gourmetTime_m;
    programSeconds = gourmetTime_s;
  } else if (currentProgram == MAGICS) {
    programHours = magicsTime_h;
    programMinutes = magicsTime_m;
    programSeconds = magicsTime_s;
  }

  if (programHours < 10) lcd.print("0");
  lcd.print(programHours);
  lcd.print(":");
  if (programMinutes < 10) lcd.print("0");
  lcd.print(programMinutes);
  lcd.print(":");
  if (programSeconds < 10) lcd.print("0");
  lcd.print(programSeconds);
}

I've fixed your (attampt to) code tags. Thanks for remembering them after all this time.
[code] should have been on its own line :wink:

thank you i was trying

Without going through all your code (I did glance over it)

The usual solution to this is to have a global flag variable that you set when you start up, and clear when the cycle is complete.

Use that flag within your code to ignore the run phase until it’s been set ‘again’

This will crash the program due to endless recursion.
What is exit() expected to do on your controller?

i want it to exit the current running program

but currently it just continues to operate even when the time has elapsed i am by no means an expert with coding and dont do much work in this field

It looks like your code at line 176, switch on output ON whenever the timer is not running.

if (!isTimerRunning)
	{
		// If timer is not running, keep the cooker on for warming up
		digitalWrite(COOKER, HIGH);
	}

I woud suggest to draw the states of cooker logic and the states of timer logic on paper and carefully observe the conditions for transitions from one state to another one. BTW I really like you separate code to individual functions this make your code readable.

This statement is never reached : digitalWrite(COOKER, LOW); // Turn off the cooker when the timer stops. You could move it above stopTimer(); but, as has been pointed out, the code then effectively blocks in an infinite recursive loop requiring a reset of the Arduino.

i just see one program
what do you think are the 2 programs?

i didn't realize the exit() just stops the code from running. if you think think there are 2 programs, both will stop running

it has two seperate timers to be toggeld by pin 4
and it does not exit anything

The exit( 0 ) statement in this case is never reached. On the subject of exit() in an Arduino environment, there is this discussion: use of exit(0)

How will i get it to reach the exit

What do you want to happen when the timer has expired ? Clearly you want to switch off the cooker. Do you then want the arduino to wait in an infinite loop until it is manually reset ? In other words, what were you hoping the exit statement would do ? In an Arduino, at least of the Uno/Nano class, it just blocks.

Put it into the first line in the function.

both at the same time?

No if the button is pushed one times if the button is relased the other timer it is a latching button

Yes it must not start up again until its reset

Then try this:

void stopTimer() {
  isTimerRunning = false;
  // stopTimer();
  digitalWrite(COOKER, LOW);  // Turn off the cooker when the timer stops
  // exit(0);
  while( true ) ;  // wait until Arduino reset
}

so shouldn't the "program" button be checked once in setup() and that determines the parameters for what the program (singular) should do?

or do you switch between the to options while it is running?