I'm having problems with long var acting as int variable.

Good morning.

Little basic idea to my project. I’m building a basic alarm type system to start my car at 5:30/7:30/3:30 throughout the day jumping my autostart, instead of me having to physically be there. Sometimes I’m miles from it!

Here is my code so far. It’s a bit wild. Basically, I have buttons to reset the time and correct it as I need because I don’t have an actual timer circuit for it yet. I’m using an arduino UNO. I’m using the time library and want to start at 0 seconds for each day. After one day, I want to reset the time back to zero. I know I’ll want to add in more days, but for now this is what I’m looking for. My problem is:

full_day and start_time1 act as ints. As soon as they go past the 32~~~ they go backwards. Why? I have them declared as long.

/* 
 * TimeSerialDateStrings.pde
 * example code illustrating Time library date strings
 *
 * This sketch adds date string functionality to TimeSerial.pde
 * 
 */ 
 
#include <Time.h>  
#include <LiquidCrystal.h>

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int switchstate = 0;
int switchstate2 = 0;
int switchstate3 = 0;
int timecheck;
int timecheck2;
unsigned long start_time1 = 0;
unsigned long full_day = 3600*24;



void setup()  {
  
  pinMode(6,INPUT);
  pinMode(8,OUTPUT);
  pinMode(9,INPUT);
  pinMode(10,INPUT);
  time_t t = now(); // Store the current time in time 
                    //  variable t 
  hour(t);          // Returns the hour for the given
                    //  time t
  minute(t);        // Returns the minute for the given
                    //  time t
  second(t);        // Returns the second for the given
                    //  time t 
  day(t);           // The day for the given time t

  weekday(t);       // Day of the week for the given
                    //  time t  
  month(t);         // The month for the given time t

  year(t);          // The year for the given time t
  
  Serial.begin(9600);
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.setCursor(0,0);
  lcd.print("BIGS!!");
  setTime(0);
}

void loop(){    
  
  switchstate = digitalRead(6);
  switchstate2 = digitalRead(10);
  switchstate3 = digitalRead(9);
  
  if (switchstate == LOW) {
  }
  else {
    //Serial.print("Button Pressed");
    delay(100);
    adjustTime(60);
  }
  
  if (switchstate2 == LOW) {
  }
  else {
    //Serial.print("Button Pressed");
    delay(100);
    adjustTime(3600);
  }
  
  if (switchstate3 == LOW) {
  }
  else {
    //Serial.print("Button Pressed");
    delay(100);
    setTime(0);
    //setTime(hz,mz, sz, 0,0,0);
  }
  
  timecheck = now();
  
  if (timecheck2 == timecheck) {
    //Serial.print("Do Nothing");
  }
  else{
    
    timecheck2 = timecheck;
    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print(year());
    lcd.print(" ");
    lcd.print(hour());
    lcd.print(":");
    lcd.print(minute());
    lcd.print(":");
    lcd.print(second());
    
  }
  //6:30 am = 23400
  if (now() > 23400 && now() < 23415){
    digitalWrite(8,HIGH);
  }
  else{
    digitalWrite(8,LOW);
  }
  
  //8:30 am = 30600
start_time1  = 35000 /// DOES NOT WORK
  if (now() > 30600 && now() < 30615){
    digitalWrite(8,HIGH);
  }
  else{
    digitalWrite(8,LOW);
  }
  
full_day = 86400; // THIS DOES NOT WORK
  if(now() > 86400){
    Serial.println("Time Reset");
    setTime(0);
  }
  
}
full_day = 86400UL;

Etc.

So if let's say I want to do something like this.

hour = 10
minute = 30
second = 0

time = (hour3600+minute60+second)UL

does that work?

No, but getting into the habit of writing constants (not expressions) with the suffix UL is a good idea.
E.g. daySeconds = 3600UL * 24UL;

So is there any way to use an expression with a long? How would you suggest an example of setting a time to the seconds? Thank you so much with the help so far also!

Edit. Just saw your edit!

Can you use ints in an expression of a long?

time = (hour*3600UL+minute*60UL+second)

With the UL there, the compiler will automatically promote smaller data types (byte, int, etc.) to an unsigned long for the calculation.

Ok. that makes more sense to me. I'm used to this day and age where most most of my programming has no worry about memory usage. I usually do most of my projects in Python and recently started on the arduino. Thank you so much.

I’m used to this day and age where most most of my programming has no worry about memory usage.

It has nothing to do with memory usage, rather it is the default size of the “int” type on an eight bit micro controller.
I’m not sure why the era is relevant - the AVR exists in “this day and age”, just as the quad core hyper-threaded Xeon does.

zsn0w:
I'm using the time library and want to start at 0 seconds for each day. After one day, I want to reset the time back to zero. I know I'll want to add in more days, but for now this is what I'm looking for.

I don't know this time library as I've never needed it. There is a simple and direct way that will let you set intervals up to 49.71 days in milliseconds without going to 64-bit integers. The example code is in your IDE under the name BlinkWithoutDelay but it has some minor errors (doesn't use unsigned long for -all- the time variables) so here's a fixed copy:

/* Blink without Delay -- with UL fixes... 2013
 
 Turns on and off a light emitting diode(LED) connected to a digital  
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.
 
 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.
 
 
 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen
modified 2013 to make all the time variables unsigned long
 by GFS 
 
 This example code is in the public domain.

 Without the 2013 fixes:
 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay 
 */

// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0UL;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long interval = 1000UL;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Learn this, understand what these few lines do and you have the key to multitasking on Arduino.

The big important part is:

  if(currentMillis - previousMillis > interval) {

In that unsigned subtraction you will ALWAYS get the difference from previous to current even through the dreaded rollover BECAUSE it is UNSIGNED subtraction. It is the same as looking at a clock and knowing that 1 o'clock is 2 hours after 11 o'clock. Unsigned math is like a clock.

Here is a sketch that you can use and modify to see just how unsigned math works:

unsigned long a, b, c;

void setup() {
  Serial.begin( 9600 );
  a = 0xffffff00UL;
  b = 0x10UL;
  Serial.println( "\n unsigned math\n" );
  Serial.print( "a = ");
  Serial.print( a, DEC );
  Serial.print( " = 0x");
  Serial.print( a, HEX );
  Serial.print( " = 0b");
  Serial.println( a, BIN );
  Serial.print( "b = ");
  Serial.print( b, DEC );
  Serial.print( " = 0x");
  Serial.print( b, HEX );
  Serial.print( " = 0b");
  Serial.println( b, BIN );
  if ( b >= a ) Serial.println( "b >= a" );
  else          Serial.println( "a > b" );
  c = a - b;
  Serial.print( "a - b = ");
  Serial.print( c, DEC );
  Serial.print( " = 0x");
  Serial.print( c, HEX );
  Serial.print( " = 0b");
  Serial.println( c, BIN );
  c = b - a;
  Serial.print( "b - a = ");
  Serial.print( c, DEC );
  Serial.print( " = 0x");
  Serial.print( c, HEX );
  Serial.print( " = 0b");
  Serial.println( c, BIN );
  c = b - (b + 1);
  Serial.print( "b - (b + 1) = ");
  Serial.print( c, DEC );
  Serial.print( " = 0x");
  Serial.print( c, HEX );
  Serial.print( " = 0b");
  Serial.println( c, BIN );
  
  while( 1 );
}

void loop() {};

So a day is 24UL * 60UL * 60UL * 1000UL; // the compiler pre-calculates, hours x minutes x seconds x millis.

UNO time is not exact and varies some with temperature. You can test how far off and use that to correct your interval values.

zsn0w:
time = (hour3600+minute60+second)UL
does that work?

I thought I would explore a little more for you exactly why this doesn't work. Constants such as 3600 and 60 default to int. If we assume that hour, minute, and second are defined as ints, then the expression works out to:

unsigned long time = (unsigned long)((int)hour * (int)3600 + (int)minute * (int)60 + (int)second)

Check the parentheses there. Inside the parentheses, everything is an integer. The integer math completes (including unwanted rollovers) and then the result is cast as an unsigned long. But that's not what we want. The damage has already been done. What we want is:

unsigned long time = (unsigned long)hour * 3600UL + (unsigned long)minute * 60UL + (unsigned long)second

That way, the numbers are treated as unsigned longs when the math is being done, and the unwanted rollovers won't occur.

The syntax that I'm using, of putting the data type in parentheses before the variable or constant, is called type-casting, and can be used anywhere, to cast pretty much any variable or constant as pretty much any simple data type. I disagree with AWOL's suggestion to get into the habit of putting UL after constants, mostly because it's tedious, but also because it will get you in trouble sometimes if you don't stop to think about why you are doing it. For example:

long bigNumber = -10000000UL * multiplier;

Oops. You've cast a negative number as an unsigned long. The operation will complete, but the results won't be what you expect, because the negative value will go away when the literal is cast as an unsigned long. In essence, when working with the Arduino, you need to keep half a mind out for mathematical operations in which a final or intermediate value will exceed the range of -32,768 to 32,767. Because you don't always know exactly what value the operation will produce, it isn't necessary to compare to exactly those values every time. Just check your rough order of magnitude for the number, and if it is going to go up around 30,000, it's best to go up to long or unsigned long.

Bear in mind that sometimes intermediate values will need casting, such as:

byte b;
byte foo = 255 * b / 1000

The "255 * b" operation will produce a value that can exceed 32,767, even though the result will always be small enough to store in a byte without rollover. This operation will produce unexpected results and casting 255 to unsigned long is required.

For example:

Code:

long bigNumber = -10000000UL * multiplier;

Oops. You’ve cast a negative number as an unsigned long.

Just as there is no cast in that expression, there is no “Oops” either - “big” will contain the expected -(multiplier x 107).
(Unless, of course, “multiplier” is bigger than 214)

51 * b / 200

will not exceed 32767.

AWOL:
Just as there is no cast in that expression, there is no “Oops” either - “big” will contain the expected -(multiplier x 107).
(Unless, of course, “multiplier” is bigger than 214)

Is this because, although the UL cannot represent a negative number, the underlying bit-pattern that occurs when you put a negative number into a UL “container” still works out correctly mathematically when that number is used in mathematical operations with signed data-types?

Is there a down-side, then, to casting all literal numerical values as UL? Certainly not memory use, since the values only exist for the duration of the operation.

I should have been more careful and explicit.
I do not advocate modifying all constants UL, I was really referring to those in the OP's problem-space of time calculations, where it makes sense.

We're in an awkward state now, where "Arduino" could mean an Uno or a Due, with different "int" sizes, so for portability, I suggest getting into the habit of using modifiers.

Considering that b initializes as 0....

It's better to use unsigned long variables for all your time math and make hour, minute and second const unsigned long so they stay in flash where they belong. Mixed-type operations deserve care with casting.

Remember that rollover is not a problem when subtracting one unsigned integer from another. You will always get the difference, just take care to get the order right: ( timeNow - timeStart >= timeInterval ).

If I want to run code 2 hours from now, I set timeStart = millis() and timeInterval = 2UL * oneHour and let time catch up.

I save millis() as a variable named timeNow and then if I add 2 hours, it adds to the time that hit or went over timeInterval (in the expression above) and not that time plus however long the code took to get to the add 2 hours part. IF you code a fast loop(), you won't go over timeInterval milliseconds.
Also remember that an Arduino with a resonator won't be nearly as accurate as one with a crystal.

If you need better then get an RTC module.

Is there a down-side, then, to casting all literal numerical values as UL? Certainly not memory use, since the values only exist for the duration of the operation.

Don't use them for type unsigned long long. It may be funny what happens if you use them for type int, byte or float.

GoForSmoke:
Considering that b initializes as 0....

Ah, I see. Sorry. I was trying to get the concept across rather than write literal, compilable code, and simply meant to indicate that b was of type byte, but not to imply that b held any particular value. If that code was executed, b would be zero, or possibly undefined, but in my example, I meant to suggest that b could hold any possible value that a byte could hold, and for the programmer to be prepared for that situation.

joshuabardwell:
If that code was executed, b would be zero, or possibly undefined,

It is better to be sure and have no doubt. Don’t take my word for it, ask your Arduino.

byte i;
byte b;
int  a[ 20 ];
char buf[ 40 ];
float f;


void setup() {
  Serial.begin( 9600 );
  Serial.println( "\n variable initializations\n" );
  Serial.print( "b = ");
  Serial.println( b, DEC );
  Serial.print( "a = { ");
  for ( i = 0; i < 20; i++ )
  {
    Serial.print( a[ i ], DEC );
    if ( i < 19 )
    {
      Serial.print( ", " );
    }
    else
    {
      Serial.println( " }\n" );
    }
  }
  Serial.print( "buf as string is " ); 
  Serial.println( buf );
  Serial.print( "buf as hex bytes = { " ); 
  for ( i = 0; i < 40; i++ )
  {
    if ( buf[ i ] < 0xF )
    {
      Serial.print( "0" );
    }
    Serial.print( buf[ i ], HEX );
    if ( i < 39 )
    {
      Serial.print( ", " );
    }
    else
    {
      Serial.println( " }\n" );
    }
  }
  Serial.print( "f = ");
  Serial.println( f );
  
  while( 1 );
}

void loop() {};

Considering that b initializes as 0....

To be fair, in reply #9, there is no context to make that assumption - 'b' could be an automatic and therefore undefined, though it would, of course, be improper to use it immediately.

There's days when I wonder if I've forgotten more C++ than I know. I remember the term automatic variable but unless I dig or search, it's somewhere out in the fog to me.

GoForSmoke:

joshuabardwell:
If that code was executed, b would be zero, or EDIT: depending on platform, O/S, etc... possibly undefined,

It is better to be sure and have no doubt. Don't take my word for it, ask your Arduino.