Arduino non-blocking software PWM LED fader not working I am trying to write a simple software PWM to fade some LEDs because I don't have enough PWM I/O Ports.

The code evaluates how long you want the LED to fade, and breaks it down into a number of steps. During each step, it will evaluate the period the LED should be on.

I have the following code:

class Led{
  public:
    Led(int pin);
    void setup();
    // void updateFadeDirection();
    void updateBrightness();

  private:
    int _pin;
    unsigned long _currentTime;
    unsigned long _startTime; // Very beginning of fade period 
    unsigned long _fadePeriod; // How long to fade on and off
    int _fadeStep; // current fade step i.e. 1/255
    int _fadeSteps; // How many steps to take until full brightness
    int _fadeDirection; // low to high or high to low?
    float _T_on; // Amount of time to turn LED on
    float _T_fadeStep; // Amount of time per step increment of brightness
    unsigned long _stepTime; // Start of current step period

    bool _evaluated;
};

Led::Led(int pin){
  _pin = pin;
}

void Led::setup(){
  pinMode(_pin, OUTPUT);
  _startTime = micros();
  _fadePeriod = 2*1000000; //microseconds(us)
  _fadeStep = 50; // start at 0 brightness here
  _fadeSteps = 100;
  _fadeDirection = 1;

  _T_fadeStep = _fadePeriod/_fadeSteps; // i.e. 2000000us/100steps = 20000us/step of brightness
  _T_on = (_fadeStep/_fadeSteps) * _T_fadeStep; // i.e. 20/100 * 20000us = 4000us on

  _stepTime = micros();
  delayMicroseconds(200);
}

void Led::updateBrightness(){
  _currentTime = micros();

  if(_currentTime - _startTime &lt; _fadePeriod){
    if (_currentTime - _stepTime &gt; _T_on){
      digitalWrite(_pin, LOW);
    } else {
      digitalWrite(_pin, HIGH);
    }

    if(_currentTime - _stepTime &gt;= _T_fadeStep){
      // _fadeStep++;
      _stepTime = _currentTime;
      _T_on = (_fadeStep/_fadeSteps) * _T_fadeStep;
    }
  }
  else{
    digitalWrite(_pin, HIGH);
  }
}

Led LED0(0);

void setup() {
  LED0.setup();
}

void loop() {
  LED0.updateBrightness();
}


The current behaviour when powered on is the single LED will be turned off, then will turn on after 2 seconds.

In particular, it never seems to enter the else part

  if (_currentTime - _stepTime &gt; _T_on){
    digitalWrite(_pin, LOW);
  } else {
    digitalWrite(_pin, HIGH);
  }


The problem is that the LED will never hit HIGH until the outer else is triggered.

I believe it has to do with _T_on being an int and the timestamps being unsigned long and me not casting it.

The expected behaviour is 2 seconds of dimmed (50%) light, and then a full 100% when it hits the outer else.
As @ott-- has mentioned, because of the int datatype, _fadeStep/_fadeSteps will always evaluate to 0.

Here's the updated code along with some timing tweaks:

float fadeSteps = 150; // How many steps to take until full brightness

class Led{
  public:
    Led(int pin, float fadeStep=0);
    void setup();
    // void updateFadeDirection();
    void updateBrightness();

  private:
    int _pin;
    unsigned long _currentTime;
    unsigned long _startTime; // Very beginning of fade period 
    unsigned long _fadePeriod; // How long to fade on and off
    float _fadeStep; // current fade step i.e. 1/255
    int _fadeDirection; // low to high or high to low?
    unsigned long _T_on; // Amount of time to turn LED on
    unsigned long _T_fadeStep; // Amount of time per step increment of brightness
    unsigned long _stepTime; // Start of current step period

    bool _evaluated;
};

Led::Led(int pin, float fadeStep){
  _pin = pin;
  _fadeStep = fadeStep;
}

void Led::setup(){
  pinMode(_pin, OUTPUT);
  _startTime = micros();
  _fadePeriod = 2000000; //microseconds(us)
  _fadeDirection = 1;

  _T_fadeStep = _fadePeriod/2/fadeSteps; // i.e. 2000000us/100steps = 20000us/step of brightness
  _T_on = (_fadeStep/fadeSteps) * _T_fadeStep; // i.e. 20/100 * 20000us = 4000us on

  _stepTime = micros();
}

void Led::updateBrightness(){
  _currentTime = micros();
  if (_currentTime - _stepTime &gt; _T_on){
    digitalWrite(_pin, LOW);
  } else {
    digitalWrite(_pin, HIGH);
  }

  if(_currentTime - _stepTime &gt;= _T_fadeStep){
    _fadeStep += _fadeDirection;
    _stepTime = _currentTime;
    _T_on = (_fadeStep/fadeSteps) * _T_fadeStep;
  }

  if(_fadeStep &gt;= fadeSteps-1) {
    _fadeDirection = -1;
  } else if(_fadeStep &lt;= 1) {
    _fadeDirection = 1;
  }
}

Led LED0(0);
Led LED1(1,fadeSteps/5);
Led LED2(2,2*fadeSteps/5);
Led LED3(3,3*fadeSteps/5);
Led LED4(4,4*fadeSteps/5);

void setup() {
  LED0.setup();
  LED1.setup();
  LED2.setup();
  LED3.setup();
  LED4.setup();
}

void loop() {
  LED0.updateBrightness();
  LED1.updateBrightness();
  LED2.updateBrightness();
  LED3.updateBrightness();
  LED4.updateBrightness();
}


Some refactoring is needed to be more modular, but will fade (using software PWM) LEDs asynchronously on every digital OUT port on an attiny85. Can also set the starting brightness so that you can make an LED fading chaser.