Dimming LEDs using mosfets

Hello!

I am trying to control an LED strip to fade on, stay on for "pictureTime" milliseconds, then fade off, using a MOSFET as a relay.

This action gets triggered by a sensor value. I am using an Adafruit Time of Flight sensor to read this value, and this portion of the function works perfectly. When the distance is close enough, the trigger starts as expected and the lights fade on. The fade-on to stay-on transition is smooth. BUT when the fade out section happens, there is a blip in the LEDs where they go off for just a "blink of an eye's" worth of time before continuing to fading out smoothly. I wish to get rid of this blip. Not sure why this behavior is happening, so this is why I am here.

my code is here, but please focus on the void loop() section // making the LEDs behave smoothly on the fade-out. The setup is mostly for the ToF sensor.

#include "Adafruit_VL53L1X.h"

#define IRQ_PIN 2
#define XSHUT_PIN 3

Adafruit_VL53L1X vl53 = Adafruit_VL53L1X(XSHUT_PIN, IRQ_PIN);


int pictureTime = 5000;
int brightness = 0;
int fadeAmount = 3;
int light = 7;

void setup() {
  pinMode(light, OUTPUT);
  Serial.begin(115200);
  while (!Serial) delay(10);

  Serial.println(F("Adafruit VL53L1X sensor demo"));

  Wire.begin();
  if (! vl53.begin(0x29, &Wire)) {
    Serial.print(F("Error on init of VL sensor: "));
    Serial.println(vl53.vl_status);
    while (1)       delay(10);
  }
  Serial.println(F("VL53L1X sensor OK!"));

  Serial.print(F("Sensor ID: 0x"));
  Serial.println(vl53.sensorID(), HEX);

  if (! vl53.startRanging()) {
    Serial.print(F("Couldn't start ranging: "));
    Serial.println(vl53.vl_status);
    while (1)       delay(10);
  }
  Serial.println(F("Ranging started"));

  // Valid timing budgets: 15, 20, 33, 50, 100, 200 and 500ms!
  vl53.setTimingBudget(50);
  Serial.print(F("Timing budget (ms): "));
  Serial.println(vl53.getTimingBudget());

}

void loop() {
  int16_t distance;
  analogWrite(light, brightness);

  if (vl53.dataReady()) {
    // new measurement for the taking!
    distance = vl53.distance();
    if (distance == -1) {
      // something went wrong!
      Serial.print(F("Couldn't get distance: "));
      Serial.println(vl53.vl_status);
      return;
    }

    if (distance < 500){  //TRIGGERED MOMENT
      Serial.print(F("Distance: "));
      Serial.print(distance);
      Serial.print (" mm");
      Serial.println(" IM IN!!");
      brightness = 0; 

      while (brightness < 256) { ///FADE ON
        delay(30);
        brightness = brightness + fadeAmount;
        analogWrite(light, brightness);
      }

      analogWrite(light, 255); //HOLD
      delay(pictureTime);

      while (brightness > 0){ ///FADE OFF
        analogWrite(light, brightness);
        brightness = brightness - (fadeAmount*.3);
        delay(15);
      }
    }
    brightness = 0;
    Serial.print(F("Distance: "));
    Serial.print(distance);
    Serial.println(" mm");
  
    // data is read out, time for another reading!
    vl53.clearInterrupt();
  }
}

If this is an UNO, pin 7 is not a PWM pin.

https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/

Make sure that your strip really can be dimmed by PWM.

At the end of this loop, brightness will be 258. Since the maximum value that analogWrite() allows is 255, it will treat 258 the same as (258-256) = 2. So for a very, very short time, less than the blink of an eye, the brightness will be very low. But this won't be noticeable because...

this code immediately sets the led to max brightness.

But then ...

this code will set it back to 2 again and then there is a short delay, so the effect does last for the blink of an eye.

2 Likes

Thanks @PaulRB ! This was the exact answer I was looking for. I see two solutions, one; change 255 to 258.
two; set brightness equal to 255 again right before entering the fade off loop.

Which one? if either?

EDIT: I used option 2

I wouldn't choose either of them. They won't fix the fact that your code is "blocking code", code which uses delay() for timing. This prevents the Arduino from doing anything else at the "same time", such as checking for button presses or other events. You may not realise the importance of that yet.

1 Like

@PaulRB this is all true, I actually did want my arduino to do nothing and not check for anything else while on delay(), but maybe this is clogging something? Also, I had to run some long wires between the sensor, arduino (mega) and mosfet in order to place things in my setup appropriately, and after a few successful runs, the lights do not turn on anymore and the serial monitor stops communicating. After testing, what I have discovered is that after a power cycle the system works as expected for a couple more iterations, then stops again. Sometimes I have to reset everything. Very inconsistent function. Why? And how do I fix this?

This sounds like a hardware problem. Post your schematic and some close-up, clear, bright photos of the circuit so that every wire can be traced.

Use the watch dog timer with interrupt. Just set up the pre-scaler values and have it service the interrupt. You can use that to increment a counter then after so many counts increment or decrement the fade amount.
That way you can carry on and do other things or just leave it to do its stuff.





#include "Adafruit_VL53L1X.h"

#define IRQ_PIN 2
#define XSHUT_PIN 3

Adafruit_VL53L1X vl53 = Adafruit_VL53L1X(XSHUT_PIN, IRQ_PIN);


int pictureTime = 5000;
int brightness = 0;
int fadeAmount = 3;
int light = 7;

void setup() {
  pinMode(light, OUTPUT);
  Serial.begin(9600);
  while (!Serial) delay(10);

  Serial.println(F("Adafruit VL53L1X sensor demo"));

  Wire.begin();
  if (! vl53.begin(0x29, &Wire)) {
    Serial.print(F("Error on init of VL sensor: "));
    Serial.println(vl53.vl_status);
    while (1)       delay(10);
  }
  Serial.println(F("VL53L1X sensor OK!"));

  Serial.print(F("Sensor ID: 0x"));
  Serial.println(vl53.sensorID(), HEX);

  if (! vl53.startRanging()) {
    Serial.print(F("Couldn't start ranging: "));
    Serial.println(vl53.vl_status);
    while (1)       delay(10);
  }
  Serial.println(F("Ranging started"));

  // Valid timing budgets: 15, 20, 33, 50, 100, 200 and 500ms!
  vl53.setTimingBudget(50);
  Serial.print(F("Timing budget (ms): "));
  Serial.println(vl53.getTimingBudget());

}

void loop() {
  int16_t distance;
  analogWrite(light, brightness);

  if (vl53.dataReady()) {
    // new measurement for the taking!
    distance = vl53.distance();
    if (distance == -1) {
      // something went wrong!
      Serial.print(F("Couldn't get distance: "));
      Serial.println(vl53.vl_status);
      return;
    }

    if (distance < 800){  //TRIGGERED MOMENT
      Serial.print(F("Distance: "));
      Serial.print(distance);
      Serial.print (" mm");
      Serial.println(" IM IN!!");
      brightness = 0; 

      while (brightness < 256) { ///FADE ON
        delay(50);
        brightness = brightness + fadeAmount;
        analogWrite(light, brightness);
      }

      analogWrite(light, 255); //HOLD
      delay(pictureTime);
      brightness = 255;

      while (brightness > 0){ ///FADE OFF
        analogWrite(light, brightness);
        brightness = brightness - (fadeAmount*.3);
        delay(50);
      }
    }
    brightness = 0;
    Serial.print(F("Distance: "));
    Serial.print(distance);
    Serial.println(" mm");
    return;
  
    // data is read out, time for another reading!
    vl53.clearInterrupt();
  }
  delay(250);
}

I can't see anything obviously wrong with the code or the circuit.

What model of MOSFET is that? Is it logic-level?

If you connect the PSU directly to the led strip and leave it for a good length of time, is there any flickering or dimming?

If you add the MOSFET into the circuit and connect it's gate to 5V instead of the digital pin and leave that for a good length of time, what happens?

Hey @PaulRB,

It is a logic level mosfet!

The leds do not flicker when directly connected to the power supply unit.

When I wire the mosfet directly into 5v the leds stay on with no flickering.

When wired correctly, the leds eventually just do not turn on at all and the system becomes unresponsive.

Any ideas? I am about to try replacing all wires with grounded, shielded wire.

Probably won’t change things, if this is an N channel MOSFET, a 10k resistor from gate to GND is recommended.

Similar to circuit F2

There was some guy on the forum only a couple of days ago saying he had a logic level MOSFET, but when he revealed the model number, guess what?

But if connecting the MOSFET gate to 5V causes no flickering or other problems then I guess you are right.

Those tests point back to a problem with the sketch, I think, not the PSU, MOSFET or wiring. What does serial monitor show just before the problems begin?

One thing I don't personally like about your code on post #11 is the use of return; in loop(). I think that's poor code structure that could lead to coding errors. For example:

That vl53.clearInterrupt(); never gets called because of the return; .

Double checked the mosfet, that seemed solid! Moving to shielded wire helped a lot, also that return removal helped a lot as well, seems to be running smoothly now! Thanks

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.