// simple project using Arduino UNO, NeoPixel ring and Rotary Encoder to fill the ring with colors
// created by upir, 2024
// youtube channel: https://www.youtube.com/upir_upir
// YOUTUBE VIDEO: https://youtu.be/JK3KePYrkYY
// Source Files: https://github.com/upiir/arduino_neopixel_rings
// Links from the video:
// Wokwi starting sketch: https://wokwi.com/projects/374907938100932609
// Adafruit NeoPixel guide: https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library-use
// NeoPixel ring(s): https://s.click.aliexpress.com/e/_DdIyIgl
// Rotary Encoder Module: https://s.click.aliexpress.com/e/_DETznkv
// Solid Aluminium Knob: https://s.click.aliexpress.com/e/_DFPuloh
// Breadboard wires: https://s.click.aliexpress.com/e/_Dkbngin
// Arduino UNO R3: https://s.click.aliexpress.com/e/_AXDw1h
// Arduino breadboard prototyping shield: https://s.click.aliexpress.com/e/_DlxEfPX
// Related videos:
// Pimp My Potentiometer! - https://youtu.be/tHL4RYGSvg4
// Pimp My Potentiometer (again) - https://youtu.be/sE3LSYoCqLQ
// Pimp my Potentiometer -CHEAPER- - https://youtu.be/Bot865qmdsM
// Your 1st CNC-ed Part - https://youtu.be/EB8PISr4m4g
// My First CNCed part --EVER-- - https://youtu.be/e2UNsZPjHkk
// My First PCB --EVER-- - https://youtu.be/6cqvTHCuDto
// DIY Volume Control - https://youtu.be/jvHRfsgw4l8
// Knob over OLED Display - https://youtu.be/SmbcNx7tbX8
#include <Adafruit_NeoPixel.h> // library for NeoPixels
#include <Encoder.h> // library for rotary encoder
#define PIN_NEO_PIXEL 6 // Arduino pin that connects to NeoPixel
#define NUM_PIXELS 16 // The number of LEDs (pixels) on NeoPixel
#define ENCODER_BTN 4 // rotary encoder button pin
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800); // set the NeoPixel ring initialization
Encoder myEnc(2, 3); // initialize the rotary encoder
byte color_blue_RGB[3] = {0, 0, 255}; // blue color in RGB color space
byte color_red_RGB[3] = {255, 0, 0}; // red color in RGB color space
byte color_blend_RGB[3]; // variable to store blended RGB color
byte color_blue_HSV[3] = {170, 255, 255}; // blue color in HSV color space
byte color_red_HSV[3] = {0, 255, 255}; // red color in HSV color space
byte color_blend_HSV[3]; // variable to store blended HSV color
int encoder_value_old = 0; // previous value of rotary encoder
int encoder_value_new = 0; // current value of rotary encoder
int percentage_value = 50; // percentage value to fill the ring: 0 - 100%
int mode = 0; // 0 = white, 1 = blue to red RGB, 2 = blue to red HSV
// function to blend between two colors
void blend_colors (byte color_start[3], byte color_end[3], byte color_blended[3], float percentage /*0-100*/) {
for (int i = 0; i < 3; i ++) {
// linear interpolation between two values
color_blended[i] = round((float)color_start[i] + (((float)color_end[i] - (float)color_start[i]) * (percentage / 100.0)));
}
}
void setup() {
NeoPixel.begin(); // initialize the NeoPixel strip object
pinMode(ENCODER_BTN, INPUT_PULLUP); // set pin for rotary encoder button
}
void loop() {
// read the new value of rotary encoder
encoder_value_new = myEnc.read(); // read the encoder value
if (encoder_value_new != encoder_value_old) { // if the old value does not equal the new value
percentage_value = constrain(percentage_value - (encoder_value_new - encoder_value_old), 0, 100); // set the percentage value between 0-100%
encoder_value_old = encoder_value_new; // update the old encoder value
}
if (digitalRead(ENCODER_BTN) == LOW) {
// switch the mode
mode++;
if (mode > 2) {
mode = 0;
}
delay(500); // add a small delay
}
NeoPixel.clear(); // set all pixel colors to 'off'. It only takes effect if pixels.show() is called
// go over every single pixel on the neopixel ring
for (int pixel = 0; pixel < NUM_PIXELS; pixel++) { // for each pixel
if ((pixel * (100 / (NUM_PIXELS - 1))) < percentage_value) { // fill pixels based on the rotary encoder value
if (mode == 0) { // draw white pixels
// set pixels to WHITE color
NeoPixel.setPixelColor(pixel, NeoPixel.Color(255, 255, 255)); // set all pixels to white color
} else if (mode == 1) { // blend between blue and red in RGB
// blend two colors in RGB color space
blend_colors(color_blue_RGB, color_red_RGB, color_blend_RGB, pixel * (100.0 / (NUM_PIXELS - 1)));
// set the pixel to the blended color
NeoPixel.setPixelColor(pixel, NeoPixel.Color(color_blend_RGB[0], color_blend_RGB[1], color_blend_RGB[2]));
} else if (mode == 2) { // blend between blue and red in HSV
// blend two colors in HSV color space
blend_colors(color_blue_HSV, color_red_HSV, color_blend_HSV, pixel * (100.0 / (NUM_PIXELS - 1)));
// set the pixel to the blended color
NeoPixel.setPixelColor(pixel, NeoPixel.ColorHSV((unsigned int)color_blend_HSV[0] * 256, color_blend_HSV[1], color_blend_HSV[2]));
}
}
}
//NeoPixel.setBrightness(50); // don´t forget to uncomment this line for real Arduino to make it less bright
NeoPixel.show(); // show all the set pixels on neopixel ring
}