How do i write my code without the delay function?

Hey, I´m a newbie and i want to create a little christmas decoration. I have a code that does everything it is supposed to, but i want to add more stuff down the line and therefore i want to remove the delays.

Working code:

int i = 0;
int snabb = 250;
int lagom = 500;
int seg = 1000;

void setup() {
  // put your setup code here, to run once:
for (int i=0; i <= 9; i++){
  pinMode(i, OUTPUT);
}
}
void loop() {
  // put your main code here, to run repeatedly:
  for (i=0; i<=9; i++){
   digitalWrite(i, HIGH); 
  }
   
  delay(lagom);

  for(i=0; i<=9; i++) {
    digitalWrite(i, LOW);
  }

delay(snabb);

  for (i=0; i<=9; i++){
   digitalWrite(i, HIGH); 
  }
   
  delay(lagom);

  for(i=0; i<=9; i++) {
    digitalWrite(i, LOW);
  }

delay(snabb);

  for (i=0; i<=9; i++){
   digitalWrite(i, HIGH); 
  }
   
  delay(lagom);

  for(i=0; i<=9; i++) {
    digitalWrite(i, LOW);
  }

delay(seg);

// PÅ, AV, PÅ, AV, PÅ AV. Slutar med seg delay.

for(i=0; i<=9; i++) {
 digitalWrite(i, HIGH);
 delay(snabb);
 digitalWrite(i, LOW);
  }
delay(seg);

// Trappa upp med blink. Slutar med seg delay.

for(i=0; i<=9; i+=3) {
  digitalWrite(i, HIGH);
}

delay(lagom);

for(i=0; i<=9; i+=3) {
  digitalWrite(i, LOW);
  
}

for(i=1; i<=9; i+=3) {
  digitalWrite(i, HIGH);
}

delay(lagom);

for(i=1; i<=9; i+=3) {
  digitalWrite(i, LOW);
  
}

for(i=2; i<=9; i+=3) {
  digitalWrite(i, HIGH);
}

delay(lagom);

for(i=2; i<=9; i+=3) {
  digitalWrite(i, LOW);
  
}
delay(seg);
//Tänd och släck alla röda, sedan grön och gul. Slutar med seg delay.

for(i=0; i<=9; i++){
digitalWrite(i, HIGH);
delay(snabb);
}

delay(snabb);

for(i=9; i>=0; i--){
  digitalWrite(i, LOW);
  delay(snabb);
}

delay(seg);
}

My poor attempt to use a millis timer:

int i = 0;
const long snabb = 250;
const long lagom = 500;
const long seg = 1000;
unsigned long forraMillisEtt = 0;
unsigned long forraMillisTva = 0;


void setup() {

for (i=0; i <= 9; i++){
  pinMode(i, OUTPUT);
}
}




void loop() {

unsigned long tid = millis();
if(tid - forraMillisEtt >= 0){
  forraMillisEtt = tid;
}

  for (i=0; i<=9; i++){
   digitalWrite(i, HIGH); 
  }


   if(tid - forraMillisEtt >= lagom) {
    forraMillisEtt = tid;
      for(i=0; i<=9; i++) {
    digitalWrite(i, LOW);
   }
  }

if(tid - forraMillisEtt >= snabb) {
  forraMillisEtt = tid;
    for (i=0; i<=9; i++){
   digitalWrite(i, HIGH); 
  }
 }

   if(tid - forraMillisEtt >= lagom) {
    forraMillisEtt = tid;
      for(i=0; i<=9; i++) {
    digitalWrite(i, LOW);
  }
   }
if(tid - forraMillisEtt >= snabb) {
  forraMillisEtt = tid;
    for (i=0; i<=9; i++){
   digitalWrite(i, HIGH); 
  }
 }

   if(tid - forraMillisEtt >= lagom) {
    forraMillisEtt = tid;
      for(i=0; i<=9; i++) {
    digitalWrite(i, LOW);
  }
   }
   // PÅ, AV, PÅ, AV, PÅ AV.

   
if(tid-forraMillisEtt >= seg) {
  forraMillisEtt >= tid;
for(i=0; i<=9; i++) {
  digitalWrite(i, HIGH);
if(tid-forraMillisEtt >= snabb) {
  forraMillisEtt = tid;
  digitalWrite(i, LOW);
}
}
}
// Trappa upp med blink.


if(tid-forraMillisEtt >= seg) {
  forraMillisEtt = tid;
  for(i=0; i<=9; i+=3) {
  digitalWrite(i, HIGH);
}
}

if(tid-forraMillisEtt >= lagom) {
  forraMillisEtt = tid;
  for(i=0; i<=9; i+=3) {
  digitalWrite(i, LOW);
  
}
  for(i=1; i<=9; i+=3) {
  digitalWrite(i, HIGH);
}
}

if(tid-forraMillisEtt >= lagom) {
    forraMillisEtt = tid;
  for(i=1; i<=9; i+=3) {
  digitalWrite(i, LOW);
  
}

  for(i=2; i<=9; i+=3) {
  digitalWrite(i, HIGH);
}  
}

if(tid-forraMillisEtt >= lagom) {
  forraMillisEtt = tid;  
  for(i=2; i<=9; i+=3) {
  digitalWrite(i, LOW);
  
}
}
//Tänd och släck alla röda, sedan grön och gul.

if(tid-forraMillisEtt >= seg) {
  forraMillisEtt = tid;
  for(i=0; i<=9; i++) {
    digitalWrite(i, HIGH);
    if(tid - forraMillisEtt >= snabb) {
      forraMillisEtt = tid;
    }
  }
}

if(tid-forraMillisEtt >= snabb) {
  for(i=9; i>=0; i--){
  digitalWrite(i, LOW);
  if(tid-forraMillisEtt >= snabb) {
    forraMillisEtt = tid;
  }
}
}
//Trappa upp (tänd), trappa ner (släck).
if(tid-forraMillisEtt >=seg) {
forraMillisEtt = tid;
}
   }

If the Swedish variable names and/or the comments mess you up, just ask and I´ll translate.

I really have no clue how to use millis timer and my only experience with it is from reading the blinkwithoutdelay page.

If someone wonders, I want to add a piezo buzzer later on that can play some kind of christmas song.

Sorry if my english is poor, I´m trying.
Thanks in advance!

3lvisp: I really have no clue how to use millis timer and my only experience with it is from reading the blinkwithoutdelay page.

Oh but you do. You know exactly how to do it. I'd say you've probably been doing it most of your life. It's just math, the code behind it isn't esoteric. If it was 4:00 and I told you to meet me in 10 minutes and now it is 4:09 is it time to be there? What if it was 4:11? How did you figure that out? That's all you're doing with BWoD style timing.

if(tid - forraMillisEtt >= 0){
  forraMillisEtt = tid;
}

So if the new time is more than 0ms past the last time you reset the last time to the current time. Why? The last time should track the time it was the last time you did something. Put the line that sets the last time right next to the line that does the thing you’re timing.

If you have several things that you want to time, then you’ll need to have several “last time I did it” variables.

if(tid - forraMillisEtt >= 0){

forraMillisEtt = tid;
}

This ALWAYS sets forraMillisEtt to the current value of millis(). I don’t think you need to have this part at all.

Switching from the linear programming method (on, delay, off, delay, on…) to the millis-based method, you have to consider that the loop runs thousands of times per second. On just a few of those, it will find that it’s time to change the outputs. From off to on or on to off. That means that it must remember where it is up to in the cycle - are the lights on and are they due to go off for the short or long period next?

It looks like you have a couple of different patterns there? Or maybe you just have one long pattern? If it’s just one long pattern then it’s easy. If it’s different patterns and there’s some other rule for when to change patterns, then it gets a little more complex.

I would first seperate the pin numbers from the light numbers. You are using pins 0 and 1 which are the Serial pins on most Arduinos. If you want to add serial in the future, this will make it difficult. If you want to re-wire the 1st light onto the A0 pin because the wires fit better in the box, you have a real problem.

int lights[] = {A0, 3, 4, 5, 6, 7, 8, 9, 10};  //A0 is just a guess, you probably don't want that

I would next try to seperate the code that turns the lights on and off from the definition of the pattern. It should be easy to just change a few delay times or light activations without having to read through all the if() statements to find it.

#define ON HIGH
#define OFF LOW
unsigned int pattern[][] = {
    {0   , OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF},
    {250  ,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON},    
    {500 , OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF},
    {250  ,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON},    
    {1000, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF},
    {250  ,  ON, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF}
    //keep going - put more here
}

This uses integers, which is a limitation - you can’t have a delay longer than 65536 milliseconds, but you can put the same thing twice so it looks like a longer delay. It also wastes a lot of space, using integers for simple ON/OFF information. Unless your pattern is very long, you won’t run out of memory.

Then your main loop is just a small piece of code which looks at the first number in the pattern to decide if it’s time to move on to the next row and walks down that row to turn the appropriate lights on and off.

int lights[] = {A0, 3, 4, 5, 6, 7, 8, 9, 10}; 
#define ON HIGH
#define OFF LOW
unsigned int pattern[][11] = {
    {0   , OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF},
    {250  ,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON},    
    {500 , OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF},
    {250  ,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON,  ON},    
    {1000, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF},
    {250  ,  ON, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF}
    //keep going - put more here
};

//we're going to need to know the number of elements in the above arrays
//many times throughout the code, so let's make a simple macro for that
#define length(a) ( sizeof(a) / sizeof(a[0]) )

void setup() {
  for(int i=0; i<length(lights); i++) {
    pinMode(lights[i], OUTPUT);
  }
}

void loop() {
  static unsigned long lastTime = 0;
  static int pos = 0;
  
  if(millis() - lastTime > pattern[pos][0]) {
    //time to change the lights
    for(int i = 1; i < length(pattern[pos])-1; i++) {
      digitalWrite(lights[i], pattern[pos][i+1]);
    }
    
    //now move pos along to the next position in the pattern
    pos++;
    
    //if we reached the end, start at the beginning again
    if(pos >= length(pattern)) pos = 0;
    
    //now record the time that we did this, for the next delay
    lastTime = millis();
  }
}

See my http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html Or Robin2's several things at once http://forum.arduino.cc/index.php?topic=223286.0