new program too fast! Where to put millis()?

hi, thanks for help in advance.

I am tryinjgto learn Arduino programming. I want to make lots of blinky LEDs for two applications, One will be my next Christmas lights display, and two, wearable bling for my nieces.

So to that end I have been on here eliciting help, and have gotten a good deal of assistance. Recently, I had a light pattern I tried to set up, but there was no algorithm I could think of to give me exactly what I wanted. So I used a 2 dimensional array to provide the proper sequence.

It worked very well, only trouble is that the new code sequence is too fast! I know, I know, use millis()! I have tried, here is the code:

// Larson scanner with PWM

#define DEBUG_UART 0

const uint8_t ledPin[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};  // PWM pins 2 through 13
const uint8_t totalNoLeds = sizeof(ledPin);

void twopattern()
{
static uint8_t  actual = (totalNoLeds);
static uint32_t previousMillis = 0;
const uint16_t myIntervall = 100;

int patternij[17][12] = {
{255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255}, 
{75, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 75},
{50, 75, 255, 0, 0, 0, 0, 0, 0, 255, 75, 50},
{25, 50, 75, 255, 0, 0, 0, 0, 255, 75, 50, 25},
{10, 25, 50, 75, 255, 0, 0, 255, 75, 50, 25, 10},
{5, 10, 25, 50, 75, 255, 255, 75, 50, 25, 10, 5},
{0, 5, 10, 25, 50, 255, 255, 50, 25, 10, 5, 0},
{0, 0, 5, 10, 255, 75, 75, 255, 10, 5, 0, 0},
{0, 0, 0, 255, 75, 50, 50, 75, 255, 0, 0, 0},
{0, 0, 255, 75, 50, 25, 25, 50, 75, 255, 0, 0},
{0, 255, 75, 50, 25, 10, 10, 25, 50, 75, 255, 0},
{255, 75, 50, 25, 10, 5, 5, 10, 25, 50, 75, 255},
{75, 50, 25, 10, 5, 0, 0, 5, 10, 25, 50, 75},
{50, 25, 10, 5, 0, 0, 0, 0, 5, 10, 25, 50},
{25, 10, 5, 0, 0, 0, 0, 0, 0, 5, 10, 25},
{10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10},
{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5},
};

if (millis() - previousMillis >= myIntervall)
  {
    
for (int j = 0;  j < 17; j++)  
  {
for (int i = 0; i < 12; i++)
    {
    analogWrite(ledPin[i], patternij[j][i]);
    delay(4);
    } 
  }
  
#if DEBUG_UART
#endif 

previousMillis = millis();
}
}

void setup() 
{
  for (uint8_t i = 0; i < totalNoLeds; i++) 
  {
    pinMode(i, OUTPUT);
  } 
}

void loop()
{
twopattern();
}

I cannot figure out WHERE to put the millis(). If I put it where it is, the LEDs flash and then wait for the millis(), If I move it to after the ‘for’ loops, it never runs.

I am missing something. I tried putting the first dimension (rows, columns?) into a variable that updates on millis(), but it did not work well either.

Anyway, a bit of help and a second set of eyes on this program would be very welcome!

Roger Ayotte

Hi Roger,

You have a 4 millisecond delay inside your 2 for loops, as those are 12 and 17 loops long they go round 204 times, which is then multiplied by 4, making 816 milliseconds stuck in your for loops, more than 8 times the 100 milliseconds produced by using millis(). I suspect this is not what you want.

Perry,

If I increase the interval, and eliminate the delay, then the LEDs will cycle fast, then wait for the interval. I tried to put an if millis() - previousmillis statement elsewhere, but I have not been able to get it to wher I would like.

The issue appears to be that the ‘j’ loopgoes too fast, if I recall, when I put an if millis() -previousmillis right between the for loop and the analoguewrite statement, the program just lights a single (or no) led.

Roger

Roger, what you are missing is that you need to get rid of those for-loops. Both of them. You will still need variable j to increment from 0 to 16 and back to 0, and for each value of j, you still need variable I to increment from 0 to 11. But you can't do it with for-loops, you have to do it with global variables and if statements. Only then will you be able to stop using delay() and start using millis() as you want.

Roger,
What PaulRB said, plus, I don't understand what your 4ms delay is for or what your 100ms millis() delay is for, so it's difficult to offer specific advice about how to proceed. To use millis() you need a 'lastMillis' for each delay you need and you need to know the interval you want, which means knowing what it is for. At the moment your millis() delay is not doing anything because the delay() delay is taking longer, 8 times longer, to complete that than the 100 millis() delay.

The below will give you the idea; not sure if it exactly does what you need

As said, you will need to get rid of the for-loops in twopattern.

To do so, first create two additional static variables (that will replace i and j of your for-loops); e.g. indexI and indexJ.

void twopattern()
{
  static uint8_t  actual = (totalNoLeds);
  static uint32_t previousMillis = 0;
  const uint16_t myIntervall = 100;
  
  static uint8_t indexI;
  static uint8_t indexJ;

  ...
  ...
}

Next you can get rid of the for-loops.

void twopattern()
{
  static uint8_t  actual = (totalNoLeds);
  static uint32_t previousMillis = 0;
  const uint16_t myIntervall = 100;
  
  static uint8_t indexI;
  static uint8_t indexJ;

  int patternij[17][12] = {
    ...
    ...
  };

  // if it's time
  if (millis() - previousMillis >= myIntervall)
  {
    analogWrite(ledPin[indexI], patternij[indexJ][indexI]);
    // next indexI
    indexI++;
    // if indexI has reach max value
    if(indexI == 12)
    {
      // reset indexI
      indexI = 0;
      // next indexJ
      indexJ++;

      // if indexJ has reached max value
      if(indexJ == 17)
      {
          // reset indexJ
          indexJ = 0;
      }
    }
    
    previousMillis = millis();
  }
}

Thanks. I tried something simlar to start with, and then thought it did not need to be that complicated. The for loops work, but not for timing.

Perry, without the delay, the LEDs update so fast that you can hardly tell they are blinking! I guess that is what a 120MHz processor will do!

I will update my program and let you know how it went.

Roger Ayotte

here is completed code. It works wonderfully! Thank you!

Roger

// Larson scanner with PWM

#define DEBUG_UART 0

const uint8_t ledPin[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};  // PWM pins 2 through 13
const uint8_t totalNoLeds = sizeof(ledPin);

void twopattern()
{

  static uint8_t  actual = (totalNoLeds);
  static uint32_t previousMillis = 0;
  const uint16_t myIntervall = 5;
 
  static uint8_t indexI;
  static uint8_t indexJ;

int patternij[17][12] = {
{255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255}, 
{75, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 75},
{50, 75, 255, 0, 0, 0, 0, 0, 0, 255, 75, 50},
{25, 50, 75, 255, 0, 0, 0, 0, 255, 75, 50, 25},
{10, 25, 50, 75, 255, 0, 0, 255, 75, 50, 25, 10},
{5, 10, 25, 50, 75, 255, 255, 75, 50, 25, 10, 5},
{0, 5, 10, 25, 50, 255, 255, 50, 25, 10, 5, 0},
{0, 0, 5, 10, 255, 75, 75, 255, 10, 5, 0, 0},
{0, 0, 0, 255, 75, 50, 50, 75, 255, 0, 0, 0},
{0, 0, 255, 75, 50, 25, 25, 50, 75, 255, 0, 0},
{0, 255, 75, 50, 25, 10, 10, 25, 50, 75, 255, 0},
{255, 75, 50, 25, 10, 5, 5, 10, 25, 50, 75, 255},
{75, 50, 25, 10, 5, 0, 0, 5, 10, 25, 50, 75},
{50, 25, 10, 5, 0, 0, 0, 0, 5, 10, 25, 50},
{25, 10, 5, 0, 0, 0, 0, 0, 0, 5, 10, 25},
{10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10},
{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5},  
};

  // if it's time
  if (millis() - previousMillis >= myIntervall)
  {
    analogWrite(ledPin[indexI], patternij[indexJ][indexI]);
    // next indexI
    indexI++;
    // if indexI has reach max value
    if(indexI == 12)
    {
      // reset indexI
      indexI = 0;
      // next indexJ
      indexJ++;

      // if indexJ has reached max value
      if(indexJ == 17)
      {
          // reset indexJ
          indexJ = 0;
      }
    }
    previousMillis = millis();
  }
}

void setup() 
{
  for (uint8_t i = 0; i < totalNoLeds; i++) 
  {
    pinMode(i, OUTPUT);
  } 
}

void loop()
{
twopattern();
}

Here is completed code. It works wonderfully!

:slight_smile:

I guess that is what a 120MHz processor will do!

Well, delay(4) takes 4ms regardless of your processor's speed, be that 1MHz or 1GHz.
What processor are you using, you never said?

Paul,

I was refering to how fast they went without a delay or millis.

I am using an Adafruit Metro M4 express, an SAMD51.

And thank you.

Roger