LED Fading problem

I’m trying to get a sketch to program my LED to simulate sunrise and sunset at preset time/durations.

I used this sketch on an internet site but the sunset (fading out) part is not working as intended. The white light will fade out then come on again followed by the blue lights fading out, afterwhich both lights will go out…

Please any expert help me check the code for problems. Thanks :slight_smile:

// Other variables. These control the behavior of lighting. Change these to customize behavoir
int minCounter = 0;         // counter that resets at midnight. Don't change this.
int blueStartMins = 580;    // minute to start blues. Change this to the number of minutes past midnight you want the blues to start.
int whiteStartMins = 600;   // minute to start whites. Same as above.
int bluePhotoPeriod = 720;  // photoperiod in minutes, blues. Change this to alter the total photoperiod for blues.
int whitePhotoPeriod = 620; // photoperiod in minutes, whites. Same as above.
int fadeDuration = 80;      // duration of the fade on and off for sunrise and sunset. Change this to alter how long the fade lasts.
int blueMax = 255;          // max intensity for blues. Change if you want to limit max intensity.
int whiteMax = 200;         // max intensity for whites. Same as above.

/****** LED Functions *********************************/
//function to set LED brightness according to time of day
//function has three equal phases - ramp up, hold, and ramp down
void setLed(int mins,    // current time in minutes
        int ledPin,  // pin for this channel of LEDs
        int start,   // start time for this channel of LEDs
        int period,  // photoperiod for this channel of LEDs
        int fade,    // fade duration for this channel of LEDs
        int ledMax   // max value for this channel
            )  {
  if (mins > start && mins <= start + fade)  {
    analogWrite(ledPin, map(mins - start, 0, fade, 0, ledMax));
  }
    if (mins > start + period && mins <= start + period - fade)  {
    analogWrite(ledPin, ledMax);
  }
    if (mins > start + period - fade && mins <= start + period)  {
    analogWrite(ledPin, map(mins - start + period - fade, 0, fade, ledMax, 0));
  }
}

We can’t see how you are calling this function, so we may not be all that helpful. There is nothing in this code that is specific to the color of an led.

One thing I would suggest that you do, though, is to look at the precedence rules for C operators. Is the precedence such that:

if (mins > start + period - fade && mins <= start + period)

does what you think you are trying to do.

Alternatively, you could skip the research on precedence and simply put parentheses in these statements to force the correct evaluation:

if ((mins > start + period - fade) && (mins <= start + period))

I forgot to add that the LEDs are controlled via Pin 9 (Blue) and 10 (White).

Anyway, thanks PaulS.

I'll try it :slight_smile:

I won’t be home to try the changes till a few days later. But I found the sketch on my laptop and the full version is attached.

Any other comments is greatly appreciated :slight_smile:

// Pins to control LEDs. Change these if you're using different pins.
int blueLed = 9;     // LED PWM channel for blues
int whiteLed = 10;   // LED PWM channel for whites

// Set up RTC
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68

// RTC variables
byte second, rtcMins, oldMins, rtcHrs, oldHrs, dayOfWeek, dayOfMonth, month, year;

// Other variables. These control the behavior of lighting. Change these to customize behavoir
int minCounter = 0;         // counter that resets at midnight. Don't change this.
int blueStartMins = 480;    // minute to start blues. Change this to the number of minutes past midnight you want the blues to start.
int whiteStartMins = 480;   // minute to start whites. Same as above.
int bluePhotoPeriod = 510;  // photoperiod in minutes, blues. Change this to alter the total photoperiod for blues.
int whitePhotoPeriod = 510; // photoperiod in minutes, whites. Same as above.
int fadeDuration = 60;      // duration of the fade on and off for sunrise and sunset. Change this to alter how long the fade lasts.
int blueMax = 255;          // max intensity for blues. Change if you want to limit max intensity.
int whiteMax = 255;         // max intensity for whites. Same as above.


/****** LED Functions ******/
/***************************/
//function to set LED brightness according to time of day
//function has three equal phases - ramp up, hold, and ramp down
void setLed(int mins,    // current time in minutes
            int ledPin,  // pin for this channel of LEDs
            int start,   // start time for this channel of LEDs
            int period,  // photoperiod for this channel of LEDs
            int fade,    // fade duration for this channel of LEDs
            int ledMax   // max value for this channel
            )  {
  if (mins > start && mins <= start + fade)  {
    analogWrite(ledPin, map(mins - start, 0, fade, 0, ledMax));
  }
    if (mins > start + period && mins <= start + period - fade)  {
    analogWrite(ledPin, ledMax);
  }
    if (mins > start + period - fade && mins <= start + period)  {
    analogWrite(ledPin, map(mins - start + period - fade, 0, fade, ledMax, 0));
  }
}

/***** RTC Functions *******/
/***************************/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers.
void setDateDs1307(byte second,        // 0-59
                   byte minute,        // 0-59
                   byte hour,          // 1-23
                   byte dayOfWeek,     // 1-7
                   byte dayOfMonth,    // 1-28/29/30/31
                   byte month,         // 1-12
                   byte year)          // 0-99
{
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.send(0);
   Wire.send(decToBcd(second));
   Wire.send(decToBcd(minute));
   Wire.send(decToBcd(hour));
   Wire.send(decToBcd(dayOfWeek));
   Wire.send(decToBcd(dayOfMonth));
   Wire.send(decToBcd(month));
   Wire.send(decToBcd(year));
   Wire.endTransmission();
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
          byte *minute,
          byte *hour,
          byte *dayOfWeek,
          byte *dayOfMonth,
          byte *month,
          byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  *second     = bcdToDec(Wire.receive() & 0x7f);
  *minute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}

void setup()  { 
  
// init I2C  
  Wire.begin();
} 

/***** Main Loop ***********/
/***************************/
void loop()  { 
  // get time from RTC and put in hrs and mins variables
  getDateDs1307(&second, &rtcMins, &rtcHrs, &dayOfWeek, &dayOfMonth, &month, &year);
  minCounter = rtcHrs * 60 + rtcMins;

  // determine if it is day or night, and act accordingly
  if ((minCounter > blueStartMins || minCounter > whiteStartMins)
           && (minCounter < blueStartMins + bluePhotoPeriod || minCounter < whiteStartMins + whitePhotoPeriod))  {   //day
    // set LED states
    setLed(minCounter, blueLed, blueStartMins, bluePhotoPeriod, fadeDuration, blueMax);
    setLed(minCounter, whiteLed, whiteStartMins, whitePhotoPeriod, fadeDuration, whiteMax);
  }
  else  {   //night
    analogWrite(blueLed, 0);
    analogWrite(whiteLed, 0);
  }
    
  // Get ready for next iteration of loop
  delay(1000);
}

Krub

Anyone help?
Thanks

Start with adding Serial.print statements in loop to show what values are being passed to the setLed function (what is minCounter).

Then, add Serial.print statements in setLed to show which of the three if tests are true. I suspect that on any one call to setLed you only want to execute one of the if blocks, but that you are executing more than one. The second and third ones should be executed (I think) only if the first is not (and the third should be executed only if the second is not).

In other words, I think you might need:
if()
{
// Do something
}
else if()
{
// Do something else
}
else if()
{
// Do something else
}

minCounter is reset to 0 at midnight every day and counts up from there.

I'll try yout suggestion. Thanks again PaulS :slight_smile: