wait without delay() in a for-loop... How to do this?

first a bit of the kit. This is for LPD6803 LED pixel strings. Using IDE 1.01, arduino pro mini, 80 pixels, rotary encoder, DS2331 Real Time CLock.

What I am doing with this code:
I send this chunk a few variables to control which LEDs are on and when. (digits, a,b,c,d)
setCircle(); calls a subroutine to advance the position of a lit LED in a circle of 20 leds (the last 20 on the string)

what I am trying to do: eliminate the delay(); statement, as it affects the speed of the setCircle routine (which is already has no delay()'s.

what am I missing? can you manipulate the for()'s variable.
I know about wait without delay, I’m using it in the setCircle() routine, But I don’t get how to manage within a loop, and still do the full loop count (30 in this case)…

it couldn’t be as simple as a millis() based i-- command, could it?

// goes forwards
  for (int j = 0; j < digits; j++)
       {
         c = a + 1;
         d = b - 1; 
  
         for (int i = 0; i < 30; i++)
         {

           strip.setPixelColor((a-i)%60, i, 30-i, 0);
           strip.setPixelColor((b+i)%60, i, 30-i, 0);

           delay((i*2));
           strip.setPixelColor((c-i)%60, 0, 0, 0);
           strip.setPixelColor((d+i)%60, 0, 0, 0);
           strip.setPixelColor(digits*5%60,31,0,0);
          
          
          setCircle();
          
           strip.show();
         }

Would something like this work?

// goes forwards
  for (int j = 0; j < digits; j++)
       {
         c = a + 1;
         d = b - 1; 

         unsigned long startTime = millis();
  
         for (int i = 0; i < 30; i++)
         {

           strip.setPixelColor((a-i)%60, i, 30-i, 0);
           strip.setPixelColor((b+i)%60, i, 30-i, 0);

           while (millis()-startTime <= (i*2))
              setCircle();

           strip.setPixelColor((c-i)%60, 0, 0, 0);
           strip.setPixelColor((d+i)%60, 0, 0, 0);
           strip.setPixelColor(digits*5%60,31,0,0);
          
           strip.show();
         }

"wait without delay()"

You want the program to stop what its doing for a certain amount of time? That's what delay() is for...

I see you have a couple of nested FOR loops that are working through a sequence of actions in 'slow time' (with delays between each action, and something else going on within setCircle() that I guess you want to call frequently.

The way I would do that is make your loop counters global variables and use the 'blink without delay' approach to determine when it was time to carry out the next action. Instead of using a FOR loop, you would increment the global variable and use a range check to detect whether you have completed each sequence.

When you change from the synchronous approach based on delay() to the asynchronous approach based on comparing millis() values, you need to fundamentally change the architecture of your sketch - it's not just a matter of replacing delay() with something else.

Marco - nice. now why didn't I think of that? thanks for the kick in the butt :~

Peter - I hear you about the fundamental re-structuring that kicking the delay() habit causes. setCircle() was orignally delay() based and kinda clunky. I "converted" it to millis() but it still ran like ass. Crossroads (mad props) enlightened me that I could use millis() and a few arrays, so I rebuilt it much leaner and it runs really smooth now, until these other delays() pop up. I have a bunch of variations on this same chunk of code, so I think the idea of a global time variable that ALL my functions run on could work, but I am not sure if I understand how to use such a method. I definitely can and probably will re-build this routine and the others like it with a local millis()-lastMillis approach.

Unless you feel like a little bit of coaching ;-) I'm a quick study.

james - like I said, using delay() also delayed setCircle(), and i was looking for an elegant way around that but thanks for sharing anyway.

curious: can one manipulate the counter variable inside a for() loop? would it be considered "bad form" to do that? I can see how it could cause problems with endless loops and such...

GoolGaul: curious: can one manipulate the counter variable inside a for() loop? would it be considered "bad form" to do that?

I think you can do it, but bad form. Research "break".

http://www.gammon.com.au/blink

curious: can one manipulate the counter variable inside a for() loop?

Yes

would it be considered "bad form" to do that?

Yes it is bad form, mainly because the (human) reader expects to see all the conditions in the for statement. If you just want to exit the loop use break rather than changing the index.

If you want to manipulate the counter, use a while loop. In this case the reader is expecting that the condition will be worked out somewhere in the loop and is more alert to that.

On the issue of running things at certain intervals, look at the MultiBlink example in the Playground. You can change this relatively easily to call functions rather than just blink LEDs, using the same table-based principle. It needs abasic understanding of calling functions indirectly and I can help if you want to go that way.

Yes it is bad form, mainly because the (human) reader expects to see all the conditions in the for statement.

I disagree to some extent. If you are deleting objects from a linked list, for instance, and you know how many links there are in a list, you often have to back up after removing a node, as well as changing the end condition.

What I'd recommend is that you clearly state, using comments, that the loop variables will be modified inside the loop, and why.

Manipulating the loop variable just to get the loop to end IS bad form. Just break out of the loop.

I’m not looking to exit the loop early, actually I am looking to stay in the loop longer.

this is a simplified example.

for(i=0;i<30;i++)
  {                    
     if (millis() - lastmillis < 25)    //  testing if the proper time has NOT passed
        {   
             i--;                                  // subtracting from the index to remian in loop longer than 30
             otherRoutine();               // the other routine that needs to be regularly called
         }    
      else                                        // if the time HAS passed
     doSomething                          // do the occasional thing
     otherRoutine();                      // the other routine that needs to be regularly called
     lastmillis=millis();
   }

now that I look at it, it seems kinda odd…
with proper commenting, it shouldn’t be a problem…

Thanks all!

This is much more readable:

for(i=0;i<30;)
  {                    
     if (millis() - lastmillis < 25)    //  testing if the proper time has NOT passed
        {   
             otherRoutine();               // the other routine that needs to be regularly called
         }    
     else  {                                      // if the time HAS passed
       doSomething                          // do the occasional thing
       otherRoutine();                      // the other routine that needs to be regularly called
       lastmillis=millis();
       i++;
    }
   }

Or you could swap out the for loop for a while loop

for(i=0;i<30;i++)
  {                    
     if (millis() - lastmillis < 25)    //  testing if the proper time has NOT passed
        {   
             i--;                                  // subtracting from the index to remian in loop longer than 30

I’m sorry, but with all due respect, this looks silly to me. Rework it so that you add to i under some condition, use a while loop, and when i gets to 30, leave the loop.

I'm sorry, but with all due respect, this looks silly to me.

I agree.

Rework it so that you add to i under some condition, use a while loop, and when i gets to 30, leave the loop.

A for loop is meant to iterate a fixed number of times. There are circumstances that can change that fixed number of times. But, if the number of times to do something is unknown, a for loop is not the right construct to use.

A while loop is. But, I don't see anything in the posted code that makes 30 anything other than some magic number. I think the whole logic behind that loop needs to be rethought.

PaulS: A for loop is meant to iterate a fixed number of times.

You may think that when a loop needs to be executed a fixed number of times, a FOR loop is the preferred way to achieve that. You may even have a preference for using a different construct when the number of iterations is not known in advance, in which case that may be the only time that [u]you[/u] would use a FOR loop. But I absolutely do not agree that a FOR loop is 'meant' to iterate a fixed number of times. ('Meant' by whom?)

You may think that when a loop needs to be executed a fixed number of times, a FOR loop is the preferred way to achieve that.

I do.

You may even have a preference for using a different construct when the number of iterations is not known in advance, in which case that may be the only time that you would use a FOR loop.

True.

But I absolutely do not agree that a FOR loop is 'meant' to iterate a fixed number of times. ('Meant' by whom?)

Look at the documentation on the Arduino page for for. The examples on that page, and on a lot of other sites, demonstrate how to use a for loop to iterate a fixed number of times.

I was, of course, only expressing my opinion, as you are.

PaulS: Look at the documentation on the Arduino page for for. The examples on that page, and on a lot of other sites, demonstrate how to use a for loop to iterate a fixed number of times.

I was, of course, only expressing my opinion, as you are.

It's a very common use that shows how to use all the features of the FOR loop and no surprise that it's used so often as an example. All I'm objecting to is your assertion that this is how it's meant to be used and that other uses are somehow improper. There are many other ways to use the FOR loop which are every bit as suitable and appropriate as the examples you've cited.

Some other languages do have constructs which are designed to iterate through the elements in a set or the contents of an array or do something a specified number of times, but in C/C++ the FOR loop is more general than that.

All I'm objecting to is your assertion that this is how it's meant to be used and that other uses are somehow improper.

I suppose that I could have said that for loops are usually used to iterate a fixed number of times, while while loops are generally used to iterate an unknown number of times. But, I was just stating my opinion about what construct to use when. I'm sorry that it bothers you.

I'm not bothered by your opinion. Largely, it's consistent with mine. What I was bothered by was a seemingly arbitrary personal preference (about when to use FOR loops) being presented as a matter of right and wrong, in a thread where an inexperienced programmer is asking for advice about how to use the FOR loop. That's all.

i think its very human to see programming as an extension to math in math we've been told to use clear formula's, and believe the shortest formula's are the right ones. Computers for example can deal with much complexer math and (try eureka solver) dont care much about it, it us who care. Nature doenst seam to care much either, nature doesnt interprent how it should be, its just too complex quanta for us. Some programmers are more in to nature while others are more into math ;)

its a taste thing.

I'm largely in agreement with PaulS here. For "do something x times" sorts of situations, a for loop is natural.

A nice counterpoint though is when using the STL, and iterators, for example:

  for (it = m_OutstandingLines.begin ();   // initial value
       it != m_OutstandingLines.end ();    // check for end of loop  
       it++)   // move to next item
    {
     // do something with the iterator
    }

Conceptually it is similar. You want to initialize something. You want to check if the loop end condition has arrived. You want to increment to the next item.

As discussed, you can manually adjust the iterator value in a for loop should you choose to, but when I see a for loop, I don't expect it. Such behaviour causes a bit of a double take: "What on earth is happening here?". I'll take PeterH's point that it's not banned by some higher power (Struggling with precise phrasing here), but to quote Jeff Goldblum's character in Jurrassic park: "Just because you could doesn't mean that you should".