0

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);
  }
}
  • 1
    your code does not have a variable named onTime – jsotola May 24 at 0:04
4

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

  • 1
    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 ? – Guy . D May 23 at 18:28
  • 2
    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. – Majenko May 23 at 18:32
  • Thank you very much for comprehensive answer – Guy . D May 24 at 4:44
1

Juraj already told you how to fix this.

Some more info on why:

(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.

In your expression:

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 either expressing either or both values as an unsigned long constant, or casting one or both of them to an unsigned long type, the compiler then promotes both values to unsigned longs before doing the math on them, so the result doesn't overflow before being assigned to the destination variable.

  • "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. – AnT May 24 at 15:03
  • @AnT. Good point. I struggled a bit with how to word that. Your wording is more accurate. – Duncan C May 24 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.