How to add LED brightness control to this code

So I've got this code for a night light I'm working on. It will automatically turn on and off with day/night. There are three trim pots for settings - one for RGB cycle speed, one for LED brightness and one for the darkness setting for the on/off control. I have the code in for the brightness but the problem is I can't figure out where to insert the int for the brightness to change it.

I also can't seem to get the color cycling to go fast. With the speed pot turned to full it cycles pretty slow - about 3 minutes or so for a full cycle. I'm looking for like 15-20 seconds for a full cycle on max.

Here's the code:

// Outputs
const int redPin = 6;           // Red LED pin connected to digital output 6
const int grnPin = 5;           // Green LED pin connected to digital output 5
const int bluPin = 3;           // Blue LED pin connected to digital output 3

// Inputs
const int brtPin = A0;          // Brightness pot connected to A0
const int spdPin = A1;          // Speed pot hooked to A1
const int lghtPot = A2;         // Light setting pot hooked to A3
const int lghtPin = A3;         // Light sensor hooked to A3

// Smoothing settings for light sensor
const int numReadings = 100;    // Number of readings to average
int readings[numReadings];      // The readings from the analog input
int readIndex = 0;              // The index of the current reading
unsigned long total = 0;        // The running total
int average = 0;                // The average

int spdOutVal = 0;
int spdVal = 0;
int lghtPotVal = 0;
int lightPot = 0;
int lghtOutVal = 0;
int lghtVal = 0;
int brtPotVal = 0;
int brtVal = 0;
int brtOutVal = 0;

void color(int r, int g, int b)
{
  analogWrite(redPin, r);              // write current values to LED pins
  analogWrite(grnPin, g); 
  analogWrite(bluPin, b);  
}

void hsv(float H, float S, float V)
{
  // http://www.easyrgb.com/index.php?X=MATH&H=21#text21

  int var_i;
  float R, G, B, var_1, var_2, var_3, var_h;

  if (S == 0) {
    R = V;
    G = V;
    B = V;
  }
  else {
    var_h = H * 6;
    if (var_h == 6) var_h = 0;                          // H must be < 1
    var_i = int(var_h) ;                                // or ... var_i = floor( var_h )
    var_1 = V * (1 - S );
    var_2 = V * (1 - S * (var_h - var_i));
    var_3 = V * (1 - S * (1 - (var_h - var_i)));

    if (var_i == 0) {
      R = V;
      G = var_3;
      B = var_1;
    }
    else if (var_i == 1) {
      R = var_2;
      G = V;
      B = var_1;
    }
    else if (var_i == 2) {
      R = var_1;
      G = V;
      B = var_3;
    }
    else if (var_i == 3) {
      R = var_1;
      G = var_2;
      B = V;
    }
    else if (var_i == 4) {
      R = var_3;
      G = var_1;
      B = V;
    }
    else {
      R = V;
      G = var_1;
      B = var_2;
    }
  }

  color(255 * R, 255 * G, 255 * B);                // RGB results from 0 to 255
}

unsigned long time;

void setup() {
  Serial.begin(9600);                                                    // Initialze seial communication
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {  // Initialize all the readings to zero
    readings[thisReading] = 0;
  }
  pinMode(spdPin, INPUT);                       // Set speed pin to input
  pinMode(brtPin, INPUT);                       // Set the brightness pin to input
  pinMode(lghtPot, INPUT);                      // Set the light setting pot to input
  pinMode(lghtPin, INPUT);                      // Set the light sensor pin to input
  pinMode(redPin, OUTPUT);                      // Set red pin to output
  pinMode(grnPin, OUTPUT);                      // Set green pin to output
  pinMode(bluPin, OUTPUT);                      // Set blue pin to output
  time = millis();
}

void loop() {
  Serial.print("Speed Setting = ");
  Serial.print(spdVal);
  Serial.print("\t Speed = ");
  Serial.print(spdOutVal);
  Serial.print("\t Light Sensor Value = ");
  Serial.print(lghtVal);
  Serial.print("\t Light Pot Value = ");
  Serial.print(lghtPotVal);
  
  brtVal = analogRead(brtPotVal);               // Read the value of the brightness pot
  brtOutVal = map(brtVal, 0, 1023, 0, 255);     // Map the pot value to max PWM
  Serial.print("\t Brightness = ");
  Serial.print(brtOutVal);
  lghtPotVal = analogRead(lghtPot);             // Read the value of the light pot
  lghtVal = analogRead(lghtPin);                // Read the value of the light sensor

  // Averaging functions
  total = total - readings[readIndex];          // Subtract the last reading
  readings[readIndex] = analogRead(lghtVal);    // Read from the light sensor
  total = total + readings[readIndex];          // Add the reading to the total
  readIndex = readIndex + 1;                    // Advance to the next position in the array
  if (readIndex >= numReadings)  {              // If we're at the end of the array
    readIndex = 0;                              // Wrap around to the beginning
  }
  average = total / numReadings;                // Calculate the average
  Serial.print("\t Light Sensor Average = ");
  Serial.println(average);
  delay(1);                                     // Delay for stability
  if (average >= lghtPotVal) {                  // If the pot value is lower than the light sensor reading
  static float f = 0;                           // Run color cycling

  // Color cycling section
  spdVal = analogRead(spdPin);                  // Read speed control pin
  spdOutVal = map(spdVal, 1023, 0, 0, 100);     // Map sensor value to between 0 and 100ms
    if ((millis() - time) > spdOutVal) {        // Add output value in ms to formula
      f += 0.0005;
      if (f > 1) {
        f = 0;
      }
      hsv(f, 1, 1);
      time = millis();
   }
  }
    else{                                       // Otherwise turn LED's Off
      analogWrite(redPin, 1023);
      analogWrite(bluPin, 1023);
      analogWrite(grnPin, 1023);
  }
}

With, or without, all the serial printing?

That seems like an awful lot of code to do something relatively simple…

For your brightness, simply use the mapped value as a ‘multiplier’ when you write the PWM values to modify the relative brightness.

Keep in mind the PWM-to-LED brightness is non linear, you might like to consider a SINE lookup table to map the brightness value linearly.
RGB will likely track each colour slightly differently :slightly_frowning_face:
So three tables may help with that if needed.

Ok so I got rid of the serial printing and that sped it up a bit. However now when it's turned all the way slow I get a lot of blinking and flashing that seems to come and go only with the green and blue channels, specifically when they are fading in and out. It doesn't do it with red and also doesn't do it when the speed it turned up past about 1/3 of the way.

That's what I'm trying to do, I just can't figure out where it goes. I found the color cycling code online and then added the lights ensor and other stuff.

Just from the sound of it, arithmetic problems can cause the kinds of flashing you mention. Lots of different ones, integer overflow topping the list. Maybe then truncation. Then sign problems. etc. etc. Does it exhibit this unwelcome flashing behaviour all the time, or just intermittently?

Or, maybe the sensor code is making it hiccup by introducing short delays.

Can you post your latest code here (in code tags)… thanks

Wrong function.

You meant so say an exponential. For progressive increase, you just multiply the value by a fraction slightly greater than unity each time until you hit the limit. This can be done in integer arithmetic (of course) by a shift-and-add operation. Similarly for fading.

Ok the flickering was due to the pot for the light trigger being close to the light level in the room - I thought the averaging would take care of that, maybe I need to change the average count. I turned the pot and no more flickering at all.

Edit - changing the average count doesn't do much. Maybe I need to add a timer as well so that once the value goes over the set point wait 1 seconds or something to turn on

Here's the current code:

// Outputs
const int redPin = 6;           // Red LED pin connected to digital output 6
const int grnPin = 5;           // Green LED pin connected to digital output 5
const int bluPin = 3;           // Blue LED pin connected to digital output 3

// Inputs
const int brtPin = A0;          // Brightness pot connected to A0
const int spdPin = A1;          // Speed pot hooked to A1
const int lghtPot = A2;         // Light setting pot hooked to A2
const int lghtPin = A3;         // Light sensor hooked to A3

// Smoothing settings for light sensor
const int numReadings = 150;    // Number of readings to average
int readings[numReadings];      // The readings from the analog input
int readIndex = 0;              // The index of the current reading
unsigned long total = 0;        // The running total
int average = 0;                // The average

int spdOutVal = 0;
int spdVal = 0;
int lghtPotVal = 0;
int lightPot = 0;
int lghtOutVal = 0;
int lghtVal = 0;
int brtPotVal = 0;
int brtVal = 0;
int brtOutVal = 0;

void color(int r, int g, int b)
{
  analogWrite(redPin, r);              // write current values to LED pins
  analogWrite(grnPin, g); 
  analogWrite(bluPin, b);  
}

void hsv(float H, float S, float V)
{
  // http://www.easyrgb.com/index.php?X=MATH&H=21#text21

  int var_i;
  float R, G, B, var_1, var_2, var_3, var_h;

  if (S == 0) {
    R = V;
    G = V;
    B = V;
  }
  else {
    var_h = H * 6;
    if (var_h == 6) var_h = 0;                          // H must be < 1
    var_i = int(var_h) ;                                // or ... var_i = floor( var_h )
    var_1 = V * (1 - S );
    var_2 = V * (1 - S * (var_h - var_i));
    var_3 = V * (1 - S * (1 - (var_h - var_i)));

    if (var_i == 0) {
      R = V;
      G = var_3;
      B = var_1;
    }
    else if (var_i == 1) {
      R = var_2;
      G = V;
      B = var_1;
    }
    else if (var_i == 2) {
      R = var_1;
      G = V;
      B = var_3;
    }
    else if (var_i == 3) {
      R = var_1;
      G = var_2;
      B = V;
    }
    else if (var_i == 4) {
      R = var_3;
      G = var_1;
      B = V;
    }
    else {
      R = V;
      G = var_1;
      B = var_2;
    }
  }
  color(255 * R, 255 * G, 255 * B);                // RGB results from 0 to 255
}

unsigned long time;

void setup() {
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {  // Initialize all the readings to zero
    readings[thisReading] = 0;
  }
  time = millis();
}

void loop() {
  brtVal = analogRead(brtPotVal);               // Read the value of the brightness pot
  brtOutVal = map(brtVal, 0, 1023, 0, 255);     // Map the pot value to max PWM
  //Serial.print("\t Brightness = ");
  //Serial.print(brtOutVal);
  lghtPotVal = analogRead(lghtPot);             // Read the value of the light pot
  lghtVal = analogRead(lghtPin);                // Read the value of the light sensor

  // Averaging functions
  total = total - readings[readIndex];          // Subtract the last reading
  readings[readIndex] = analogRead(lghtVal);    // Read from the light sensor
  total = total + readings[readIndex];          // Add the reading to the total
  readIndex = readIndex + 1;                    // Advance to the next position in the array
  if (readIndex >= numReadings)  {              // If we're at the end of the array
    readIndex = 0;                              // Wrap around to the beginning
  }
  average = total / numReadings;                // Calculate the average
  if (average >= lghtPotVal) {                  // If the pot value is lower than the light sensor reading
  static float f = 0;                           // Run color cycling

  // Color cycling section
  spdVal = analogRead(spdPin);                  // Read speed control pin
  spdOutVal = map(spdVal, 1023, 0, 0, 250);     // Map sensor value to between 0 and 250ms
    if ((millis() - time) > spdOutVal) {        // Add output value in ms to formula
      f += 0.0005;
      if (f > 1) {
        f = 0;
      }
      hsv(f, 1, 1);
      time = millis();
   }
  }
    else{                                       // Otherwise turn LED's Off
      analogWrite(redPin, 1023);
      analogWrite(bluPin, 1023);
      analogWrite(grnPin, 1023);
  }
}

So I figured out the flickering - It's due to the averaging for the light sensor reading, the average goes above/below the threshold set by the pot and it flickers. Turning the pot down keeps it on steady. I need o figure out something else for the light sensor delay.

The speed control is working properly now that I removed all the serial print stuff.

I just need to figure out how to add brightness control and figure out a new way to delay the turn on/off to avoid flickering

Anyone? Bueller?

Ferris Bueller?

That'd be the reference lol

One word. Hysteresis.

Ok so I've come across the FastLED library and it works well - cycle speed is what I want. I see an option to control brightness but that's using WS2811 LED's. I'm currently using the "AnalogOutput" setup in my code.

Is there a way to implement brightness into the Fast LED library without needing to use WS2811? I have no problem buying them if it'll make it easy - Adafruit has 5mm ones for $1/ea but I also have a TON of regular RGB piranha LED's I'd like to use for something lol.

Here's the current code as of right now:

#include <FastLED.h>

#define REDPIN 3              // Red LED pin connected to digital output 6
#define GREENPIN 5            // Green LED pin connected to digital output 5
#define BLUEPIN 6             // Blue LED pin connected to digital output 3

const int brtPin = A0;          // Brightness pot connected to A0
const int spdPin = A1;          // Speed pot hooked to A1
const int lghtPot = A2;         // Light setting pot hooked to A2
const int lghtPin = A3;         // Light sensor hooked to A3

const int numReadings = 150;    // Number of readings to average
int readings[numReadings];      // The readings from the analog input
int readIndex = 0;              // The index of the current reading
unsigned long total = 0;        // The running total
int average = 0;                // The average

int spdOutVal = 0;
int spdVal = 0;

int lghtPotVal = 0;
int lightPot = 0;

int lghtOutVal = 0;
int lghtVal = 0;

int brtPotVal = 0;
int brtVal = 0;
int brtOutVal = 0;

// This function takes the incoming RGB values and outputs the values
// on three analog PWM output pins to the r, g, and b values respectively.
void showAnalogRGB(const CRGB& rgb)
{
  analogWrite(REDPIN, rgb.r);
  analogWrite(GREENPIN, rgb.g);
  analogWrite(BLUEPIN, rgb.b);
}
void setup() {
}

void loop() {
  brtVal = analogRead(brtPotVal);               // Read the value of the brightness pot
  brtOutVal = map(brtVal, 0, 1023, 255, 0);     // Map the pot value to max PWM
  lghtPotVal = analogRead(lghtPot);             // Read the value of the light pot
  lghtVal = analogRead(lghtPin);                // Read the value of the light sensor
  spdOutVal = analogRead(spdPin);
  spdVal = map(spdOutVal, 0, 1023, 150, 10);

  // Averaging functions
  total = total - readings[readIndex];          // Subtract the last reading
  readings[readIndex] = analogRead(lghtVal);    // Read from the light sensor
  total = total + readings[readIndex];          // Add the reading to the total
  readIndex = readIndex + 1;                    // Advance to the next position in the array
  if (readIndex >= numReadings)  {              // If we're at the end of the array
    readIndex = 0;                              // Wrap around to the beginning
  }
  average = total / numReadings;                // Calculate the average
  if (average >= lghtPotVal) {                  // If the pot value is lower than the light sensor reading
    static uint8_t hue;
    hue = hue + 1;
    showAnalogRGB( CHSV( hue, 255, 255) );      // Use FastLED automatic HSV->RGB conversion
    delay(spdVal);
   }
    else{                                       // Otherwise turn LED's Off
      analogWrite(REDPIN, 1023);
      analogWrite(BLUEPIN, 1023);
      analogWrite(GREENPIN, 1023);
  }
}

Sure, but as you may have noticed, the number of analog output capable pins is limited to a few. You need 3 to drive one RGB LED. In fact I have such an arrangement on my proto demo board. But due to the limited number of internal hardware timers on most processors, there is a practical limit to the number of PWM analog pins (therefore analog because that's how it's done).

I'm just not clear on why you need to use the FastLed library on what must be so few LEDs?

I plan on having all 4 hooked in parallel so they light up the same.

I don't need to use the Fast LED library, I just came across it while searching and it seems like a simple library to do what I want.

It almost seems like ditching the idea for adjustable brightness would be the easiest thing to do. The code already works perfectly sans dimming. I need to drive 4 LED's, I'm planning on putting two in parallel on each set of PWM outputs (2 on 3, 5, 6 and 2 on 9, 10, 11)

Okay, with MOSFET drivers? You know about the 20mA current limit on pins, right?

Is that on each pin?

Yes, the absolute max per pin is 40mA but that is a destructive limit. 20mA is a more reasonable working limit.