EDIT: also, (!dOn && n1000) >= 500 doesn't make a lot of sense because it is always false ( (!dOn && n1000) evaluates to either 0 or 1, which is always strictly smaller than 500)
Sorry. Of course >= is evaluated before &&. I just
get confused when retrolefty suggested parenthesis and
I just thought the original code was ok without (as it was)
and did not notice the false suggest.
00068 typedef struct {
00069 int quot; /**< The Quotient. */
00070 int rem; /**< The Remainder. */
00071 } div_t;
00072
00073 /** Result type for function ldiv(). */
00074 typedef struct {
00075 long quot; /**< The Quotient. */
00076 long rem; /**< The Remainder. */
00077 } ldiv_t;
...
00153 /**
00154 The ldiv() function computes the value \c num/denom and returns
00155 the quotient and remainder in a structure named \c ldiv_t that
00156 contains two long integer members named \c quot and \c rem.
00157 */
00158 extern ldiv_t ldiv(long __num, long __denom) __asm__("__divmodsi4") __ATTR_CONST__;
Assuming that the compiler uses ldiv() for both % and / , it brings us to the same assembly call ; that "explains" why both % and / have same behavior. Still strange ...
Adding shortest delay seems to make it more stable
Yes it helps, because then you minimize the change to hit reset during modulo (%). But still it is possible to hang if you are patient enough pressing the reset button. So this is not a way to replace this, one only hides the real problem.
... what does micros() do low level as that is also a constant factor in the code?
it gives the microseconds from the last restart. And notice that if one uncomments the two lines:
n1000 = micros();
while ( n1000 > 1000000L) n1000 -= 1000000L; // This works
and comments the modulo line
// n1000 = micros() % 1000000L; // This hangs Arduino while pressing reset
then the code works just perfect and does the same thing. So the % is the only one (what I can see) that has effect. And as in earlier posts also division (/) has the same (not working) effect.
When I press the reset when the LED is on the strange behavior appears.
When I press the reset when the LED is off it acts normal.
I think I get the behavior in both cases. You can changes the 500000L
to something longer to get more time in each case. F.ex to 2500000L.
Then you must also change the n1000 %= 5000000L; to get 5 sec round trip.
But I do not see reason why it behaves differently in different state.
ldiv_t n1000;
unsigned long m = 0;
void setup() {
}
void loop() {
n1000 = ldiv(m++,1000000L); // This hangs Arduino while pressing reset
}
You code may not hang because if nothing is changing, the compiler may optimize something away. The same was also problem for "my minimal code with modulo" when nothing was changing.
void loop() {
n1000 = ldiv(m++,1000000L); // This hangs Arduino while pressing reset
}
By "hang" you mean that it goes into some sort of bootloader loop where you get the initial flashes, repeating approximately every second, but the sketch itself never seems to start?
I can get this to happen with an m168 containing optiboot, using 0022 from a Mac. Not every time, though.
This is really strange. It's not really hung, or it wouldn't be running the bootloader enough to flash the LEDs. Or to recover on a new upload. The ldiv function really doesn't do anything suspicious that I can see...
unsigned long n1000 = 0;
void setup() {
}
void loop() {
n1000++;
n1000 %= 1000; // This hangs Arduino while pressing reset
}
This is a simpler sketch, based on the code actually produced. A signed divide does sign correction and calls the unsigned divide, and the use of ldiv_t results in some substantial structure-passing code...
ah hah! This had all the signs of a watchdog problem, except that those are supposed to be all fixed on Uno. And looking at the code, it does look like they should indeed be fixed.
Except...
The C compiler uses register 1 (R1) as a "known zero" in most places. Functions that use it for something else are supposed to save and restore it, so any particular C function, like main(), knows it can assume that R1 contains a zero. R1 is initialized in the startup code that happens before main() happens (which is before setup() or loop() as well.)
The optiboot bootloader suppresses the normal startup code. R1 does not get set to zero.
The first thing done in the bootloader is to reset the watchdog timer "MCUSR = 0;", which compiles to "out 0x34, R1" - it assumes that R1 contains a zero!
RESET does not set register contents to zero.
If a reset occurs while R1 contains certain values, (bit 1 set), the bootloader will not restart the sketch.
The divide library function uses R1 as a loop counter.