hi guys!! im trying to make my lamp fade smoothly from off to full brightness but it doenst work right. instead of a smooth fade it just jumps around to random brightness levels, its super weird
heres my code:
#include <RBDdimmer.h>
dimmerLamp dimmer(5, 2);
void setup() {
dimmer.begin(NORMAL_MODE, ON);
}
void loop() {
for (int i = 0; i <= 100; i++) {
dimmer.setPower(i);
delay(50);
}
for (int i = 100; i >= 0; i--) {
dimmer.setPower(i);
delay(50);
}
}
i thought this would make a nice smooth 5 second fade up and then back down but the lamp just kind of flickers and jumps between brightness levels. sometimes it looks like its going backwards too??
im using arduino uno with teh rbdimmer 1CH 4A module. the dimmer works fine if i just set a fixed power level like setPower(50) so i know its not a wiring problem
what am i doing wrong??
The issue is your use of delay() inside the fade loop.
Why this breaks dimming:
The RBDdimmer library uses a zero-cross interrupt (ISR) that needs to fire precisely at each AC half-cycle — every 10ms at 50Hz or 8.33ms at 60Hz. The ISR calculates when to fire the TRIAC within each half-cycle based on your power setting.
When you call delay(50), the Arduino’s main loop is completely blocked for 50ms. During that time:
- The ZC interrupt still fires (interrupts aren’t blocked by
delay())
- But the TRIAC timing can become unstable because
delay() messes with the internal timer state
- The library’s internal state and your
setPower() calls get out of sync
- Result: unpredictable brightness jumps instead of smooth fading
The fix: Use non-blocking timing with millis() instead of delay(). This lets the main loop run freely so the dimmer ISR can do its work without interference:
unsigned long lastUpdate = 0;
int currentPower = 0;
int fadeDirection = 1;
void loop() {
if (millis() - lastUpdate >= 50) {
lastUpdate = millis();
currentPower += fadeDirection;
if (currentPower >= 100) fadeDirection = -1;
if (currentPower <= 0) fadeDirection = 1;
dimmer.setPower(currentPower);
}
// loop runs freely — no blocking
}
The key difference: millis() checks the time without blocking, so the loop runs thousands of times per second. The dimmer ISR stays happy and your fade is smooth.
ohhh ok so delay() is bad for dimmers?? i use delay() in like all my arduino projects lol i didnt know it could mess up other stuff thats running in the background
let me try the millis thing, ive never used it before but your code makes sence. give me a sec to upload it and ill report back!
Here’s a compact version if you want something quick to test — worked for me on a similar setup:
#include <RBDdimmer.h>
dimmerLamp dimmer(5, 2);
unsigned long lastFade = 0;
int power = 0;
int step = 1;
void setup() {
dimmer.begin(NORMAL_MODE, ON);
}
void loop() {
if (millis() - lastFade >= 50) {
lastFade = millis();
power += step;
if (power >= 100 || power <= 0) step = -step;
dimmer.setPower(power);
}
}
Same idea as Hank’s code, just a bit shorter. The step = -step trick flips the direction automatically when you hit the limits.
AFAIK any blocking call inside the loop will cause issues with the dimmer — not just delay() but also things like Serial.readString() or waiting for sensor responses. Keep the loop non-blocking and you’ll be fine.
omg it worked thanks so much!!! the fade is super smooth now, exactly what i wanted!!
i used Felix’s code because it was shorter and easyer to understand. the lamp fades up and down perfectly, no more jumping around
so basically the rule is never use delay() when the dimmer is running? good to know, i will remeber that for all my future projects
thanks everyone you guys are the best!!!
Glad it’s working!
For anyone finding this later, here’s the general rule:
Never use blocking calls (delay(), blocking Serial reads, long while loops) in your main loop when using the RBDdimmer library. Always use millis()-based non-blocking timing for any timed operations.
One more tip: if you’re on ESP32 with the rbdimmerESP32 library, you have another option. You can put your fade logic in a separate FreeRTOS task:
void fadeTask(void *parameter) {
int power = 0;
int step = 1;
while (true) {
power += step;
if (power >= 100 || power <= 0) step = -step;
dimmer.setPower(power);
vTaskDelay(pdMS_TO_TICKS(50));
}
}
void setup() {
dimmer.begin(NORMAL_MODE, ON);
xTaskCreatePinnedToCore(fadeTask, "fade", 2048, NULL, 1, NULL, 1);
}
On ESP32, vTaskDelay() yields the CPU to other tasks (including the dimmer ISR task on Core 0) instead of blocking everything. This keeps dimming smooth even with complex fade logic. The millis() approach works fine on ESP32 too though — FreeRTOS tasks are just a more structured option for complex projects.