pfeerick / elapsedMillis

Arduino 'port' of the elapsedMillis library
MIT License
84 stars 26 forks source link

value of elapsedMillis object not an unsigned long? #14

Open paynterf opened 4 years ago

paynterf commented 4 years ago

I am having problems printing elapsedMillis object values to the serial port in Arduino avr code, and it appears that this is caused by the object not returning an unsigned long value. The following is a small program to illustrate the problem:

/*
    Name:       PrintEx_ElapsedMillis.ino
    Created:    8/14/2020 9:47:31 AM
    Author:     FRANKNEWXPS15\Frank
*/

#include <elapsedMillis.h>
#include <print.h> //allows printf-style printout syntax

elapsedMillis sinceLastCheckMsec = 0;

void setup()
{
  Serial.begin(115200);
  sinceLastCheckMsec = 0;

  Serial.printf("small program to demonstrate problems with modified Print.h\n");
  Serial.printf("Printing out value of an 'elapsedMillis' object sinceLastCheckMsec, with & without chaining\n");
  Serial.printf("Printing out return value from millis(), with & without chaining\n");
  Serial.println();

  Serial.printf("sinceLastCheckMsec no chaining, no cast: %lu\n", sinceLastCheckMsec);

  Serial.printf("sinceLastCheckMsec no chaining, cast to (unsigned long): %lu\n", (unsigned long)sinceLastCheckMsec);

  Serial.printf("chaining: millis = %lu\tsinceLastCheckMsec (cast to unsigned long): %lu\n", millis(), (unsigned long)sinceLastCheckMsec);

  Serial.printf("chaining: millis: %lu\tsinceLastCheckMsec (no cast): %lu\tsinceLastCheckMsec (cast to unsigned long): %lu\tsinceLastCheckMsec (cast to uint32_t): %lu\n",
    millis(), sinceLastCheckMsec, (unsigned long)sinceLastCheckMsec, (uint32_t)sinceLastCheckMsec);

  Serial.printf("chaining: millis: %lu\tsinceLastCheckMsec (cast to unsigned long): %lu\tsinceLastCheckMsec (no cast): %lu\tsinceLastCheckMsec (cast to uint32_t): %lu\n",
    millis(), (unsigned long)sinceLastCheckMsec, sinceLastCheckMsec, (uint32_t)sinceLastCheckMsec);

  Serial.printf("ms: %lu\tChk: %lu\tChk:: %lu\tChk: %lu\n",
    millis(), (unsigned long)sinceLastCheckMsec, sinceLastCheckMsec, (uint32_t)sinceLastCheckMsec);

  Serial.printf("chaining: millis: %lu\tsinceLastCheckMsec (cast to unsigned long): %lu\tmillis: %lu\tsinceLastCheckMsec (cast to unsigned long): %lu\n",
    millis(), (unsigned long)sinceLastCheckMsec, millis(), (unsigned long)sinceLastCheckMsec);
}

void loop()
{
}

When this is run on an Arduino Mega, I get the following output:

Opening port
Port open
small program to demonstrate problems with modified Print.h
Printing out value of an 'elapsedMillis' object sinceLastCheckMsec, with & without chaining
Printing out return value from millis(), with & without chaining

sinceLastCheckMsec no chaining, no cast: 92217847
sinceLastCheckMsec no chaining, cast to (unsigned long): 17
chaining: millis = 22   sinceLastCheckMsec (cast to unsigned long): 22
chaining: millis: 28    sinceLastCheckMsec (no cast): 1843703   sinceLastCheckMsec (cast to unsigned long): 1835008 sinceLastCheckMsec (cast to uint32_t): 0
chaining: millis: 41    sinceLastCheckMsec (cast to unsigned long): 41  sinceLastCheckMsec (no cast): 2695671   sinceLastCheckMsec (cast to uint32_t): 92209152
ms: 55  Chk: 55 Chk:: 3613175   Chk: 0
chaining: millis: 58    sinceLastCheckMsec (cast to unsigned long): 58  millis: 58  sinceLastCheckMsec (cast to unsigned long): 58

I looked at the ellapsedMillis code, but I can't for the life of me see why a reference to an elapsedMillis object doesnt return an 'unsigned long' object, but I'm pretty sure that's what is happening. I use elapsedMillis objects a lot, and it would be nice if I didn't have to remember to always explicitely cast references to 'unsigned long'.

TIA

Frank

pfeerick commented 3 years ago

Hi Frank. Did you get anywhere with this issue? I just had a look at the code also, and nothing stands out. But I can't say I understand the ins and outs of class logic and chaining. All I can think of atm is that it is because sinceLastCheckMsec will return as a elapsedMillis object, not as an unsigned long, hence the need to cast.

In order to be able to have any hope of reproducing the issue, what library are you using?

#include <print.h> //allows printf-style printout syntax
rw-schumann commented 1 year ago

Anybody have any additional thoughts on this? I just spent two days chasing a bug which in the end was because I cast the result to (uint32_t) for a comparison and of course that had highly unpredictable results. An exceptionally useful code set otherwise!

pfeerick commented 1 month ago

Still none the wiser. It looks like the OP also tried to get some help on the Arduino forum, and they suggested it was either user error (i.e. giving the wrong format specifier to printf) or some obscure behaviour in the bowels of Arduino and Print libraries... https://forum.arduino.cc/t/printex-serial-printf-and-elapsedmillis-printing/670092/28

Another added complicated is that unsigned long is typically equialent to uint32_t... but is not an absolute guarantee... I'm tempted to try switching this to uint32_t instead of unsigning long, and seeing what happens. First step will be to setup https://www.arduino.cc/reference/en/libraries/printex/ and try to reproduce the results, and then will see what happens...