Go Down

Topic: Not using delay () in a 'for' loop (Read 544 times) previous topic - next topic

How_do_I_know

Hi

My first post here - so please be gentle with this noob:) After 6 months of gentle tinkering and lurking I have to admit I need to ask someone!

I am trying to get rid of delay() from within a 'for' loop, for all the good reasons discussed elsewhere.

I am running 8 LEDS with a 595 shift register (and need to read 8 potentiometers at the same time) and have the following 'for' loop within the sketch taken from the ShiftOut tutorial (which runs fine):

Code: [Select]
void loop() {
  for (int thisLed = 0; thisLed < 8; thisLed++) {
    registerWrite(thisLed, HIGH);
    delay(250);
    if (thisLed > 0) {
      registerWrite(thisLed - 1, LOW);
    }
    else {
      registerWrite(8, LOW);
    }
    delay(250);
  }
}


I have managed to get rid of the first delay() by doing this:

Code: [Select]
void loop() {
    unsigned long currentMillis = millis();
    previousMillis = currentMillis;
    for (int thisLed = 0; thisLed < 8; thisLed++) {
    registerWrite(thisLed, HIGH);
    if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    if (thisLed > 0) {
    registerWrite(thisLed - 1, LOW);
    }
    else {
    registerWrite(8, LOW);
          }
    }
    delay(250);
}
}


which works fine - having tried numerous arrangements which did not, but I cannot see a way to get rid of the second delay(). Is it possible to get rid of them both this way? Is there a way to use

Code: [Select]
if(currentMillis - previousMillis > interval)

to make the board do a 'nothing' after 250ms have passed and it will then re-iterate around the loop? Will it take another nested loop?

Thanks very much for your help.

daniel
(clinician, not coder - previous experience a few lines on a DOS .bat file to run DOOM on a work PC!)

PaulS

Quote
I am trying to get rid of delay() from within a 'for' loop, for all the good reasons discussed elsewhere.

What else is the Arduino supposed to be doing while this code is running? Where are you reading from the potentiometers?

If you are to get rid of the delays, you need to implement a state machine. Replacing delay() with your own do-nothing-for-a-specified-period-of-time() function is not useful.

So, at any given time, you should be in one state (3 LEDs lit, for example), and waiting for the appropriate time to transition to another state (4 LEDs lit, for example). The millis() function and stored times are used to determine if it is time to transition to another state.

The tricky part (not hard, just requires some thought) is knowing what state to transition to, and what action(s) to perform during the transition to that state or the transition away from the previous state.

AWOL

In a nutshell, you need to get rid of the "for" loop, and implement the iteration that it performs explicitly in the state machine PaulS described.
Example to follow.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

AWOL

(This is by no means complete, but should give you an idea)
Code: [Select]

void setup ()
{
  state = LED_ON;  // need to define an enum with values like LED_ON, LED_OFF, END_PAUSE..
  thisLed = 0;    /// now a global.
  interval = ledInterval;
}

void loop()
{
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      switch (state) {
        case LED_ON :       
          registerWrite(thisLed, HIGH);
          state = LED_OFF;
        break;
        case LED_OFF :       
          registerWrite(thisLed, LOW);
          thisLed++;
          if (thisLed >= 8) {
            thisLed = 0;
            state = END_PAUSE;
            interval = endInterval;
          } else {
            state = LED_ON;
          } 
        break;
        case END_PAUSE:
        /// whatever.
        break;
      }
      // stuff to do when not changing LED states.
}
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

How_do_I_know

Thanks for your rapid replies guys.

My project is that old chestnut the step sequencer. I had a nice sketch running for only 5 steps, but to get more I started working with the shift register. My first attempt failed because of the delays - the one LED on for each step was out of synch with the MIDI signal being generated by the potentiometer reading for the step (which I kept in an array and stepped through, but again with a delay() ). Hence I started again, with the LEDs first, but trying to do away with the delay (). No other code yet (it might take a few months!).

Sorry for the rather basic descriptions, but I am very much a noob at programming.

AWOL- thanks very much for the code - I will have to go aware and stare at it for a while!

daniel

AWOL

#5
Jul 01, 2011, 12:53 pm Last Edit: Jul 01, 2011, 12:56 pm by AWOL Reason: 1
The thing to remember is that the only actions that take place are to set or reset a LED, and to pause at the end of a sequence.
You only perform an action and proceed to the next state at a timeout.
The only reason you had a "for" loop in your original code was to allow you to step from LED to LED.
Now, the "for" loop is deconstructed into its component parts and spread through the sketch.
The four components (initialisation, condition, end action and loop body)are still there, just put next to where they acually need to be actioned.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Go Up