Roll over and data types got me spinning- Do you know the answer?

Hello My Arduino People,
I believe I'm having issues on one of my codes with data types.
I'm hoping some of you good people can help me figure it out.
On the surface it seems to be a roll over issue, but I'm unsure why or how to fix it.
This project requires a timer where something is turned on for X amount of time and turned off for Y amount of time.
Where X and Y are controlled by potentiometers.
The On and Off intervals are dictated by a delta defined using millis().
My issue seems to lie in millis() as it's a very large number and I need to convert it into increments of Half minutes. (0.5 min intervals)
I'm dealing with intervals of up to 45min ON and 45 min OFF, so a half min is much more intuitive than 2,700 seconds.
I've tried to run the conversion with both a Float and a Double as the variable housing the result but both return negative answers regardless of all inputs being positive values.
Find my code attached to sample the results yourself.
Maybe I'm missing something bigger here. Not sure.

EDIT: Sorry for the sloppy post. It's been a while since I pasted code here. I'll be sure to re-up my reading on the posting guidlines. Scroll down to see pasted code for easy viewing. Thanks

Interval_counter_Millis_test_1.ino (2.94 KB)

More members will see your code if you post your code as described in the forum guidelines.

Post your code as described in the forum guidelines. Few here will download your files.

Millis are unsigned longs. Not Float or Double (which are the same in the Arduino).

When checking for elapsed time always use the construct:

"millis() - lastTimeChecked >= elapsedTargetTime"

This will make sure that the point at which millis() has rolled over and lastTimeChecked was before the rollover is worked out properly in the arithmetic.

Noted. Will do.

Below you can find my code. Thank you.

For the millis() variable I am using unsigned long as noted in the documentation references.

This part seems to be functioning properly.

Where I am struggling is I want to convert millis to (0.5 min) intervals for serial display.

// convert millisecond to minutes
double onLimit_Min = (onLimit_ms/(100060));
double offInterval_Min = (offInterval_ms/(1000
60));

const int pot_1 = A2;
const int pot_2 = A3;

const float ctMultiplier = 30000;     // 30000milliseconds == 30 seconds
const int mappedUpperLimit = 91;    // 30sec*90 == 45min ; 91 is used to ensure 45min is reached as pot may fall short of full scale value of 1023


const byte LED = 13;

unsigned long ct1 = 0; // initialize the count interval
unsigned long ct2;


void setup() {
  Serial.begin(9600);
  pinMode(LED, OUTPUT);

}

void loop() {
  ct2 = millis(); // Start the count 

// Read raw Potentiometer data
  int  pot_1_rawData = analogRead(pot_1);
  int  pot_2_rawData = analogRead(pot_2);

// map Raw pot data for smoother incrementation of timming intervals
  int pot_1_mappedData = map(pot_1_rawData, 0, 1023, 0, mappedUpperLimit);
  int pot_2_mappedData = map(pot_2_rawData, 0, 1023, 0, mappedUpperLimit);

// create varibles and functions to store timmed interval that LED will be ON and OFF
//Multimpler is used to increment mapped data to larger intervals of time

// double is used so I can convert from milliseconds to 0.5 min increments
  double onLimit_ms = pot_1_mappedData * ctMultiplier;
  double resetLimit_ms = (pot_2_mappedData * ctMultiplier) + onLimit_ms;

// Set interval limits and compare them to the millis() count value
  double offInterval_ms = ( resetLimit_ms - onLimit_ms );
  long interval = ct2 - ct1;

// convert millisecond to minutes
  double onLimit_Min = (onLimit_ms/(1000*60));
  double offInterval_Min = (offInterval_ms/(1000*60));

// Print data
  Serial.print("pot 1 Raw Data = ");
  Serial.println(pot_1_rawData);
  Serial.print("pot 2 Raw Data = ");
  Serial.println(pot_2_rawData);

  Serial.print("pot 1 Mapped Data = ");
  Serial.println(pot_1_mappedData);
  Serial.print("pot 2 Mapped Data = ");
  Serial.println(pot_2_mappedData);

  Serial.print("onLimit_ms = ");
  Serial.println(onLimit_ms);
  Serial.print("resetLimit_ms = ");
  Serial.println(resetLimit_ms);
  Serial.print("offInterval_ms = ");
  Serial.println(offInterval_ms);

  Serial.print("onLimit_Min = ");
  Serial.println(onLimit_Min);
  Serial.print("offInterval_Min = ");
  Serial.println(offInterval_Min);  

  Serial.print("Time ct1 = ");
  Serial.println(ct1);
  Serial.print("Time ct2 = ");
  Serial.println(ct2);

  Serial.print( "interval = ");
  Serial.println(interval);
  Serial.print( "abs(interval) = ");
  Serial.println(abs(interval));



// Action Items
// use abs() to ensure when the counting variable (ct2) rolls over its limit the difference still falls within the rules of if statemets below
  if( abs(interval) < onLimit_ms ){
    digitalWrite(LED, HIGH);
    Serial.print("HIGH");
  }
  else{
    digitalWrite(LED, LOW);
    Serial.print("LOW");
  }

  if ( abs(interval) >= resetLimit_ms ){
    ct1=ct2;
    Serial.print("RESET");
  }

  Serial.println("//***************************************************************************************");
  Serial.println();


}

(1000*60) will be treated as an int. An int has a maximum value of 32767. 60000 will cause the int to roll over to some negative number.

Try using (1000. *60) [NOTICE THE DECIMAL POINT] instead. This will not roll over and will not be treated as an int.

This occurs in multiple places.

#define   SECOND   1000   // MS
#define   MINUTE   SECOND * 60
#define   HOUR     MINUTE * 60

This help?

-jim lee

// convert millisecond to minutes
 double onLimit_Min = (onLimit_ms/(1000*60));
 double offInterval_Min = (offInterval_ms/(1000*60));

What part of "millis is an unsigned long" did you not read?

A minute is 3600 ms, so half a minute would be 1800 ms. Your math makes no sense.

vaj4088:
(1000*60) will be treated as an int. An int has a maximum value of 32767. 60000 will cause the int to roll over to some negative number.

Try using (1000. *60) [NOTICE THE DECIMAL POINT] instead. This will not roll over and will not be treated as an int.

This occurs in multiple places.

This looks to be helpful. Thank you

jimLee:

#define   SECOND   1000   // MS

#define   MINUTE   SECOND * 60
#define   HOUR     MINUTE * 60




This help?

-jim lee

This indeed looks helpful thank you Jim Lee

BearManTooth:

jimLee:

#define   SECOND   1000   // MS

#define  MINUTE  SECOND * 60
#define  HOUR    MINUTE * 60




This help?

-jim lee

Except two of them won't always give the results you think they will....

SteveMann:

// convert millisecond to minutes

double onLimit_Min = (onLimit_ms/(100060));
double offInterval_Min = (offInterval_ms/(1000
60));




What part of "millis is an unsigned long" did you not read?

A minute is 3600 ms, so half a minute would be 1800 ms. Your math makes no sense.


**Calm down Stevie boy.** 
**It doesn't sound like you understand how prefixes work.**
**If you're gonna be a dick at least be right.**

You really should do everything in 'unsigned long' using milliseconds. It's OK to display intervals in minutes but there is no need to store values in minutes or half-minutes.

const int pot_1 = A2;
const int pot_2 = A3;


const unsigned long ctMultiplier = 30000ul;     // 30 seconds


 // 30 sec * 90 == 45 min ; 91 is used to ensure 45 min is reached as pot 
// may fall short of full scale value of 1023

const int mappedUpperLimit = 91;   


unsigned long PreviousTime = 0; // initialize the count interval
void setup()
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}


void loop()
{
  unsigned long currentTime = millis(); // Start the count


  // map Raw pot data for smoother incrementation of timming intervals
  int pot_1_mappedData = map(analogRead(pot_1), 0, 1023, 0, mappedUpperLimit);
  int pot_2_mappedData = map(analogRead(pot_2), 0, 1023, 0, mappedUpperLimit);


  // create variables and functions to store timed interval that LED_BUILTIN will be ON and OFF
  // Multiplier is used to increment mapped data to larger intervals of time


  // double is used so I can convert from milliseconds to 0.5 min increments
  unsigned long onInterval_ms = pot_1_mappedData * ctMultiplier;
  unsigned long offInterval_ms = pot_2_mappedData * ctMultiplier;
  unsigned long resetInterval_ms = onInterval_ms + offInterval_ms;


  // Set interval limits and compare them to the millis() count value
  unsigned long interval = currentTime - PreviousTime;


  // Print data
  Serial.print("pot 1 Mapped Data = ");
  Serial.println(pot_1_mappedData);
  Serial.print("pot 2 Mapped Data = ");
  Serial.println(pot_2_mappedData);


  Serial.print("onInterval_ms = ");
  Serial.println(onInterval_ms);
  Serial.print("offInterval_ms = ");
  Serial.println(offInterval_ms);
  Serial.print("resetInterval_ms = ");
  Serial.println(resetInterval_ms);


  Serial.print("onInterval_Min = ");
  Serial.println(onInterval_ms / 60000ul);
  Serial.print("offInterval_Min = ");
  Serial.println(offInterval_ms / 60000ul);


  Serial.print("Time PreviousTime = ");
  Serial.println(PreviousTime);
  Serial.print("Time currentTime = ");
  Serial.println(currentTime);


  Serial.print( "interval = ");
  Serial.println(interval);


  // Action Items


  if (interval < onInterval_ms)
    digitalWrite(LED_BUILTIN, HIGH);
  else
    digitalWrite(LED_BUILTIN, LOW);


  if (interval >= resetInterval_ms)
  {
    PreviousTime = currentTime;
    Serial.print("RESET");
  }


  Serial.println("//***************************************************************************************");
  Serial.println();
}