Double Timers

Hello, first post here so please excuse me I miss some obvious board etiquette.

I am working on a project where I have two timed functions.
-The first is a working time, nothing happens before the button is pushed followed by all functions ending at interval X.
-The second timer is much shorter and does not “just loop” it must fulfil obligations to initiate and this can take shorter or longer depending on the resistance ( currently a potentiometer).

The actual project is controlling a heater element via relays while polling resistance on specified intervals.
I am here because I am not getting coinsistant durations of time. I get different durations each time I run the code.

Thank you for taking a look,

// Randy

// Push Button on pin 5
int buttonState;
int lastButtonState;

// Potentiometer on A4
int pot;

//------------------
boolean runMode;
boolean heatMode;
boolean pollMode;

unsigned long intervalA = 20000; // Primary Timer
unsigned long previousMillisA;

unsigned long intervalB = 5000; // Secondary Timer
unsigned long previousMillisB;


void setup() {
Serial.begin(9600);
pinMode (5, INPUT);
pinMode (A4, INPUT);

// LED indicators
pinMode (11, OUTPUT);
pinMode (12, OUTPUT);
pinMode (13, OUTPUT);

runMode = false;
pollMode = false;
heatMode = false;
}

void loop() {
unsigned long currentMillis = millis();

// Serial Refernce 
Serial.print ("Pot Value   ");
Serial.println (pot);

Serial.print ("RunMode  ");
Serial.println (runMode);

Serial.print ("pollMode  ");
Serial.println (pollMode);

Serial.print ("heatMode  ");
Serial.println (heatMode);

pot = analogRead (A4);
buttonState = digitalRead (5);

// ------START BUTTON------
if (buttonState == HIGH){
runMode = true;
heatMode = true;}

// ------Saftey Off------
if (runMode == false){
   heatMode = false;
   pollMode = false;
}



// ------PRIMARY TIMER------
if ((currentMillis - previousMillisA >= intervalA) && runMode == true) {
    previousMillisA = currentMillis;
    Serial.print ("Primary Timed Out");
    if (runMode == true){
    runMode = false;}
  } 


// ------SECONDARY TIMER------
    if ((currentMillis - previousMillisB >= intervalB) && runMode == true && heatMode == HIGH ) {
    previousMillisB = currentMillis;
    Serial.print ("Secondary TIMED OUT ");
   if (heatMode == HIGH) {
   heatMode = LOW;} 
 }



// -----Read-----
if (heatMode == false && runMode ==true ){
  pollMode = true;}
  else 
  {pollMode = false;}

   
if (pollMode == true && pot <= 300){
  previousMillisB = currentMillis;
  pollMode = false;
  heatMode = true;}
  else 
  { pollMode = true;
  heatMode = false;}


// -----EXECUTE-----

if (heatMode == true){
  digitalWrite (11, HIGH);
}else{
  digitalWrite (11, LOW);
}

if (runMode == true){
  digitalWrite (12, HIGH);
}else{
  digitalWrite (12, LOW);
}


if (pollMode == true){
  digitalWrite (13, HIGH);
}else{
  digitalWrite (13, LOW);}

 }

How is the switch connected to pin 5 wired?

Analog pins are input only. You should not use a pinMode() statement to diddle with the digital nature of the pin that shares that physical location.

Since runMode, heatMode, and pollMode are all boolean you don't need to use '== true' to get a boolean value. You can just say "if (runMode)". That also works for any integer where you want to test for the value being zero (false) or non-zero (true).

You have several places where you have an 'if' statement inside another 'if' statement such that you are testing for a condition that you already know:

  // ------PRIMARY TIMER------
  if ((currentMillis - previousMillisA >= intervalA) && runMode == true) {
    previousMillisA = currentMillis;
    Serial.print ("Primary Timed Out");
    if (runMode == true) {
      runMode = false;
    }
  }

You don't need to test runMode again since you would not be inside the 'if' unless runMode was true.

  // ------PRIMARY TIMER------
  if ((currentMillis - previousMillisA >= intervalA) && runMode) {
    previousMillisA = currentMillis;
    Serial.print ("Primary Timed Out");
    runMode = false;
  }

Since 'intervalA' is only measured while in runMode you should probably set previousMillisA only when you set runMode to true. If you reset it here and not when runMode starts you will be measuring from the previous timeout, not from the start of runMode.

Thank you for both responses. I do apprichiate the guidance.

I adjusted the previousMillisA as per suggestion, and everything is on track.
Thanks for the help.

Here is the updated script if anyone is interested.

// Push Button on pin 5
int buttonState;
int lastButtonState;

// Potentiometer on A4
int pot;

//------------------
boolean runMode;
boolean heatMode;
boolean pollMode;

unsigned long intervalA = 20000; // Primary Timer
unsigned long previousMillisA;

unsigned long intervalB = 5000; // Secondary Timer
unsigned long previousMillisB;


void setup() {
Serial.begin(9600);
pinMode (5, INPUT);

// LED indicators
pinMode (11, OUTPUT);
pinMode (12, OUTPUT);
pinMode (13, OUTPUT);

runMode = false;
pollMode = false;
heatMode = false;
}

void loop() {
unsigned long currentMillis = millis();

// Serial Refernce 
Serial.print ("Pot Value   ");
Serial.println (pot);

Serial.print ("RunMode  ");
Serial.println (runMode);

Serial.print ("pollMode  ");
Serial.println (pollMode);

Serial.print ("heatMode  ");
Serial.println (heatMode);

pot = analogRead (A4);
buttonState = digitalRead (5);

// ------START BUTTON------
if (buttonState == HIGH){
runMode = true;
previousMillisA = currentMillis;
heatMode = true;
pollMode = false;}

// ------Saftey Off------
if (runMode == false){
   heatMode = false;
   pollMode = false;
}


// ------PRIMARY TIMER------
if ((currentMillis - previousMillisA >= intervalA) && runMode == true) {
    Serial.print ("Primary Timed Out");
    runMode = false;}
 


// ------SECONDARY TIMER------
    if ((currentMillis - previousMillisB >= intervalB) && runMode == true && heatMode == true ) {
    previousMillisB = currentMillis;
    Serial.print ("Secondary TIMED OUT ");
    heatMode = false;} 
 



// -----Read-----
if (heatMode == false && runMode ==true && pollMode == false ){
  pollMode = true;
  heatMode = false;}
   
if (runMode == true && pollMode == true && pot <= 300 && heatMode == false){
  previousMillisB = currentMillis;
  pollMode = false;
  heatMode = true;}
 


// -----EXECUTE-----

if (heatMode == true){
  digitalWrite (11, HIGH);
}else{
  digitalWrite (11, LOW);
}

if (runMode == true){
  digitalWrite (12, HIGH);
}else{
  digitalWrite (12, LOW);
}

if (pollMode == true){
  digitalWrite (13, HIGH);
}else{
  digitalWrite (13, LOW);}

 }
// Push Button on pin 5
int buttonState;
int lastButtonState;

// Potentiometer on A4
int pot;

Then why not make a variable to hold which pin the button and pot is connected to? Now you need to remember all that.

const byte ButtonPin = 5;
const byte PotPin = A4;

Makes it all a lot easier for you, us and future you ;)

Also, press CTRL+T in the IDE, does look much better, doesn't it?

And try to get in the habit of picking the smallest possible variable that's large enough. It's not a Intel i7 with 64GB of RAM. See how I used byte for the pins? Also, declare then as local as possible. There is no reason for pot to be global other then you work backwards. You first want to print everything and then you go off reading and changing stuff. I would say it's easier to first read stuff, do stuff and then report back ;)

The code can be made more readable with more descriptive variable names and use of the properties of boolean variabes:

const byte StartButtonPin = 5;
const byte HeatModeLEDPin = 11;
const byte RunModeLEDPin = 12;
const byte PollModeLEDPin = 13;
const byte PotPin = A4;

// Push Button on pin 5
int LastButtonState;  // UNUSED?


//------------------
boolean RunMode;
boolean HeatMode;
boolean PollMode;

const unsigned long RunInterval = 20000; // Primary Timer
unsigned long RunStartTime;

const unsigned long HeatInterval = 5000; // Secondary Timer
unsigned long HeatStartTime;


void setup() {
  Serial.begin(9600);

  pinMode (StartButtonPin, INPUT);

  // LED indicators
  pinMode (HeatModeLEDPin, OUTPUT);
  pinMode (RunModeLEDPin, OUTPUT);
  pinMode (PollModeLEDPin, OUTPUT);

  RunMode = false;
  PollMode = false;
  HeatMode = false;
}

void loop() {
  unsigned long currentMillis = millis();

  int potValue = analogRead(PotPin);
  int buttonState = digitalRead(StartButtonPin);

  // Serial Refernce
  Serial.print ("Pot Value   ");
  Serial.println (potValue);

  Serial.print ("RunMode  ");
  Serial.println (RunMode);

  Serial.print ("PollMode  ");
  Serial.println (PollMode);

  Serial.print ("HeatMode  ");
  Serial.println (HeatMode);



  // ------START BUTTON------
  if (buttonState) {
    RunMode = true;
    // Start the run timer
    RunStartTime = currentMillis;
    HeatMode = true;
    PollMode = false;
  }


  // ------PRIMARY TIMER------
  if (RunMode &&
      (currentMillis - RunStartTime >= RunInterval)) {
    Serial.print ("Primary Timed Out");
    RunMode = false;
    HeatMode = false;
    PollMode = false;
  }


  // ------SECONDARY TIMER------
  if (RunMode && HeatMode &&
      (currentMillis - HeatStartTime >= HeatInterval)) {
    Serial.print ("Secondary TIMED OUT ");
    HeatMode = false;
  }


  // -----Read-----
  if (RunMode && !HeatMode && !PollMode) {
    PollMode = true;
    // HeatMode = false;
  }

  if (RunMode && PollMode && !HeatMode &&
      potValue <= 300) {
    // Switch from poll mode to heat mode
    PollMode = false;
    HeatMode = true;
    HeatStartTime = currentMillis;
  }

  // ------Saftey Off------
  if (!RunMode) {
    HeatMode = false;
    PollMode = false;
  }

  // -----EXECUTE-----
  digitalWrite (HeatModeLEDPin, HeatMode);
  digitalWrite (RunModeLEDPin, RunMode);
  digitalWrite (PollModeLEDPin, PollMode);
}