Problem in defining a variable as multiplication

I have a simplest code to turn on and off a led. The variable holding time definition is `onTime`, using Arduino Nano.

When it is written as: `onTime=1000*30`, all is good.

When `onTime` is greater than this, `if` loop does not return `true` value when needed ( see code below ).

BUT when writing it implicit as `onTime=60000`, and not `onTime=1000*60` code run OK.

I'm guessing that value of 30*1000 - has to be something with `int` value.

CODE:

``````int enbPin = 10;
bool onState = true;
unsigned long onPeriod = 60*1000; // <----
unsigned long startTime = millis();
void setup() {
// put your setup code hee, to run once:
Serial.begin(9600);
pinMode(enbPin, OUTPUT);
digitalWrite(enbPin, onState);
Serial.println("START");
}

void loop() {
// put your main code here, to run repeatedly:
if (millis() - startTime >= onPeriod ) {
onState = !onState;
startTime = millis();
digitalWrite(enbPin, onState);
Serial.println(onState);
}
}
``````
• your code does not have a variable named `onTime` May 24, 2019 at 0:04

`unsigned long onPeriod = 60ul * 1000;`

`ul` makes 60 to unsigned long and then the calculation has place for result.

without `ul` the constants and the result are `int` and it overflows

• thank you for your quick answer. 1) when using NodeMCU, without `ul` - result was OK, why is that ? 2) to define 1hr should I write `60ul*1000*60` ?
– guyd
May 23, 2019 at 18:28
• 1) The NodeMCU is a 32-bit chip. `int` is 32 bits and can hold a massive amount more (same as a long). 2) Sure. Any one (or all of) the numbers can have `ul` - as long as at least one does. May 23, 2019 at 18:32
• Thank you very much for comprehensive answer
– guyd
May 24, 2019 at 4:44

Juraj already told you how to fix this.

(Edited)

By default, the C/C++ compiler uses the smallest size that can hold the specified value for integer constants, starting with the "native" integer size on the platform it's compiling for. For a 16 bit device like an AVR-based Arduino, an int is 16 bits. A signed 16 bit int can hold a value from -32768 to 32767.

(As pointed out by AnT in his comment, if you declare an integer constant of 60,000, the compiler automatically promotes it to the larger long int type.)

It evaluates expressions assuming int constants are of type int unless their value doesn't fit in an int. If you try to do math with an int and a long int, or store the results of int math into a long, the int gets "promoted" to the larger data type first.

``````unsigned long onPeriod = 60 * 1000;
The compiler first evaluates the right side of the expression, `60 * 1000`, as `(int)60 * (int)1000)`. Since it treats both parts of that expression as 16 bit signed ints, it does the multiplication using 16 bit integer math. The result of the multiplication is 60,000, which is too large to store in a signed int, so the intermediate calculation overflows.
It then tries to store the result to an `unsigned long`. It promotes the now-overflowed value to an unsigned long and stores the (garbled, and thus wrong) result into the unsigned long destination.
• "By default, the C/C++ compiler uses the "native" size for integer constants". This is a bit misleading. For an unsuffixed decimal literal, the compiler will automatically chose the smallest type from `int -> long -> long long` sequence that can accommodate the constant. In this case `int` is chosen just because the constants fit in it. And `int` happens to be a 16 bit signed type on this platform. It is more appropriate to say that the compiler uses "native" size for `int` type, not for integer constants. For example, `2 * 40000` would not overflow, even though `80 * 1000` does. May 24, 2019 at 15:03