Output fading for use with PIR sensor

Hi,

I am currently trying to solve a problem and wanted to see if somebody could help me. I am currently using 'map' to turn a led off when my PIR sensor is activated. I now want it to fade off slowly but cant see a way of doing this with 'map'.

Any help or suggestions would be much appreciated, the code is below:

const int analogInPin = A0;  // Analog input pin that the PIR is attached to
const int analogOutPin = 9; // Analog output pin that the LED is attached to

int sensorValue = 0;        // value read from the PIR
int outputValue = 0;        // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(analogInPin);            
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 1023, 255, 0);  
  // change the analog out value:
  analogWrite(analogOutPin, outputValue);           

  // print the results to the serial monitor:
  Serial.print("sensor = " );                       
  Serial.print(sensorValue);      
  Serial.print("\t output = ");      
  Serial.println(outputValue);   

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:
  delay(20);    
  if (outputValue==0);

}

Thanks, Sam.

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

When the PIR sensor is activated set a variable to indicate it and a second variable to 255.
Each time through loop() when activated is true, analog output the second variable, decrement it and wait a while

What should happen if the PIR is deactivated whilst the LED is fading ?
What should happen once the LED has completely faded ?

Hi,

the map function you are using converts the sensor value to another range. This range you are using to lighten up a LED. This should work so far. The fading effect cannot be achieved by the map function. If it gets the same value again, it will map it to the same output, easy isn't it?

So what you need in order to do fading is a loop right after the outputValue = map(sensorValue, 0, 1023, 255, 0); line.
The code would look like

for(int i = outputValue; i >= 0; i--)
    analogWrite(analogOutPin, outputValue);

maybe a very small delay inside the loop will be necessary (otherwise the loop is too fast). However, this will slow down your code; In a worst case for 256ms (1ms per loop iteration).
If you want it faster, you can try to subtract more than one (ie i -= 10).

The result of the inserted loop will merely create a heartbeat (like you know it from the product with the fruit on top), because the sensor value does not change as fast as you come to the "read"-line again.

I hope I understood your question in a right way.

UKHeliBob:
What should happen if the PIR is deactivated whilst the LED is fading ?
What should happen once the LED has completely faded ?

Hi Bob,

Thank you for your response.
I would like the fade to complete and then the LED to stay off for a minute before reading the sensor. I would also like the LED to fade back on if PIR is neutral after the 1 minute.

Should i use another method for achieving this. Or can i add arguments to the code i have already?

Thanks again for helping it is much appreciated.

Sam.

If I were you I would do this by using a state machine

State 1 - LED is on and waiting for PIR input. When PIR input is triggered move to state 2
State 2 - fade LED down one step each time through loop using millis() as a timer. When the LED is off move to state 3
State 3 - wait for 1 minute using millis() as a timer then move to state 4
State 4 - test PIR. If inactive move to state 5, otherwise stay in this state
State 5 - fade LED up one step each time through loop using millis() as a timer. When the LED is on move to state 1

Doing this using millis() means that the code is non blocking and can test for the events that trigger a change of state each time through loop() as well as timing the intervals between fade steps. A convenient way to do this is to use select/case base on the value of a state variable. I find this easier to read and follow than multiple if/else statements.

Look at the BlinkWithoutDelay example in the IDE for an application of this idea.

UKHeliBob:
If I were you...

Bob,

Thank you so much for your help. I really appreciate it.

Have a good week.

Sam.

UKHeliBob:
If I were you I would do this by using a state machine

State 1 - LED is on and waiting for PIR input. When PIR input is triggered move to state 2
State 2 - fade LED down one step each time through loop using millis() as a timer. When the LED is off move to state 3
State 3 - wait for 1 minute using millis() as a timer then move to state 4
State 4 - test PIR. If inactive move to state 5, otherwise stay in this state
State 5 - fade LED up one step each time through loop using millis() as a timer. When the LED is on move to state 1

Doing this using millis() means that the code is non blocking and can test for the events that trigger a change of state each time through loop() as well as timing the intervals between fade steps. A convenient way to do this is to use select/case base on the value of a state variable. I find this easier to read and follow than multiple if/else statements.

Look at the BlinkWithoutDelay example in the IDE for an application of this idea.

Thanks Bob,

Heres the code if anyone needs to do this in the future:

// This example code is in the public domain.
 


// These constants won't change.  They're used to give names
// to the pins used:
const int analogInPin = A0;  // Analog input pin that the PIR is attached to
const int analogOutPin = 9; // Analog output pin that the LED is attached to

int sensorValue = 0;        // value read from the PIR
int outputValue = 0;        // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  analogWrite(analogOutPin, 255);  //set the LED at high
}

void loop() {

  sensorValue = analogRead(analogInPin); // The sensor value is equal to the analog input A0           

  if (sensorValue > 500) { //if the value of A0 is more than 500
    
    Serial.print("fading out..." ); // print fading... into the serial window
     Serial.println(sensorValue ); // also print the sensor value into the serial window

    for (int i=255;i>0;i--){ //fade out from HIGH to LOW 
      analogWrite(analogOutPin, i); //write from the pwm 9
      delay(15); //speed of the fade
     
    }
     delay (10000); // delay 10000 
      
for (int i=0;i<255;i++){ //fade out from LOW to HIGH 
      analogWrite(analogOutPin, i); //write from the pwm 9
      delay(15); //speed of the fade
}  
  
} else {
     Serial.println("waiting..." );  
  analogWrite(analogOutPin, 255); 
     delay (1); 
  
    }
 
  // print the results to the serial monitor:
  Serial.print("sensor = " );                       
  Serial.print(sensorValue);      
  Serial.print("\t output = ");      
  Serial.println(outputValue);   

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:
  delay(20);    
  if (outputValue==0);
    delay (10); // delay 1000 before 

}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

     delay (10000); // delay 10000

Really? I'd never have guess that that was what that function did.

 if (outputValue==0);

If outputValue is 0, do nothing. Otherwise, do nothing. Hmmm, doesn't seem too useful.

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:
  delay(20);

So, why don't you wait for 2 milliseconds?

 delay (10); // delay 1000 before

Can you guess what this line does though ?

Despite the advice given I am disappointed to see the use of delay() instead of millis() for timing. It may not matter in this code but it will at some time so better to understand it and use it in my view. There is also a noticeable lack of the use of states to control what is happening in the program, not to mention that the code does not actually do what was required because it does not test the PIR input before fading up the LED, but never mind.

Can you guess what this line does though ?

I thought that I had picked on OP enough. I actually had copied and pasted that, and added a comment, but then deleted it. Sometimes I can be a nice guy. 8)

This is almost exactly what I want to do, the only difference is I want the fade the other way round. I want to start with the LED low, and then when the PIR is triggered, I want the LED to fade up, wait, and then fade back down again. Being a complete newbie at this, can anyone suggest how I would alter the code?

Many thanks

can anyone suggest how I would alter the code?

This whole thread has been full of suggestions as to how to alter the code. Have you implemented any of them. If not, get busy.

If you have, post the code you have now.

Reversing a for loop is nearly trivial, no matter how it is implemented.

Well I've had a bit of a fiddle around and I'm nearly there, all I need to add is a function where if the PIR is still being triggered, then it shouldn't fade back down until there is no movement.

// This example code is in the public domain.
 


// These constants won't change.  They're used to give names
// to the pins used:
const int analogInPin = A0;  // Analog input pin that the PIR is attached to
const int analogOutPin = 9; // Analog output pin that the LED is attached to

int sensorValue = 0;        // value read from the PIR
int outputValue = 0;        // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  analogWrite(analogOutPin, 10);  //set the LED at high
}

void loop() {

  sensorValue = analogRead(analogInPin); // The sensor value is equal to the analog input A0           

  if (sensorValue > 500) { //if the value of A0 is more than 500
    
    Serial.print("fading out..." ); // print fading... into the serial window
     Serial.println(sensorValue ); // also print the sensor value into the serial window

   for (int i=0;i<255;i++){ //fade out from LOW to HIGH 
      analogWrite(analogOutPin, i); //write from the pwm 9
      delay(5); //speed of the fade
     
    }
     delay (2000); // delay 10000 
       
for (int i=255;i>10;i--){ //fade out from HIGH to LOW
      analogWrite(analogOutPin, i); //write from the pwm 9
      delay(5); //speed of the fade
}  
  
} else {
     Serial.println("waiting..." );  
  analogWrite(analogOutPin, 10); 
     delay (1); 
  
    }
 
  // print the results to the serial monitor:
  Serial.print("sensor = " );                       
  Serial.print(sensorValue);      
  Serial.print("\t output = ");      
  Serial.println(outputValue);   

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle
  // after the last reading:
 delay(2);    
 if (outputValue==0);
 delay (1000); // delay 1000 before 

}
[code/]
 if (outputValue==0);

If the value is 0, do nothing. Otherwise, do nothing. Does it really matter WTF the value in outputValue is?

A PIR is a digital device. There is movement being sensed or there isn't. Reading digital input on an analog pin is wrong.