Problem fading LEDs on and off based on motion detection

Hi all,

First of all, I’d just like to say hi as I am a new member here. I am fairly new to arduino, and only have a limited experience with coding in general so I thought this forum would be a great place to come for help with my projects.

This first project I’m working on is fairly simple. Basically, I just have a motion detector that, once it detects motion, will fade on LED lights over a period of maybe 2 seconds. As long as motion is detected, the lights will stay on. When motion is no longer detected, there is a 15 second delay before the lights fade off over a period of maybe 3 seconds.

I started off with a basic code to just turn the lights on and off based on the above description and it has worked flawlessly so far.

int LEDPin = 11; //LED output
int pirPin = 2; //Motion detection input
int motionDetect = 0; //Motion detection variable

int count = 0; //Counter for turning off lights

void setup(){
pinMode(LEDPin, OUTPUT); // LED lighting output assign
pinMode(pirPin, INPUT); // Motion detection input assign
}

//--------------------------------------------------------------------------------------------------------------------------------

//A motion sensor will detect movement, which will fade on the LED lights, and keep them lit as long as motion is detected.
//When motion is no longer detected, a counter will begin. Once the counter has reached 15 with no motion detected, the lights will fade off.

//----------------------------------------------------------------------------------------------------------------------------------

void loop()

{
motionDetect = digitalRead(pirPin);
if (motionDetect == HIGH){
analogWrite(LEDPin, 255);
count = 0;
}
else {
delay(1000);
count = count+1;
}
while(count > 15){
analogWrite(LEDPin, 0);
count = 0;
}
}

The trouble I’m having is when I try to incorporate a fading feature to the LED lights. I had tried some slightly more complicated equations that I found from various tutorials on how to make a “breathing” LED light, but I just couldn’t get it to work properly so I tried something more simple to see if I could that working first, and then maybe build back to up more complicated equations. So I just added a simple loop, where every pass through the loop will increase the brightness of the LED light, but for whatever reason, even this won’t work. I’ve tried numerous variations of this type of loop, but I just cant see to get it to work properly.

int LEDPin = 11; //LED output
int pirPin = 2; //Motion detection input
int motionDetect = 0; //Motion detection variable

int count = 0; //Counter for turning off lights
int brightness = 0; //Brightness variable

void setup(){
pinMode(LEDPin, OUTPUT); // LED lighting output assign
pinMode(pirPin, INPUT); // Motion detection input assign
}

//--------------------------------------------------------------------------------------------------------------------------------

//A motion sensor will detect movement, which will fade on the LED lights, and keep them lit as long as motion is detected.
//When motion is no longer detected, a counter will begin. Once the counter has reached 15 with no motion detected, the lights will fade off.

//----------------------------------------------------------------------------------------------------------------------------------

void loop()

{
motionDetect = digitalRead(pirPin);
if (motionDetect == HIGH && brightness < 255){
analogWrite(LEDPin, brightness);
brightness = brightness + 1;
delay(100);
}

if (motionDetect == HIGH){
analogWrite(LEDPin, 255);
count = 0;
}
else {
delay(1000);
count = count+1;
}
while(count > 15){
analogWrite(LEDPin, 0);
count = 0;
}
}

In this particular version, for instance, when motion is detected, the lights will fade in for just a couple steps and then suddenly jump to full max brightness. This is the closest I’ve gotten to my goal, but it’s still not where I want it to be.

Does anybody have any idea what I’m doing wrong in my sketch? I’m open to other ideas as well, if somebody knows of a better way to create a smooth transition from lights off to lights at max brightness over a 2 -3 second period, and vice versa.

Thanks in advance for any help you guys can provide.

Try and read you code like a book.
With that last code, if motionDetect is high it writes the brightness variable, delays for a short time and then immediately sets it to full brightness and then turns it off.
This is a million miles from what you want to do.

The other thing is modify that post and remove the quote tags and replace them with code tags, the # key next to the quote icon.

you can look at a state change with the motion detection.

of course you can substitute any fade function you want…

like this (untested):

#include <math.h>

int LEDPin = 11;                    //LED output
int pirPin = 2;                     //Motion detection input
int oldMotion; 
int motionState;
unsigned long startTime;

int count = 0;                      //Counter for turning off lights

void setup()
{
  pinMode(LEDPin, OUTPUT);          // LED lighting output assign
  pinMode(pirPin, INPUT);           // Motion detection input assign
}

void loop()
{  
  int motionDetect = digitalRead(pirPin);
  if (motionDetect)
  {
    if (oldMotion == LOW)
    {
      motionState = 1;
      startTime = millis();
    }
  }
  oldMotion = motionDetect;
  if (motionState)
  {
    fadeLed();
  }
}

void fadeLed()
{
  if (millis() - startTime <= 3000UL) //3 seconds of pulsing light
  {
    float val = (exp(sin(millis()/2000.0*PI)) - 0.36787944)*108.0;
    analogWrite(LEDPin, val);
  }
  else
  {
    motionState = 0;
  }
}

Hey all,

I’ve been away for a while. I had some other things come up that distracted me from working on this, but I have some free time again, so I thought I’d take another crack at this. My updated code is below. I took the advice of using a state change. It now works to detect motion and fade the lights on, but fading off is a little funny, and I’m not sure where I’m going wrong there. As I mentioned, the fading on of the lights works fine, but then the lights just stay on for somewhere around 1 minute (even with no motion being detected). Eventually, the lights start fading down very very very slowly until they are just a very dim light, but they never completely turn off. (Actually, now that I think about it, the lights may have actually started dimming down at the correct time (approximately 15 seconds), but it happens so slowly my eyes didn’t notice). When I wave my hand in front of the sensor, the lights fade back on to full brightness, so it seems that it’s only the fading off portion that isn’t working correctly, but I’m not sure where I’m going wrong.

Any advice?

Thank you

int LEDPin = 11;                    //LED output
int pirPin = 2;                     //Motion detection input
int motionDetect = 0;               //Motion detection variable

int count = 0;                      //Counter for turning off lights
int brightness = 0;                 //Brightness variable
int state = 0;                      //On/off state

void setup(){
  pinMode(LEDPin, OUTPUT);          // LED lighting output assign
  pinMode(pirPin, INPUT);           // Motion detection input assign
}

//--------------------------------------------------------------------------------------------------------------------------------

//A motion sensor will detect movement, which will fade on the LED lights, and keep them lit as long as motion is detected.
//When motion is no longer detected, a counter will begin.  Once the counter has reached 15 with no motion detected, the lights will fade off.

//----------------------------------------------------------------------------------------------------------------------------------

void loop()

{  
  motionDetect = digitalRead(pirPin);
  if (motionDetect == HIGH){
    state = 1;
  }
  if (state == 1 && brightness < 255){
    analogWrite(LEDPin, brightness);
    brightness = brightness + 1;
    delay(10);
  }
    if (motionDetect == HIGH){
       count = 0;
     }
     else {
       delay(1000);
       count = count + 1;
     }  
    if (count >= 15){
      state = 0;
    }
    if (state == 0 && brightness > 0){
      analogWrite(LEDPin, brightness);
      brightness = brightness - 1;
      count = 0;
    }
  }

how about using constrain?

untested, but compiles

#define FADE_VALUE 5
#define FADE_INCREMENT_TIME 10UL
//
int LEDPin = 11;                    //LED output
int pirPin = 2;                     //Motion detection input
//int motionDetect = 0;               //Motion detection variable
//int count = 0;                      //Counter for turning off lights
int brightness = 0;                 //Brightness variable
int state = 0;                      //On/off state

void setup()
{
  pinMode(LEDPin, OUTPUT);          // LED lighting output assign
  pinMode(pirPin, INPUT);           // Motion detection input assign
}

void loop()

{  
  state = digitalRead(pirPin) == HIGH ? FADE_VALUE : - FADE_VALUE;
  fadeMyLed(state);
}

void fadeMyLed(int increment)
{
  static unsigned long lastIncrementTime;
  if (millis() - lastIncrementTime >= FADE_INCREMENT_TIME)
  {
    analogWrite(LEDPin, constrain((brightness + increment), 0, 255));
    lastIncrementTime += FADE_INCREMENT_TIME;
  }
}

I tried out your code and, unfortunately, it also doesn't work. It simply turns the light on and off; there is no observable fading.

But I've been looking at your code, and I have to be honest, I'm not really understanding what it's doing. I blame this on my own lack of knowledge, not anything against you. For one, I've never used the constrain function before, so I'm not sure what it's purpose is. If you're willing, could you step me through your code to help me better understand what's going on?

Thanks

constrain does what it sounds like

myValue = constrain(thisNumber, noLowerThanThis, noHigherThanThis)

try it... compile and run this several times, changing the value of myValue (within the range of an int).

int myValue = 1000;

void setup()
{
  Serial.begin(9600);
  myValue = constrain(myValue, 0,255);
  Serial.println(myValue);
}

void loop()
{
  
}

here is more on the code:

#define FADE_VALUE 5               // Compiler will replace FADE_VALUE with the integer 5 everytime it occurs after this
#define FADE_INCREMENT_TIME 10UL   // Compiler will replace FADE_INCREMENT_TIME with the unsigned long integer 10 everytime it occurs after this
//
int LEDPin = 11;                    //LED output
int pirPin = 2;                     //Motion detection input
//int motionDetect = 0;             //Motion detection variable
//int count = 0;                    //Counter for turning off lights
int brightness = 0;                 //Brightness variable
int state = 0;                      //On/off state

void setup()
{
  pinMode(LEDPin, OUTPUT);          // LED lighting output assign
  pinMode(pirPin, INPUT);           // Motion detection input assign
}

void loop()

{  
  state = digitalRead(pirPin) == HIGH ? FADE_VALUE : - FADE_VALUE;  //if the pin is HIGH make state 5, otherwise make it -5
  fadeMyLed(state);  // run the function below
}

void fadeMyLed(int increment)
{
  static unsigned long lastIncrementTime;  // declaring a local variable for the timer in this function
  if (millis() - lastIncrementTime >= FADE_INCREMENT_TIME)  // This is a timer that essentialy uses the millis() counter to look for 10UL milliseconsd of time passing
  {
    analogWrite(LEDPin, constrain((brightness + increment), 0, 255)); set the LEDpin but dont let the value go below zero or above 255
    lastIncrementTime += FADE_INCREMENT_TIME;  // reset the timer to occur again in 10 milliseconds
  }
}

try making the FADE_INCREMENT_TIME bigger like... 100UL for example.

I appreciate the help going through your code. I think I understand most of what's going on now. It seems like it should work, however, it still doesn't produce any observable fading. I've tried changing FADE_INCREMENT_TIME from 1UL up to 10000UL and it doesn't affect the fading. It only affects the time between when motion is detected and the lights switch on, and how long it takes the lights to turn off.

I've been going through my code and your code numerous times, and as best I can tell, it seems like it should work, but it's just not producing the desired fading effect. I'm still not sure what's going on. Any other suggestions?

here you go... I fixed it for you, tested it... it works.

#define FADE_VALUE 10               // Compiler will replace FADE_VALUE with the integer 5 everytime it occurs after this
#define FADE_INCREMENT_TIME 25UL   // Compiler will replace FADE_INCREMENT_TIME with the unsigned long integer 10 everytime it occurs after this
//
int LEDPin = 11;                    //LED output
int pirPin = 2;                     //Motion detection input
//int motionDetect = 0;             //Motion detection variable
//int count = 0;                    //Counter for turning off lights
int brightness = 0;                 //Brightness variable
int state = 0;                      //On/off state

void setup()
{
  pinMode(LEDPin, OUTPUT);          // LED lighting output assign
  pinMode(pirPin, INPUT);           // Motion detection input assign
  digitalWrite(LEDPin,HIGH);
}

void loop()

{  
  fadeMyLed(digitalRead(pirPin) == HIGH ? FADE_VALUE :  -FADE_VALUE);  // run the function below
}

void fadeMyLed(int increment)
{
  static unsigned long lastIncrementTime;  // declaring a local variable for the timer in this function
  if (millis() - lastIncrementTime >= FADE_INCREMENT_TIME)  // This is a timer that essentialy uses the millis() counter to look for 10UL milliseconsd of time passing
  {
    brightness = brightness + increment;
    analogWrite(LEDPin, constrain((brightness), 0, 255)); //set the LEDpin but dont let the value go below zero or above 255
    lastIncrementTime =millis();  // reset the timer to occur again in 10 milliseconds
  }
}

Well, I’m not sure what I’m doing differently from you, but it’s not working for me. I’m using your code without any changes, and it’s not working as expected. The motion sensor seems to have no effect. It simply counts for a couple minutes, then turns the lights on, then counts for another couple minutes, and fades the lights off, then repeats. I’m not sure what’s going on there.

I tried taking another stab at this myself, by building up the code state by state. I started with the fade on (State 1), then added the fade off (State 3), then added the off state (State 0), and finally added the timer state (State 2). States 0, 1, and 3 work exactly as I want them to. The lights fade on when motion is detected, then fade off, and stay off until motion is detected again. However, when I try to add the 15 second timer, it throws everything out of whack, and I’m not sure why. The intent of the timer is to keep the lights on until no motion has been detected for 15 seconds. I turned off that section in the code below. Any thoughts?

int LEDPin = 11;
int pirPin = 2;
int MotionDetect = 0;
int MDState = 0;
int brightness = 0;
int count = 0;

void setup(){
  pinMode(LEDPin, OUTPUT);
  pinMode(pirPin, INPUT);
}

//-----------------------------------------------------------------------------------------------------------------------------
// code for LED fades on
//-----------------------------------------------------------------------------------------------------------------------------

void fadeOnLED(){
  analogWrite(LEDPin, constrain((brightness), 0, 256));
  brightness ++;
  delay(20);
  if (brightness == 256){
    MDState = 2;
  }
}
//-----------------------------------------------------------------------------------------------------------------------------
// code for LED fades off
//-----------------------------------------------------------------------------------------------------------------------------

void fadeOffLED(){
  analogWrite(LEDPin, constrain((brightness), 0, 256));
  brightness --;
  delay(5);
  if (brightness == 0){
    MDState = 0;
  }
}
//-----------------------------------------------------------------------------------------------------------------------------
// code for timer
//-----------------------------------------------------------------------------------------------------------------------------

void timer(){
     if (MotionDetect == HIGH){
       count = 0;
     }
     else {
       delay(1000);
       count ++;
     }
  }
//-----------------------------------------------------------------------------------------------------------------------------

void loop(){
  MotionDetect = digitalRead(pirPin);
  if (MotionDetect == HIGH){
    MDState = 1;
    }
  while (MDState == 1 && brightness < 256){
    fadeOnLED();
  }
//  while (MDState == 2 && count < 15){
//    brightness = 256;
//    analogWrite(LEDPin, brightness);
//    timer();
//  }
  MDState = 3;
  while (MDState == 3 && brightness > 0){
    fadeOffLED();
  }
  if (MDState == 0){
    brightness = 0;
    analogWrite(LEDPin, brightness);
  }
}

The motion sensor seems to have no effect

I'd suggest that you need to work out YOUR issues with the PIR sensor, then.