Cant see wood for the trees, a little coding help please.

Hi guys,

so I'm now struggling with something that Im sure is easy... it's to do with fading LEDs, have searched like mad but just keep finding stuff related to;
A) the basic fade program
B) fade without delay sketch

what I want is for an alarm(LedOnAlarm) to trigger and turn LED on, then after a second "LedOffAlarm" fade it off over a 20 minute period, but I cant seem to figure what I need to do code-wise to do this.

I have combined and thinned out some pre-written code(see below), what I'd like is some help writing the
"LedOffAlarm" function that takes care of the fading part. I'm unsure if I need a counter-based approach or mapping approach...natural confusion in daily life is adding to my struggle.

Any/all help truly appreciated :slight_smile:

/*
 * TimeAlarmExample.pde
 *
 * This example calls alarm functions at 8:30 am and at 11:30 am 
 * and simulates turning lights on and off in the morning
 * A weekly timer is set for Saturdays at 8:30:30 (COMMENTED OUT)
 * I have modified this code to more suit my needs (Gibz73)
 */
 
  
#include <DS3232RTC.h>                      //Include the DS3231RTC library   //http://github.com/JChristensen/DS3232RTC
#include <Time.h>                           //Include the Time library        //http://www.arduino.cc/playground/Code/Time
#include <TimeAlarms.h>                     //Include the TimeAlarms library  //https://www.pjrc.com/teensy/td_libs_TimeAlarms.html
#include <Wire.h>                           //Include the Wire library
const int led = 9;                          //Declare led on pin 9
const int onboardPin = 13;

void setup()
{
     
  Serial.begin(9600);
  setSyncProvider(RTC.get);                         // the function to get the time from the RTC
  if(timeStatus() != timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");
        
  Alarm.alarmRepeat(8,30,0, LedOnAlarm);                // 8:30am every day
  Alarm.alarmRepeat(11,30,0,LedOffAlarm);                // 11:30am every day 
  //Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm);  // 8:30:30 every Saturday 
 
  pinMode(led, OUTPUT);                                   //Set led as output
  pinMode(onboardPin, OUTPUT);                            //Set onboard led as output
  digitalWrite(onboardPin, LOW);                          //Write led on pin 13 low before starting sketch
}

void  loop(){  
  digitalClockDisplay();                               //Call the clock display function
  Alarm.delay(1000);                                   // wait one second between clock display
}

/*******************************************************************************************************************
 * ****************************************************************************************************************/

// functions to be called when an alarm triggers:
void LedOnAlarm(){
  Serial.println("Alarm: - turn lights on");   
  analogWrite(led, 255); 
}
// PLEASE HELP ME MAKE THIS FUNCTION FADE LED OFF OVER 20 MINUTE PERIOD
void LedOffAlarm(){
  Serial.println("Alarm: - turn lights off");  
  analogWrite(led, 0);         
}

// Functions to display the clock
void digitalClockDisplay()
{
    // digital clock display of the time
    Serial.print(hour());
    printDigits(minute());
    printDigits(second());
    Serial.print(' ');
    Serial.print(day());
    Serial.print(' ');
    Serial.print(month());
    Serial.print(' ');
    Serial.print(year()); 
    Serial.println();  
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}
// PLEASE HELP ME MAKE THIS FUNCTION FADE LED OFF OVER 20 MINUTE PERIOD
void LedOffAlarm(){
  Serial.println("Alarm: - turn lights off");  
  analogWrite(led, 0);         
}

That function gets called ONCE. Do you really want it to take 20 minutes to return?

If so, use a for loop to iterate from 255 to 0, calling analogWrite() with the loop index, and adding a call to delay() to waste 20000/255 (78) microseconds per iteration of the loop.

Oh I dont know tbh, I forgot to mention Ive only been playing with arduino a cpl of mnths and had very little coding experience :-/

Given the use of the RTC and the alarmTime lib, what is the easiest way to have the LED fade off over a 20 minute period?

So;

first alarm turns LED on
seconnd alarm fades LED off over 20 mins...

and thats it for the day then, until same times next day.

Thank you.

if you was using the main loop to control the led or a function that was called every loop then something like this would be my approach

 if (ledLevel != 0) {
    if (currentMillis - previousMillis > 4706L) {
      ledLevel--;
      previousMillis = currentMillis;
    }
  }
  analogWrite(led, ledLevel);

as long as the delay is equal to less than 2^15-1 you don't need the L suffix.

(currentMillis - previousMillis > 4706)

what is the easiest way to have the LED fade off over a 20 minute period?

Given a watch and a potentiometer, how would YOU turn the brightness down over a 20 minute period?

At specific times, you set the potentiometer to specific values. It's easiest of the 20 minute time frame is all in the same hour, and starts when seconds is 0, but it can be done even if the fading is supposed to be from 10:47:14 to 11:07:13.

micros() and millis() both return unsigned long. I make all time related variables unsigned long as well for math consistency.

aarg:
as long as the delay is equal to less than 2^15-1 you don't need the L suffix.

(currentMillis - previousMillis > 4706)

I made a mistake a while back where I wasted hours trying to work out the problem with a timer. Now I just add the L as force of habit. I figure its doing no harm even if its not needed. I really should be adding a UL I guess.

PaulS:
Given a watch and a potentiometer, how would YOU turn the brightness down over a 20 minute period?

At specific times, you set the potentiometer to specific values. It's easiest of the 20 minute time frame is all in the same hour, and starts when seconds is 0, but it can be done even if the fading is supposed to be from 10:47:14 to 11:07:13.

Hi Paul,

indeed thats the way I'd look at in terms of problem solving...ergo;

have multiple alarms over a 20 minute period setting a new analogWrite value each time???

That could work yes? OR, is there a way to map 255-0 over 20 minutes that Im too ignorant to work out? (I'm thinking a yes to that one)

Thank you all for the help, please continue as I think I may need baby-walking through this :confused:

gpop1:
I made a mistake a while back where I wasted hours trying to work out the problem with a timer. Now I just add the L as force of habit. I figure its doing no harm even if its not needed. I really should be adding a UL I guess.

It's actually smarter to display the derivation of the numbers by letting the compiler do the math.

(currentMillis - previousMillis >= 20*60*1000L/256)

Notice that I divided by 256, not 255. Also use greater than or equal to compare.

gpop1:
if you was using the main loop to control the led or a function that was called every loop then something like this would be my approach

 if (ledLevel != 0) {

if (currentMillis - previousMillis > 4706L) {
     ledLevel--;
     previousMillis = currentMillis;
   }
 }
 analogWrite(led, ledLevel);

Hi thanks, if I took this approach am I right in thinking I just need to declare LedLevel in globals, and set a prevMillis = 0; too?

Gibz73:
Hi thanks, if I took this approach am I right in thinking I just need to declare LedLevel in globals, and set a prevMillis = 0; too?

Isn't interesting that simple math problems are so difficult to convert to code ?
You will be disappointed with results since LED brightens in NOT linear with applied voltage.

Vaclav:
Isn't interesting that simple math problems are so difficult to convert to code ?
You will be disappointed with results since LED brightens in NOT linear with applied voltage.

It is closer to linear when PWM is used to modulate the brightness.

Vaclav:
Isn't interesting that simple math problems are so difficult to convert to code ?
You will be disappointed with results since LED brightens in NOT linear with applied voltage.

Thats ok, I'm just trying to get the coding bit sorted...eventually I want to apply it using pwm to a constant current LED driver(that has pwm pin) with super bright LEDs.

Trying to get little bits learnt as I go, you know :slight_smile:

@gpopl, tried tha with these bits of code added;

int ledLevel = 0;
unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
if (ledLevel != 0) {
    if (currentMillis - previousMillis >= 20*60*1000L/256) {
      ledLevel--;
      previousMillis = currentMillis;
    }
  }
  analogWrite(led, ledLevel);

All that happened was LED flashed and went off....what have I done wrong there?

@Paul, would still love to know how I'd map it properly cough, hint hin :wink:

It's time to post the entire program again. It's too hard to guess where changes have been made.
Also, I see that you have included the time library. You can use the predefined constants to make this statement even more readable, and also solve the problem of data type, since SECS_PER_MIN is already defined as UL.

if (currentMillis - previousMillis >= 20*SECS_PER_MIN *1000/256) {

aarg:
It's time to post the entire program again. It's too hard to guess where changes have been made.
Also, I see that you have included the time library. You can use the predefined constants to make this statement even more readable, and also solve the problem of data type, since SECS_PER_MIN is already defined as UL.

if (currentMillis - previousMillis >= 20*SECS_PER_MIN *1000/256) {

Here ya go

/*
 * TimeAlarmExample.pde
 *
 * This example calls alarm functions at 8:30 am and at 11:30 am 
 * and simulates turning lights on at night and off in the morning
 * A weekly timer is set for Saturdays at 8:30:30 (COMMENTED OUT)
 * I have modified this code to more suit my needs (Gibz73)
 */
 
  
#include <DS3232RTC.h>                      //Include the DS3231RTC library   //http://github.com/JChristensen/DS3232RTC
#include <Time.h>                           //Include the Time library        //http://www.arduino.cc/playground/Code/Time
#include <TimeAlarms.h>                     //Include the TimeAlarms library  //https://www.pjrc.com/teensy/td_libs_TimeAlarms.html
#include <Wire.h>                           //Include the Wire library
const int led = 9;                          //Declare led on pin 9
const int onboardPin = 13;
int ledLevel = 0;
unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
void setup()
{
     
  Serial.begin(9600);
  setSyncProvider(RTC.get);                         // the function to get the time from the RTC
  if(timeStatus() != timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");
        
  Alarm.alarmRepeat(8,30,0, LedOnAlarm);                // 8:30am every day
 // Alarm.alarmRepeat(11,30,0,LedOffAlarm);                // 11:30am every day 
  //Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm);  // 8:30:30 every Saturday 
 
  pinMode(led, OUTPUT);                                   //Set led as output
  pinMode(onboardPin, OUTPUT);                            //Set onboard led as output
  digitalWrite(onboardPin, LOW);                          //Write led on pin 13 low before starting sketch
}

void  loop(){  
  digitalClockDisplay();                               //Call the clock display function
  Alarm.delay(1000);                                   // wait one second between clock display
if (ledLevel != 0) {
    if (currentMillis - previousMillis >= 20*60*1000L/256) {
      ledLevel--;
      previousMillis = currentMillis;
    }
  }
  analogWrite(led, ledLevel);

}

/*******************************************************************************************************************
 * ****************************************************************************************************************/

// functions to be called when an alarm triggers:
void LedOnAlarm(){
  Serial.println("Alarm: - turn lights on");   
  analogWrite(led, 255); 
}

// Functions to display the clock
void digitalClockDisplay()
{
    Serial.print(hour());
    printDigits(minute());
    printDigits(second());
    Serial.print(' ');
    Serial.print(day());
    Serial.print(' ');
    Serial.print(month());
    Serial.print(' ');
    Serial.print(year()); 
    Serial.println();  
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

I really do appreciate all help :slight_smile:

I don't see any call to millis() in loop().

Should I alter this line

unsigned long currentMillis = millis();

to read;

unsigned long currentMillis = 0;

then go;

currentMillis = millis();

in void loop()?

Help, I'm drowning :smiley:

if (ledLevel != 0) {
    if (currentMillis - previousMillis >= 20*60*1000L/256) {
      ledLevel--;
      previousMillis = currentMillis;
    }
  }
  analogWrite(led, ledLevel);

Since ledLevel is initially set to 0, the first if statement will never be true.

You need to set ledLevel to 255 in LEdOnAlarm (and use that value in the analogWrite() statement).

And, as aarg points out, you need to assign a value to currentMillis.

Those lines are not in loop().