gif gif

The interesting corner

gif gif

Programming WS2812B LEDs with an Arduino Nano

For a cyberpunk-themed birthday party, my gf and I decided to make jackets with LEDs in them. I did the electronics and programming, and she did the sewing. The LEDs I used are WS2812B LEDs, which are individually addressable. I also decided to add a MAX4466 sound sensor to be able to change the colow of the LEDs according to the sound level, and TTP223 touch sensor to change modes. The code for the whole project is available in the library: . I controlled the LEDs with the FastLED library. I added 6 modes:

The code for the setup function sets up the serial connection, generates a random seed, sets up the LEDs driver, the timers and fills the array for a star pattern.

#define MAX_MODES 6

#define NUM_STARS 100
CRGB leds[NUM_LEDS];

void setup()
{
  Serial.begin(9600);

  randomSeed(analogRead(0));

  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);

  touch_timer.period = 2000;
  touch_timer.startMillis = millis();

  walk_timer.period = 50;
  walk_timer.startMillis = millis();

  for (int i = 0; i < NUM_STARS; i++)
  {
    generate_new_star(&stars[i]);
  }

}              
            

I use timers that use the millis() function to keep track of time:

typedef struct timer // timer based arount millis
{
  unsigned long startMillis;
  unsigned long period;
} timer_t;

uint8_t checkTimer(timer_t *timer)
{
  unsigned long currentMillis = millis();
  if (currentMillis - timer->startMillis > timer->period)
  {
    timer->startMillis = currentMillis;
    return 1;
  }
  return 0;
}
              

I also made a function to clear all the leds:

void clearAll()
{
  for (int i = 0; i < NUM_LEDS; i++)
  {
    leds[i] = CRGB(0, 0, 0);
  }

  FastLED.show();
}
                  

The main loop for the code checks the touch sensor and switches the mode accordingly:

char read_touch()
{

  if (checkTimer(&touch_timer))
  {
    return digitalRead(TOUCH_PIN);
  }
  return 0;
}


void loop()
{

  if (read_touch())
  {
    mode = (mode + 1) % (MAX_MODES + 1);
  }
  //  //  Serial.println("switch case");

  switch (mode)
  {
    case 0:
      walkMode();
      break;
    case 1:
      clearAll();
      starMode();
      break;
    case 2:
      soundMode();
      break;
    case 3:
      breathingMode();
      break;
    case 4:
      animateMode();
      break;
    case 5:
      waveMode();
      break;

  }
}

The Sound mode checks the sound level from the MAX4466 and changes the color of the LEDs accordingly:

int soundlevels[5] {0};
int sound_i = 0;

void soundMode()
{
  sound_i += 1;
  sound_i = sound_i % 5;
  float sensorvalue = abs(analogRead(A0));

  for (int i = 0; i < NUM_LEDS; i++)
  {
    leds[i] = CHSV((sensorvalue / 1024) * 255, 255, 255);
  }
  FastLED.show();
}

The breathing mode changes the brightness of all LEDs in a breathing pattern:


void breathingMode()
{
  if ((direction_bm >> BREATHING_DIRECTION_MASK) == 1)
  {
    breathing_v--;  
  } else {
    breathing_v++;
  }
  

  for (int i = 0; i < NUM_LEDS; i++)
  {
    leds[i] = CHSV(BREATHING_H, BREATHING_S, breathing_v);
  }
  FastLED.show();
  
  if (breathing_v >= 254 || breathing_v == 0)
  {
    direction_bm ^= (1 << BREATHING_DIRECTION_MASK);
  }
  Serial.println(breathing_v);
  

}

The animate mode creates a rainbow pattern accross the LEDs:

void animateMode()
{

  animate_h += 10;

  if (animate_h >= 255)
  {
    animate_h = 0;
  }

  animate_i += 2;
  if (animate_i >= NUM_LEDS)
  {
    animate_i = 0;
  }
  leds[animate_i] = CHSV(animate_h, 255, 255);
  leds[animate_i + 1] = CHSV(animate_h, 255, 255);
  FastLED.show();
}

The wave mode creates a rainbow wave accross all LEDs:

void waveMode()
{
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(wave_h, 255, 255);
  }
  FastLED.show();

  wave_h++;
}

The walk mode walks green and pink LEDs across the LED strip:

void walkMode()
{

  if (checkTimer(&walk_timer))
  {
    clearAll();
    walk_i++;
    if (walk_i == NUM_WALKERS)
    {
      walk_i = 0;
    }

    for (int i = 0; i < NUM_LEDS; i += NUM_WALKERS)
    {
      leds[i + walk_i] = CRGB(0, 255, 64);
      if ((i + walk_i) > 1 && (i + walk_i) < (NUM_LEDS - 2))
      {
        leds[i + walk_i + 1] = CRGB(255, 0, 130);
      }
    }

    FastLED.show();
  }

}

The star mode creates a star pattern accross the LEDs:

void generate_new_star(star *star)
{
  star->pos = random(NUM_LEDS);
  star->value = random(40,255);
}

void starMode() 
{

  for (int i = 0; i < NUM_STARS; i++)
  {
    leds[stars[i].pos] = CHSV(BREATHING_H, BREATHING_S, stars[i].value);
    stars[i].value-= 10;

    if (stars[i].value <= 10)
    {
        generate_new_star(&stars[i]);
    }
  }
  FastLED.show();