I was hoping to get some help on the fading led which I am working on.
For my project I need to have a led, which when it is placed next to a magnet, continuously shines, but as soon as it is taken away it has to fade out in a certain amount of time. So far I managed to write the code which detects when the light is taken away from the magnet and fades out, but when the magnet is nearby again, the led lights up and keeps shining, no matter if I take it away from the magnet or not. So how I could solve this? I tried to exit the loop function, but then this process happens only once, which is not what I want. I am also using reed switch to detect the magnet, but if you have other sensor suggestions, let me know. I'm including the code down here.
Thank you for your help in advance:)
int ledPin = 9;
int brightness = 255;
int fadeAmount = 5;
const int reedPin = 2;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(reedPin, INPUT_PULLUP);
}
void loop() {
int proximity = digitalRead(reedPin);
if (proximity == HIGH) {
Serial.println("Switch opened");
while (brightness >= 0) {
analogWrite(ledPin, brightness);
brightness = brightness - fadeAmount;
delay(30);
Serial.println(brightness);
}
}
else {
Serial.println("Switch closed");
analogWrite(ledPin, brightness);
Serial.println(brightness);
}
}
1 Answer 1
Your current problem probably comes from the fact, that you execute the fading loop, even if brightness
is already zero, and that you don't reset it to zero after fading.
while(brightness >= 0){
...
brightness = brightness - fadeAmount;
...
}
Imagine we are at the point, where brightness
is 5. The while condition is true, since 5 > 0. Then we execute the code in the loop, setting brightness
to 0. We again check the while condition. It is still true, since 0>=0
. So after executing the code in the loop again, brightness
is now -5. But analogWrite()
only takes a 1 byte unsigned (!) integer, aka uint8_t
, while int
is a 2 byte signed (!) integer. So only the lower byte of that integer will be used and interpreted as unsigned. So -5 gets interpreted as 251, which you see as lighting up in full brightness.
Easy fix would be to set brightness
to zero after the while loop:
brightness = 0;
That said, I would suggest a completely different route, which will make your code way more responsive, by using the non-blocking coding principle from the BlinkWithoutDelay
example, that comes with the Arduino IDE.
As you did, I would use a global brightness
and fadeAmount
variable, but also one to hold a timestamp:
unsigned long timestamp=0;
Then in loop()
we can first do the fading to zero by using the millis()
function as a clock:
if(millis()-timestamp > 30){
brightness = brightness - fadeAmount;
if(brightness < 0) brightness = 0;
timestamp = millis();
}
That will decrement the brightness
variable to zero without blocking with a delay()
. The speed can be changed by changing the number 30
to something different. This number has the unit milliseconds.
Then we can check for the reed switch and set brightness
to 255, if it is activated:
if(!digitalRead(reedPin)){
// reedPin is LOW
brightness = 255;
}
So as long as the magnet is at the reed switch, this code will set brightness
to 255.
And finally we need to write the value of brightness
to the output pin:
analogWrite(ledPin, brightness);
So as a full code:
int ledPin = 9;
int reedPin = 2;
int brightness = 0;
int fadeAmount = 5;
unsigned long timestamp = 0;
void setup(){
pinMode(ledPin, OUTPUT);
pinMode(reedPin, INPUT_PULLUP);
}
void loop(){
if(millis()-timestamp > 30){
brightness = brightness - fadeAmount;
if(brightness < 0) brightness = 0;
timestamp = millis();
}
if(!digitalRead(reedPin)){
// reedPin is LOW
brightness = 255;
}
analogWrite(ledPin, brightness);
}
I've tested this with a normal button (currently no reed switch here). It should work as expected.
-
I tested it, it works. Thank you so much!Igne– Igne2022年11月25日 12:04:41 +00:00Commented Nov 25, 2022 at 12:04
{}
button in the question editor