0

I want to use loop() iterations counter to execute some tasks periodically or tasks like debouncing. My other sketch is running every loop() at least 20 ms, and if i am using 5 ms time to wait to debounce a button, it will still be at least 20 ms waiting, also cpu will have to compare two not zero values, which is a bit slower. I think it is more difficult for cpu than just incrementing and decrementing one variable and comparing it to 0. So i came up with pattern like that:

boolean onOff=1; // arduino led state. My task here is LED blinking.
byte loopCounter=2; // number of iterations made by loop(). Set as little variable as possible to save ram and cpu time. 
//Code will be executed every "loopCounter" iteration of loop(). 
void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
      if (--loopCounter == 0) { //comparing with 0 should be a bit faster and easier for Arduino to process. Correct me if i am wrong. 
        loopCounter=2; // That digit sets how often your code will be executed. Every 2(3,4... set your own value) iterations of loop().
        digitalWrite(13, onOff= !onOff); // the task itself. 
        }
}

It may be more convenient in some ways than millis() and micros() patterns. Also i do want want to use hardware timers for timing. It may be convenient in cases, when you don't care when exactly task will be done, you just want it to be done ASAP (as soon as possible), but not during that particular iteration of loop(). Basicly you can use it as a timer if you know how it takes one iteration to be done. So, if your sketch runs 1 iteration of loop() for 1 ms, and you need some action to be done every 1 sec, 1ms*1000 == 1 sec. So you need it to be done every 1000 iterations.

  1. So, is that really can save some ram and cpu time?
  2. Is comparing with zero is faster for arduino than comparing with not zero?
  3. Are millis() and micros() timing patterns using more operations (setting value to variable, computing the difference between 2 values and than comparing it to a period you have set) instead of decrementing and comparing to zero with my pattern?
  4. Any side-effects of using my pattern? I can only think of very unaccurate timing and delays more than you think if your sketch done smth more than usual, because of button push for example or some sensor changed value.

    Thank you!

6
  • Your use of digitalWrite will be the slow thing there, not comparing to zero, or comparing two numbers. Try looking up the digitalWriteFast library.
    – Nick Gammon
    Commented Aug 23, 2016 at 3:32
  • 3
    To put it another way, you are optimizing the wrong thing. :)
    – Nick Gammon
    Commented Aug 23, 2016 at 3:33
  • I know about digitalWrite, thank you. But readability is more important for stackoverflow i guess) Commented Aug 23, 2016 at 8:32
  • millis() is one of the fastest function of the Arduino core. It just returns a copy of a global variable (timer0_millis) which is updated by a timer interrupt. The copy is performed with interrupts disabled in order to avoid a race condition. See the implementation. Commented Aug 23, 2016 at 9:36
  • I know about digitalWrite, thank you. But readability is more important - what's unreadable about: digitalWriteFast (13, onOff= !onOff);?
    – Nick Gammon
    Commented Aug 23, 2016 at 21:17

1 Answer 1

3

Personally I wouldn't be putting too much effort into optimizing away your timers. millis() is pretty fast - the work needed to calculate the result is done in the background anyway (by interrupts). I tried some test code:

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  unsigned long start, finish;

  start = micros ();
  for (byte i = 0; i < 100; i++)
    digitalWrite (13, HIGH);
  finish = micros ();

  Serial.print ("Time taken to do digitalWrites: ");
  Serial.println (finish - start);
  Serial.flush ();

  start = micros ();
  volatile unsigned long now;
  for (byte i = 0; i < 100; i++)
    now = millis ();
  finish = micros ();

  Serial.print ("Time taken to do millis: ");
  Serial.println (finish - start);
  Serial.flush ();

  }  // end of setup

void loop ()
  {

  }  // end of loop

Results:

Time taken to do digitalWrites: 520
Time taken to do millis: 188

You can see that the digitalWrite() (which you weren't worried about) takes 5.2 µs, whereas calling millis() (which you were worried about) takes 1.88 µs.


Are millis() and micros() timing patterns using more operations (setting value to variable, computing the difference between 2 values and than comparing it to a period you have set) instead of decrementing and comparing to zero with my pattern?

Yes, just adding one to a variable and then comparing will be faster. Whether it is worth the effort is debatable.

5
  • If 'millis()' is using interrupts, it's benchmarked time will be a bit more, at lest by the time needed to increment variable, starting and stopping an interrupt also takes some time i guess. So thank you very much for telling about interrupts:) Commented Aug 23, 2016 at 8:46
  • Or did i miss smth about interrupts? One more thing here. I have heard from an experienced programmer, that is is nice to count from 'n' to zero to optimise 'if()', especially in larger loops. Compilers usually do it themselves, but you can never be sure about that. So, it will be done 'for (byte i = 100; i >= 100; i--)' instead of 'for (byte i = 0; i < 100; i++)'. by arduino compiler? Commented Aug 23, 2016 at 8:57
  • I assume you mean 'for (byte i = 100; i >= 0; i--)'. Here's the flaw. In trying to outguess the compiler and maybe save one machine cycle, you've introduced a bug. The byte type is unsigned, and thus i will always be >= 0. Thus the loop will never terminate.
    – Nick Gammon
    Commented Aug 23, 2016 at 21:16
  • Well, i can see my mistake. And that is the reason i want to know if compiler can do hard work for me. I need to know should i think about it at all or not. I would find out about my mistake pretty soon in real code i guess, but still it is a loss of time... Commented Aug 24, 2016 at 9:08
  • Well, compilers are pretty good these days. You can help them out by choosing good data types (for example, byte as you did, rather than unsigned long when you only have to count to 10). I wouldn't be sweating over whether it is faster to count up to 10, or down to zero.
    – Nick Gammon
    Commented Aug 24, 2016 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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