LED Chasing Lights Progamming

Hey guys,

So I have a code for a ring of LEDs to make them chase faster and faster. I have the LEDs connected into the PWM pins arranged so that they are symmetrical, which is why the pins switching on and off in my code jump around a little. Here's the code:

void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);  
}

void loop() {
  digitalWrite(1, HIGH);
  delay(500);              
  digitalWrite(1, LOW);
  digitalWrite(2, HIGH);
  delay(500);
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  delay(500);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(500);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  delay(500);
  digitalWrite(5, LOW);
  digitalWrite(7, HIGH);
  delay(500);
  digitalWrite(7, LOW);
  digitalWrite(6, HIGH);
  delay(500);
  digitalWrite(6, LOW);
  digitalWrite(8, HIGH);
  delay(500);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(500);
  digitalWrite(12, LOW);
  digitalWrite(9, HIGH);
  delay(500);
  digitalWrite(9, LOW);
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  digitalWrite(10, HIGH);
  delay(500);
  digitalWrite(10, LOW);
  digitalWrite(0, HIGH);
  delay(500);
  digitalWrite(0, LOW);
  digitalWrite(11, HIGH);
  delay(500);
  digitalWrite(11, LOW);
  digitalWrite(1, HIGH);
  delay(400);              
  digitalWrite(1, LOW);
  digitalWrite(2, HIGH);
  delay(400);
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  delay(400);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(400);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  delay(400);
  digitalWrite(5, LOW);
  digitalWrite(7, HIGH);
  delay(400);
  digitalWrite(7, LOW);
  digitalWrite(6, HIGH);
  delay(400);
  digitalWrite(6, LOW);
  digitalWrite(8, HIGH);
  delay(400);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(400);
  digitalWrite(12, LOW);
  digitalWrite(9, HIGH);
  delay(400);
  digitalWrite(9, LOW);
  digitalWrite(13, HIGH);
  delay(400);
  digitalWrite(13, LOW);
  digitalWrite(10, HIGH);
  delay(400);
  digitalWrite(10, LOW);
  digitalWrite(0, HIGH);
  delay(400);
  digitalWrite(0, LOW);
  digitalWrite(11, HIGH);
  delay(400);
  digitalWrite(11, LOW);
  digitalWrite(1, HIGH);
  delay(300);              
  digitalWrite(1, LOW);
  digitalWrite(2, HIGH);
  delay(300);
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  delay(300);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(300);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  delay(300);
  digitalWrite(5, LOW);
  digitalWrite(7, HIGH);
  delay(300);
  digitalWrite(7, LOW);
  digitalWrite(6, HIGH);
  delay(300);
  digitalWrite(6, LOW);
  digitalWrite(8, HIGH);
  delay(300);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(300);
  digitalWrite(12, LOW);
  digitalWrite(9, HIGH);
  delay(300);
  digitalWrite(9, LOW);
  digitalWrite(13, HIGH);
  delay(300);
  digitalWrite(13, LOW);
  digitalWrite(10, HIGH);
  delay(300);
  digitalWrite(10, LOW);
  digitalWrite(0, HIGH);
  delay(300);
  digitalWrite(0, LOW);
  digitalWrite(11, HIGH);
  delay(300);
  digitalWrite(11, LOW);
  digitalWrite(1, HIGH);
  delay(200);              
  digitalWrite(1, LOW);
  digitalWrite(2, HIGH);
  delay(200);
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  delay(200);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(200);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  delay(200);
  digitalWrite(5, LOW);
  digitalWrite(7, HIGH);
  delay(200);
  digitalWrite(7, LOW);
  digitalWrite(6, HIGH);
  delay(200);
  digitalWrite(6, LOW);
  digitalWrite(8, HIGH);
  delay(200);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(200);
  digitalWrite(12, LOW);
  digitalWrite(9, HIGH);
  delay(200);
  digitalWrite(9, LOW);
  digitalWrite(13, HIGH);
  delay(200);
  digitalWrite(13, LOW);
  digitalWrite(10, HIGH);
  delay(200);
  digitalWrite(10, LOW);
  digitalWrite(0, HIGH);
  delay(200);
  digitalWrite(0, LOW);
  digitalWrite(11, HIGH);
  delay(200);
  digitalWrite(11, LOW);
  digitalWrite(1, HIGH);
  delay(100);              
  digitalWrite(1, LOW);
  digitalWrite(2, HIGH);
  delay(100);
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  delay(100);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(100);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  delay(100);
  digitalWrite(5, LOW);
  digitalWrite(7, HIGH);
  delay(100);
  digitalWrite(7, LOW);
  digitalWrite(6, HIGH);
  delay(100);
  digitalWrite(6, LOW);
  digitalWrite(8, HIGH);
  delay(100);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(100);
  digitalWrite(12, LOW);
  digitalWrite(9, HIGH);
  delay(100);
  digitalWrite(9, LOW);
  digitalWrite(13, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  digitalWrite(10, HIGH);
  delay(100);
  digitalWrite(10, LOW);
  digitalWrite(0, HIGH);
  delay(100);
  digitalWrite(0, LOW);
  digitalWrite(11, HIGH);
  delay(100);
  digitalWrite(11, LOW);
  digitalWrite(1, HIGH);
  
}

Now, at the end of this code, I want the 6 PWM LEDs to begin pulsing (fading in and out) in an endless loop. I tried using this code:

analogWrite(9, brightness);    

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);                            
}

at the end of it (I also set int brightness = 0 and int fadeAmount= 5 before the setup), but it did not work correctly. What's the best way to go about this? I've searched around but am having trouble finding the answer. Thanks, guys!

(brightness == 0 || brightness == 255)

The problem here is that if fadeamount does not make it get to exactly 255 or exactly 0, then it won't work. Try

(brightness <= 0 || brightness >= 255)

Also, what did not work?

  digitalWrite(1, HIGH);
  delay(500);              
  digitalWrite(1, LOW);
  digitalWrite(2, HIGH);
  delay(500);
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  delay(500);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(500);

blah blah...

If I may suggest a fairly big simplification:

const int numberOfLEDs = 14;

const byte LEDorder [numberOfLEDs] = { 1, 2, 3, 4, 5, 7, 6, 8, 12, 9, 13, 10, 0, 11 };

void setup() {                
  for (byte i = 0; i < numberOfLEDs; i++)  
    pinMode(LEDorder [i], OUTPUT);
}  // end of setup

void doCircle (const unsigned long delayAmount)
  {
  for (byte i = 0; i < numberOfLEDs; i++)
    {
    byte pin = LEDorder [i];
    digitalWrite(pin, HIGH);
    delay(delayAmount);              
    digitalWrite(pin, LOW);
    }   // end of for
  }  // end of doCircle
  
void loop() 
  {
  for (unsigned long n = 500; n > 0; n -= 100)
    doCircle (n);
  } // end of loop

Then we can look at the problem with the pulsing.

Ahhhh. :cold_sweat: That is much better. Thank you, Nick. The one thing I understood how to do with the old cumbersome code that I do not with your new, nice and clean code is that once it reaches it's fastest spinning speed (which I would like to be a delay of 10 between lights) I'd like it to spin around at that speed ten times and then begin the pulsing.

My LEDs are very, very bright and I've been getting a bit of a headache working on this. It's too hard for me to not stare at the pretty, blinky LEDs. If I wanted to set them all at a lower brightness, would I just change digitalWrite(pin, HIGH) into digitalWrite(pin, 100) or something like this? Thanks so much.

Something like, but not that. digitalWrite is as it's name says, digital. On or off.

You have to use analogWrite to vary the brightness. Only a select number of the pins on the Arduino support analogWrite though.

To answer your first question, you could change:

for (unsigned long n = 500; n > 0; n -= 100)
    doCircle (n);

to something like:

 doCircle (500);
 doCircle (400);
 doCircle (300);
 doCircle (200);
 doCircle (200);
 doCircle (100);
 doCircle (100);

Or even use a table of delays (like the table of pins further up).

If I wanted to set them all at a lower brightness, would I just change digitalWrite(pin, HIGH) into digitalWrite(pin, 100) or something like this?

No that won't work. digitalWrite is either on or off.

I did something along those lines a while back, but can't find it. Maybe someone else can. Basically it used a timer to establish a "PWM frequency" and then detect that in an interrupt to make all the pins into PWM pins.

Here:

This is how you can do it:

volatile byte wantedPin;   // which pin to pulse on and off

const byte PWMiterations = 40;
const byte PWMdutyCycle = 2;   // <-- should be less than PWMiterations

volatile byte pwmCount;

ISR(TIMER1_COMPA_vect)
{

  // if in "on" cycle turn the LED on
  if (pwmCount > PWMdutyCycle)
    digitalWrite(wantedPin, LOW);      
  else
    digitalWrite(wantedPin, HIGH);      
   
 if (++pwmCount >= PWMiterations)
   pwmCount = 0;
}  // end of TIMER1_COMPA_vect

const int numberOfLEDs = 14;

const byte LEDorder [numberOfLEDs] = { 1, 2, 3, 4, 5, 7, 6, 8, 12, 9, 13, 10, 0, 11 };

void setup() 
  {                
  for (byte i = 0; i < numberOfLEDs; i++)  
    pinMode(LEDorder [i], OUTPUT);
    
  // set up Timer 1
  TCCR1A = 0;          // normal operation
  TCNT1 = 0;           // make sure we start at zero
  TCCR1B = _BV(WGM12) | _BV(CS10) | _BV (CS12);   // CTC, scale to clock / 1024
  OCR1A =  5;       // compare A register value (1000 * clock speed / 1024)
  TIMSK1 = _BV (OCIE1A);             // interrupt on Compare A Match
    
  }  // end of setup

void doCircle (const unsigned long delayAmount)
  {
  for (byte i = 0; i < numberOfLEDs; i++)
    {
    noInterrupts ();
    byte pin = LEDorder [i];
    wantedPin = pin;
    pwmCount = 0;
    interrupts ();
    delay(delayAmount);              
    digitalWrite(pin, LOW);
    }   // end of for
  }  // end of doCircle
  
void loop() 
  {
  for (unsigned long n = 500; n > 0; n -= 100)
    doCircle (n);
  } // end of loop

Change the constant PWMdutyCycle to get it brighter or less bright. Right now it is fairly dull (2 / 40 cycles on, the rest off).

Now we're getting somewhere! Here's the code I have now:

const int numberOfLEDs = 14;

const byte LEDorder [numberOfLEDs] = { 1, 2, 3, 4, 5, 7, 6, 8, 12, 9, 13, 10, 0, 11 };

void setup() {                
  for (byte i = 0; i < numberOfLEDs; i++)  
    pinMode(LEDorder [i], OUTPUT);
}  // end of setup

void doCircle (const unsigned long delayAmount)
  {
  for (byte i = 0; i < numberOfLEDs; i++)
    {
    byte pin = LEDorder [i];
    digitalWrite(pin, HIGH);
    delay(delayAmount);              
    digitalWrite(pin, LOW);
    }   // end of for
  }  // end of doCircle
  
void loop() 
  {
 doCircle (500);
  doCircle (450);
  doCircle (400);
  doCircle (350);
  doCircle (300);
  doCircle (250);
  doCircle (200);
  doCircle (150);
  doCircle (100);
  doCircle (90);
  doCircle (80);
  doCircle (70);
  doCircle (60);
  doCircle (50);
  doCircle (40);
  doCircle (30);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);

  
  } // end of loop

And it's doing it's speed up and then stay at a 20 delay perfectly. Now I'm trying to implement the pulsing after it does it's cycle of doCircle (20)'s by using a modified version of your 'fading 20 LEDs' code, but I'm running into problems. I tried this on it's own as an experiment:

int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

const byte pwmPin = 3;
const byte maxPin = 11;

ISR (PCINT0_vect)
 {
static byte val = 0;

 val = !val;
 for (byte i = 0; i <= maxPin; i++)
   if (i != pwmPin)
     digitalWrite (i, val);
 }
 
void setup() 
  { 
  for (byte i = 0; i <= maxPin; i++)
    pinMode (i, OUTPUT);

  // pin change interrupt
  PCMSK0 = _BV (PCINT1);  // only want pin 9
  PCIFR  = _BV (PCIF0);   // clear any outstanding interrupts
  PCICR |= _BV (PCIE0);   // enable pin change interrupts for PCINT7..0
  }   // end of setup

void loop()  
  { 
  // set the brightness of pin 9:
  analogWrite(pwmPin, brightness);    

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (brightness == 0 || brightness == 255) 
    fadeAmount = -fadeAmount ; 

  // wait for 30 milliseconds to see the dimming effect    
  delay(30);                            
}  // end of loop

I changed the 'maxPin' to 11, because I didn't want all the LEDs to fade in and out at once (I don't have sufficient power so I only want pins 3, 5, 6, 9, 10, and 11 pulsing) but I only got the pin 3 LED fading. I'm assuming I'm not understanding the maxPin. Just tried your brightness limiting code and it worked perfectly. You're helping so much, Nick. I really aprecciate it. I apologize for the neverending questions, but it's exciting to be learning this stuff, however slow that process may be. You've gotten me to the point where this thing is almost finished! Now I just need it to end with the pulsing loop and have it all activated by a button push. Hehe. :roll_eyes:

  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);
  doCircle (20);

Think "loops".

for (byte j = 0; j < 14; j++)
  doCircle (20);

for (byte j = 0; j < 14; j++)
doCircle (20);

Little confused about bytes. Where are you getting the names 'i' and 'j' from for these bytes? I understand that they are there to store a number, but I'm getting confused on where the letters are coming from.

Try this, it fades a group of LEDs on and off. After that do a bit of experimenting. :slight_smile:

const int numberOfLEDs = 14;

volatile byte wantedPins [numberOfLEDs] =  { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 };   // which pin to pulse on and off

const byte PWMiterations = 40;
byte PWMdutyCycle;   // <-- should be less than PWMiterations

volatile byte pwmCount;

ISR(TIMER1_COMPA_vect)
{
byte i;

  if (pwmCount > PWMdutyCycle)
    {
    // turn all off
    for (i = 0; i < numberOfLEDs; i++)
      digitalWrite(i, LOW);      
    }
  else
    {
    // turn wanted ones on
    for (i = 0; i < numberOfLEDs; i++)
      if (wantedPins [i])
        digitalWrite(i, HIGH);      
    }
    
   
 if (++pwmCount >= PWMiterations)
   pwmCount = 0;
}

void setup() 
  {                
  for (byte i = 0; i < numberOfLEDs; i++)  
    pinMode(i, OUTPUT);
    
  // set up Timer 1
  TCCR1A = 0;          // normal operation
  TCNT1 = 0;           // make sure we start at zero
  TCCR1B = _BV(WGM12) | _BV(CS10) | _BV (CS12);   // CTC, scale to clock / 1024
  OCR1A =  5;       // compare A register value (1000 * clock speed / 1024)
  TIMSK1 = _BV (OCIE1A);             // interrupt on Compare A Match
    
  }  // end of setup

 
void loop() 
  {
  for (PWMdutyCycle = 0; PWMdutyCycle < PWMiterations; PWMdutyCycle++)
    delay (100);

  for (PWMdutyCycle = PWMiterations; PWMdutyCycle > 0; PWMdutyCycle--)
    delay (100);
    
  } // end of loop

Where are you getting the names 'i' and 'j' from for these bytes?

for (byte j = 0; j < 14; j++)

That declares "j" as in:

byte j

But what is byte j? Are you creating and naming a byte with that declaration or is byte j something that already exists that you are calling upon?

It is created at that point as a loop variable.

Look here?

Description

A byte stores an 8-bit unsigned number, from 0 to 255.

It's a good idea to look into the reference from time to time :wink: :wink: :wink:

This construction declares a variable named "j", which can hold values between 0 and 255 (incl.).

best regards
Andreas