How to make an Arduino Nano Pixel LED Ring with WS2812B LEDs

How to make an Arduino Nano Pixel LED Ring with WS2812B LEDs

Hello and welcome back! In this project, we’ll learn how to make a Pixel LED Ring using an Arduino Nano board. I used 24 WS2812B LEDs, which are perfect for creating colorful light patterns. This project is beginner-friendly, and anyone can try it with ease. I have also programmed 20 unique light patterns into the ring. But you can easily change or customize them. Additionally, I’ve added a push button to the LED ring. This allows you to change the light patterns by pressing the button. To make the project easier to build and more professional, I designed a custom PCB (Printed Circuit Board) with JLCPCB, one of the leading PCB manufacturers. You can print your own PCB quickly and affordably with JLCPCB. They also offer free coupons, which you can use by clicking this link.

What is the WS2812B LED?

The WS2812B LED is an addressable pixel LED. Each LED comes with a built-in control chip, allowing individual LEDs to be programmed independently. These LEDs use three primary colors red, green, and blue (RGB). By mixing these colors, you can create any color you want. Also, You can control the brightness, color, and even specific effects for each LED with a single data pin. I used one of the digital pins on the Arduino Nano board to control the LED ring. You can use this knowledge to apply to your own Pixel LED creations, whether it’s a decorative piece for your room, your computer desk, wall decoration, etc.

How to make an Arduino Nano Pixel LED Ring with WS2812B LEDs

Pin diagram of this WS2812B Pixel LED

How to make an Arduino Nano Pixel LED Ring with WS2812B LEDs

Ok, let’s do this project step by step. The required components are given below.

Disclosure: These Amazon links are Affiliate links. As an Amazon Associate, I earn from qualifying purchases.

Step 1

Firstly, identify these components.

Step 2

Secondly, let’s order PCBs for this project.

  • Click the “Instant Quote” button and upload the Gerber file, which you can download from the link below.
  • Gerber file — Download
  • For this project, I ordered five red PCBs along with a stencil. You can customize the PCB color, quantity, and other options based on your needs.
  • While ordering a stencil is optional, it can be very helpful for applying solder paste accurately during assembly. If you prefer, you can order the PCB without the stencil. Once you’ve finalized your selections, choose your preferred build time and shipping method. Finally, click “Save to Cart” to complete your order.

Step 3

Third, unbox your PCB package. Inside, you’ll find your PCBs and the stencil (if you ordered one).

Step 4

Now, place your PCB on a flat surface and align the stencil over it carefully. Once aligned, apply the solder paste evenly across the stencil to ensure it fills the designated pads.

Step 5

Next, carefully remove the stencil and place the LEDs, capacitors, and resistors onto their respective pads, ensuring proper alignment. Once all components are in place, solder them using a hot air gun or a heating pad to secure them firmly to the PCB.

Step 6

Now, solder the remaining components manually using a soldering iron. Once everything is in place, clean your PCB using a suitable chemical to remove any excess solder paste or flux residue.

Step 7

Afterward, connect the Arduino Nano board to the PCB and plug it into your computer. Next, open the Arduino IDE, and copy and paste the following code into the IDE. Make sure to include the FastLED library by navigating to Sketch > Include Library > Manage Libraries, then search for and install the FastLED library before uploading the code. You can also download it using the link below.

#include <FastLED.h>

#define LED_PIN     2 //Pin for Pixel LEDs
#define BUTTON_PIN 3  // Pin for button input
#define NUM_LEDS    24
#define BRIGHTNESS  100

CRGB leds[NUM_LEDS];
int currentPattern = 0; // To track the active pattern
unsigned long lastUpdate = 0;
const int patternInterval = 5000; // Change pattern every 5 seconds

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.setBrightness(BRIGHTNESS);
}

void loop() {
  static unsigned long lastButtonPress = 0;
  const unsigned long debounceDelay = 200;  // Debounce delay in milliseconds

  // Check if the button is pressed
  if (digitalRead(BUTTON_PIN) == LOW && (millis() - lastButtonPress > debounceDelay)) {
    lastButtonPress = millis();
    currentPattern = (currentPattern + 1) % 21;  // Cycle through 21 patterns (0-20)
  }

  // Automatically change patterns every interval
  if (millis() - lastUpdate > patternInterval) {
    currentPattern = (currentPattern + 1) % 21; // Cycle through 21 patterns
    lastUpdate = millis();
  }

  // Call the active pattern
  switch (currentPattern) {
    case 0: rainbowCycle(); break;
    case 1: colorWipe(CRGB::Blue); break;
    case 2: colorWipe(CRGB::Red); break;
    case 3: theaterChase(CRGB::Green); break;
    case 4: theaterChase(CRGB::Yellow); break;
    case 5: runningLights(); break;
    case 6: bouncingBall(); break;
    case 7: sparkle(CRGB::Purple); break;
    case 8: fireEffect(); break;
    case 9: rainbowStrobe(); break;
    case 10: waveEffect(); break;
    case 11: dualScanner(); break;
    case 12: twinkle(); break;
    case 13: comet(); break;
    case 14: pulseEffect(); break;
    case 15: meteorShower(); break;
    case 16: colorGradientWipe(); break;
    case 17: rippleEffect(); break;
    case 18: glitterEffect(); break;
    case 19: heartbeatPulse(); break;
    case 20: knightRider(); break;
  }

  FastLED.show();
}

// Pattern Functions

void rainbowCycle() {
  static uint8_t hue = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(hue + (i * 10), 255, 255);
  }
  hue++;
  delay(20);
}

void colorWipe(CRGB color) {
  static int pos = 0;
  leds[pos] = color;
  FastLED.show();
  delay(50);
  leds[pos] = CRGB::Black;
  pos = (pos + 1) % NUM_LEDS;
}

void theaterChase(CRGB color) {
  static int offset = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    if ((i + offset) % 3 == 0) {
      leds[i] = color;
    } else {
      leds[i] = CRGB::Black;
    }
  }
  offset = (offset + 1) % 3;
  delay(100);
}

void runningLights() {
  static int pos = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(0, 0, sin8(pos + i * 10));
  }
  pos++;
  delay(50);
}

void bouncingBall() {
  static float pos = 0;
  static float speed = 0.1;
  static int dir = 1;

  int ballPos = int(pos);
  leds[ballPos] = CRGB::White;

  FastLED.show();
  delay(20);

  leds[ballPos] = CRGB::Black;

  pos += speed * dir;
  if (pos >= NUM_LEDS - 1 || pos <= 0) {
    dir *= -1;
  }
}

void sparkle(CRGB color) {
  int pos = random(NUM_LEDS);
  leds[pos] = color;
  FastLED.show();
  delay(50);
  leds[pos] = CRGB::Black;
}

void fireEffect() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(random(10, 50), 255, random(100, BRIGHTNESS));
  }
  delay(50);
}

void rainbowStrobe() {
  static uint8_t hue = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(hue, 255, BRIGHTNESS);
  }
  hue += 10;
  delay(100);
}

void waveEffect() {
  static uint8_t wave = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(wave + (i * 8), 255, BRIGHTNESS);
  }
  wave++;
  delay(30);
}

void dualScanner() {
  static int pos = 0;
  static int dir = 1;
  leds[pos] = CRGB::Red;
  leds[NUM_LEDS - 1 - pos] = CRGB::Blue;
  FastLED.show();
  delay(50);
  leds[pos] = CRGB::Black;
  leds[NUM_LEDS - 1 - pos] = CRGB::Black;
  pos += dir;
  if (pos == 0 || pos == NUM_LEDS - 1) dir *= -1;
}

void twinkle() {
  int pos = random(NUM_LEDS);
  leds[pos] = CHSV(random(0, 255), 200, BRIGHTNESS);
  FastLED.show();
  delay(100);
  leds[pos] = CRGB::Black;
}

void comet() {
  static int pos = 0;
  leds[pos] = CHSV(160, 255, BRIGHTNESS);
  FastLED.show();
  delay(50);
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].fadeToBlackBy(20);
  }
  pos = (pos + 1) % NUM_LEDS;
}

void pulseEffect() {
  static uint8_t brightness = 0;
  static int dir = 1;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(128, 255, brightness);
  }
  brightness += dir * 5;
  if (brightness == 0 || brightness == BRIGHTNESS) dir *= -1;
  delay(30);
}

void meteorShower() {
  static int pos = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].fadeToBlackBy(40);
  }
  leds[pos] = CRGB::White;
  pos = (pos + 1) % NUM_LEDS;
  delay(50);
}

void colorGradientWipe() {
  static uint8_t hue = 0;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(hue, 255, BRIGHTNESS);
    hue += 5;
    FastLED.show();
    delay(50);
  }
}

void rippleEffect() {
  static int center = 0;
  static int radius = 0;
  static bool expanding = true;

  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].fadeToBlackBy(40);
  }
  if (expanding) {
    leds[(center + radius) % NUM_LEDS] = CRGB::Blue;
    leds[(center - radius + NUM_LEDS) % NUM_LEDS] = CRGB::Blue;
    radius++;
    if (radius >= NUM_LEDS / 2) expanding = false;
  } else {
    center = (center + 1) % NUM_LEDS;
    radius = 0;
    expanding = true;
  }
  delay(50);
}

void glitterEffect() {
  for (int i = 0; i < NUM_LEDS / 2; i++) {
    int pos = random(NUM_LEDS);
    leds[pos] = CHSV(random(0, 255), 200, BRIGHTNESS);
  }
  delay(100);
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].fadeToBlackBy(30);
  }
}

void heartbeatPulse() {
  static uint8_t brightness = 0;
  static int dir = 1;
  static bool pause = false;

  if (!pause) {
    CRGB color = CRGB::Red;
    color.nscale8(brightness); // Scale the brightness of the color
    for (int i = 0; i < NUM_LEDS; i++) {
      leds[i] = color;
    }
    brightness += dir * 10;
    if (brightness >= BRIGHTNESS || brightness <= 0) {
      dir *= -1;
      if (brightness == 0) pause = true;
    }
  } else {
    delay(500);
    pause = false;
  }
  delay(30);
}


void knightRider() {
  static int pos = 0;
  static int dir = 1;

  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i].fadeToBlackBy(40);
  }
  leds[pos] = CRGB::Red;
  FastLED.show();
  pos += dir;
  if (pos == NUM_LEDS - 1 || pos == 0) {
    dir *= -1;
  }
  delay(50);
}
  • Now, select the correct board and port in the Arduino IDE. Once selected, click the Upload button to transfer the code to the Arduino Nano.

Step 8

Finally, disconnect the USB cable and connect an external 5V DC power supply to the LED ring. While you can use USB power for this project, I recommend using an external power supply for better stability and to prevent overloading the USB port. Ok, enjoy this project! The full video guide is below. So we hope to see you in the next Project. Have a great day!

How to make an Arduino Nano Pixel LED Ring with WS2812B LEDs

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *