Fading brightness of neopixel ring with pot while button pressed?

Hi helpful and more knowledgable people than I.
tl;dr version: how to do I dim the light of neopixels in real time with an analog control?

I want to do what would appear to be a simple thing but can't figure it out. I have an arcade button, a slide potentiometer, and a Neopixel ring. I want to be able to hold the button to turn on the led ring, and while holding the button, be able to change the brightness of the ring with the potentiometer, acting like a light dimmer.

For a bit of context, this is part of a sound installation where there are four instruments that blow air through whistles. The players can control the speed of the motor which in turn changes the volume of the whistle. Each instrument is lit a different colour with an led ring, which is controlled by another person who can "conduct" the four players via light and brightness. If one player has no light on, they make no sound, if the light comes on bright, they make a loud sound and so on. In the attached image you can see the wooden hexagonal box on the right has four coloured arcade buttons and sliders. The white hexagons in the centre of the other four boxes is a motor control with its own arduino, but contains the led right which illuminates the 3D printed enclosure.

However I have learned that the adafruit neopixel library as well as the fastLED library use the brightness function less as an expressive tool and more as a permanent setting that is specified at start up and otherwise not really meant to be used in real time. So in comparison to how easy it is to fade a normal LED with PWM, another way has to be found. I looked through several old threads and didn't find a solution, so I come hat humbly in hand to ask for one here. It's entirely possible I'm missing some very basic understanding of the issue or programming/ everything in general, so please be sure to point that out to me if that's your thing.

Here's my current code using the fastLED library, which I found solved the issue of having one string of LEDs (four rings in series from the same control pin) but being able to control each individually. Currently this code doesn't try to change the brightness and only turns the rings on and off with the buttons, as I had to have the installation partly functional, so the potentiometers aren't initialised.

My question is, how do I make the leds respond directly to the movements of the slide potentiometer?

#include <FastLED.h>
#include <Bounce.h>


const uint8_t ledCount = 48;
const uint8_t startGroup0 = 0;
const uint8_t lengthGroup0 = 12;
const uint8_t startGroup1 = 11;
const uint8_t lengthGroup1 = 12;
const uint8_t startGroup2 = 24;
const uint8_t lengthGroup2 = 12;
const uint8_t startGroup3 = 24;
const uint8_t lengthGroup3 = 12;
const uint8_t ledPin = 6;

CRGB leds[ledCount];
CPixelView<CRGB> yellow(leds + startGroup0, lengthGroup0);
CPixelView<CRGB> blue(leds + startGroup1, lengthGroup1);
CPixelView<CRGB> green(leds + startGroup2, lengthGroup2);
CPixelView<CRGB> red(leds + startGroup3, lengthGroup3);


//#define PIN 6
//#define NUMPIXELS 48  //4x 12 led WS2812b rings used
//CRGB leds[NUMPIXELS];

//arcade buttons acting as momentary light switches
Bounce buttonYellow = Bounce(2, 5);  // which is appropriate for good
Bounce buttonBlue = Bounce(3, 5);    // quality mechanical pushbuttons
Bounce buttonGreen = Bounce(4, 5);
Bounce buttonRed = Bounce(5, 5);  // if a button is too "sensitive"

//40mm alps slide potentiometers acting as brightness controls
int potYellow = A0;
int potBlue = A1;
int potGreen = A2;
int potRed = A3;



//the value that mapped reading from pots will give
int lightYellow = 0;
int lightBlue = 0;
int lightGreen = 0;
int lightRed = 0;

void setup() {
  // put your setup code here, to run once:
  FastLED.addLeds<WS2812, ledPin, RGB>(leds, ledCount);
  Serial.begin(9600);
  //pixels.begin();
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
}

void loop() {

  buttonYellow.update();
  buttonBlue.update();
  buttonGreen.update();
  buttonRed.update();

  lightYellow = map(analogRead(potYellow), 0, 1023, 20, 255);
  lightBlue = map(analogRead(potBlue), 0, 1023, 0, 255);
  lightGreen = map(analogRead(potGreen), 0, 1023, 0, 255);
  lightRed = map(analogRead(potRed), 0, 1023, 0, 255);

Serial.println(lightYellow);
delay(120);
  //yellow
  for (int i = startGroup0; i < lengthGroup0; i++) {
    if (buttonYellow.fallingEdge()) {
      yellow[i].setRGB(lightYellow, lightYellow, 0);
      FastLED.show();
    }
    if (buttonYellow.risingEdge()) {
      yellow[i].setRGB(0, 0, 0);
      FastLED.show();
    }
  }

  //blue
  for (int i = startGroup1; i < lengthGroup1; i++) {
    if (buttonBlue.fallingEdge()) {
      blue[i].setRGB(0, 0, lightBlue);
      FastLED.show();
    }
    if (buttonBlue.risingEdge()) {
      blue[i].setRGB(0, 0, 0);
      FastLED.show();
    }
  }

  //green
  for (int i = startGroup2; i < lengthGroup2; i++) {
    if (buttonGreen.fallingEdge()) {
      green[i].setRGB(0, lightGreen, 0);
      FastLED.show();
    }
    if (buttonGreen.risingEdge()) {
      green[i].setRGB(0, 0, 0);
      FastLED.show();
    }
  }

  //red
  for (int i = startGroup3; i < lengthGroup3; i++) {
    if (buttonRed.fallingEdge()) {
      red[i].setRGB(lightRed, 0, 0);
      FastLED.show();
    }
    if (buttonRed.risingEdge()) {
      red[i].setRGB(0, 0, 0);
      FastLED.show();
    }
  }
}

The FastLED library has functions to use HSV. The V in HSV is the intensity (brightness) that you can vary at will.

THANK YOU!!!! So simple, and works beautifully. I am very grateful for this information.

not sure if this is the effect you want, but with that code you are update the LEDs many times one by one very fast and you are stuck for short while in the loop even if the buttons did not change status.

if this is not what you wanted you could structure the code like

  if (buttonRed.fallingEdge()) {
    // fill the right leds with the right HSV (either your for loop or envision using the fill_solid() function)
    FastLED.show(); 
  }

  if (buttonRed.risingEdge()) {
    // fill the right leds with the right HSV (either your for loop or envision using the fill_solid() function)
    FastLED.show(); 
  }

you could also only read the pot values when necessary rather than at every loop

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.