1

I'm having issues with two objects of the same class type. I have a LED class, which has functions to fade in and out, a LED. In my code, I create two objects of this class, and on the board, I fade them in and out.

Code is in my FadingLED.h file, which I #include.

I instantiate these classes - and then in my setup(), I call an Init function on the classes to initialise them and pass all the parameters I need.

And then in the loop, I just keep calling an Update method, which internally, uses Millis() to handle updating the brightness of the LED.

But I think I am having cross contamination of the objects. Because if I trigger them both to fadein and out at the same time, only the first LED fades. If I stagger them, the 2nd LED works, but it's timing seems to be out. It seems like maybe I'm somehow mixing member variables within the class. I'm new to this, so it's probably an obvious fault?

My calling code:

// This #include statement was automatically added by the Particle IDE.
#include "Buzzer.h"
#include "FadingLED.h"

// Pins being used by devices.
int LED1_PIN = A4;
int LED2_PIN = A5;
int PIR_PIN = 3;
int BUZZER_PIN = 0;

// Instantiate the objects
FadingLED LED_1;
FadingLED LED_2;
Buzzer buzzer;

// Setup global variables.
bool AllStill = true;

// Setup.
void setup() {
    // Initialise the two LEDs
    LED_1.Init(LED1_PIN, 500, 0, true);
    LED_2.Init(LED2_PIN, 500, 250, true);
    // Set the PIR pinmode.
    pinMode(PIR_PIN, INPUT);
    Particle.publish("Device","Board initialised", PUBLIC);
    buzzer.Beep(100, 2200);
}

// Function to check if movement has been detected.
bool CheckMovement() {
    // Read the pin value.
    int val = digitalRead(PIR_PIN);

    // Has a new movement been detected?
    if(val==true && AllStill==true) {
        buzzer.Beep(200, 2200);
        AllStill = false;
        Particle.publish("Device", "Movement Detected", PUBLIC);
    } 
    AllStill = !val; // All still is false if we have movement.

    return val != 0;    
}


void loop() {
    // Check for moment.
    bool val = CheckMovement();
    // Update connected devices.
    LED_1.Update(val);
    LED_2.Update(val);
    buzzer.Update();
}

And then the class it's self.

/*
 * A class that manages a fading LED. This needs to be on PWM pin.
 */
class FadingLED {
  int             delayedStart = 0;               // Period to wait before starting. 
  int             ledPin = -1;                    // The pin to control - Note, as we're fading, we must use an ANALOG pin.
  long            fadePeriod = 0;                 // The time to do a full light and dim cycle. 
  unsigned long   previousMillis = 0;             // The previous millis value.
  bool            debug = false;                  // Should we output stuff?
  float           fadeChangeGap = 0;              // Calculated gap between brightness changes.
  unsigned long   firstMillis = -1;

public:  
  void Init(int LedPin, int FadePeriod, int DelayedStart, bool Debug) {
    ledPin = LedPin;
    fadePeriod = FadePeriod;
    delayedStart = DelayedStart;
    debug = Debug; 
    pinMode(ledPin, OUTPUT);
    Particle.publish("Debug", "LED Initialised on " + String(ledPin) + ", Fade Period is " + String(fadePeriod) + ", Start Delay is " +  String(delayedStart), PUBLIC);
  }

  void Update(bool isOn) {

      // Get the current millis since the board was started.
      unsigned long currentMillis = millis();

      // Is this the first time this code is running?  
      if(firstMillis == -1) 
        firstMillis = currentMillis; // Set the first time this class was run.

      // Adjust the current time to be based on the current time since the object was created.
      currentMillis = currentMillis - firstMillis;

      // Calculate the difference bwteen the last update and now.    
      unsigned long diff = currentMillis - previousMillis;

      int brightness = 0;

      // Check if we have a delay set. If so, don't light up yet.
      if(delayedStart > 0 && currentMillis < delayedStart) {
        Particle.publish("LED", "In Delay Start...", PUBLIC);
         previousMillis = currentMillis;     
        return;
      }

      // Map the difference which is betweem 0 and the cycle time, to a value between 0 and 512.
      // Map the difference, which is between 0 and the fade period, to a value between 0 at 512.
      int b = map(diff, 0, fadePeriod, 0, 512); // 512, as we'll brighten to 256, then then fade from 256 to 512.

      // Check if we should be bringtning, or fading...
      if(b > 255) {
        brightness = 255 - (b-255);
      }
      else
      {
        brightness = b;
      }

      if(isOn == false) {
        brightness = 0;
      }  
      // Set the brightness.
      analogWrite(ledPin, brightness);

      // And then save the timestamp.
      if(currentMillis - previousMillis >= fadePeriod) {
         previousMillis = currentMillis;     
      }
  }
};

Is there an error with how I am defining the class (I'd expect to use the 'new' keyword, but don't). Maybe in the class it's self, there is a way to say the field are private to that object only?

If I try:

FadingLED LED_1 = new FadingLED();

I get:

conversion from 'FadingLED*' to non-scalar type 'FadingLED' requested

Any assistance or advice would be great.

4
  • 3
    Keep it simple, keep it straightforward, don't try to do "smart" things that have consequences. You assign -1 to a unsigned long, that's no good. You compare -1 to a unsigned long, that's can't be right either. Avoiding the rollover problem is good, but introducing another similar problem by using -1 as a flag is not good. This: "currentMillis < delayedStart" is not good, even if it is only used after power on, it still causes a problem during the rollover. You need a clear and logical structured code in the update function. Think first what you want to do before writing down code.
    – Jot
    Commented Apr 23, 2019 at 0:56
  • 1
    The keyword 'new' is not needed, it would allocate it dynamically (which you don't need). In that case the statement should be FadingLED* LED_1 = new FadingLED(); Thus LED_1 would be a pointer. Commented Apr 23, 2019 at 0:56
  • Also you don't need to compare booleans against false or true, you can use if (bool_x) or ir (!bool_x). Commented Apr 23, 2019 at 0:57
  • 1
    A4 and A5 don't work with analogWrite arduino.cc/reference/en/language/functions/analog-io/…
    – Juraj
    Commented Apr 23, 2019 at 8:45

1 Answer 1

1

I combined the FadingLED class with your "calling code" sketch, then removed the references to libraries that I don't have. The first error I received was regarding the seven lines of code immediately under the "class FadingLED {" line.

My answer will only address the issues with the way the class is written. As Jot and Michel Keijzers have mentioned in their comments to your question, there may be other issues that need to be fixed.

The following sketch uses a slightly modified version of the FadingLED class. There are 2 constructors. One is a "no argument" constructor, and the other accepts 4 arguments. Both constructors call the private function initStuff() to initialize other variables, pinModes, etc.

/*
 * A class that manages a fading LED. This needs to be on PWM pin.
 */
class FadingLED {

  private:

    int             delayedStart;     // Period to wait before starting. 
    int             ledPin;           // The pin to control - Note, as we're fading, we must use an ANALOG pin.
    long            fadePeriod;       // The time to do a full light and dim cycle. 
    unsigned long   previousMillis;   // The previous millis value.
    bool            debug;            // Should we output stuff?
    float           fadeChangeGap;    // Calculated gap between brightness changes.
    unsigned long   firstMillis;

    void initStuff(){
      previousMillis = 0;
      fadeChangeGap = 0;
      firstMillis = -1;
      pinMode(ledPin, OUTPUT);
      //Particle.publish("Debug", "LED Initialised on " + String(ledPin) + ", Fade Period is " + String(fadePeriod) + ", Start Delay is " +  String(delayedStart), PUBLIC);
    }

  public:

    FadingLED(): delayedStart(0), ledPin(-1), fadePeriod(0), debug(false){
      initStuff();
    }

    FadingLED(int LedPin, int FadePeriod, int DelayedStart, bool Debug):
      delayedStart(DelayedStart),
      ledPin(LedPin),
      fadePeriod(FadePeriod),
      debug(Debug){
      initStuff();
    }

    void Update(bool isOn) {

        // Get the current millis since the board was started.
        unsigned long currentMillis = millis();

        // Is this the first time this code is running?  
        if(firstMillis == -1) 
          firstMillis = currentMillis; // Set the first time this class was run.

        // Adjust the current time to be based on the current time since the object was created.
        currentMillis = currentMillis - firstMillis;

        // Calculate the difference bwteen the last update and now.    
        unsigned long diff = currentMillis - previousMillis;

        int brightness = 0;

        // Check if we have a delay set. If so, don't light up yet.
        if(delayedStart > 0 && currentMillis < delayedStart) {
          //Particle.publish("LED", "In Delay Start...", PUBLIC);
          previousMillis = currentMillis;     
          return;
        }

        // Map the difference which is betweem 0 and the cycle time, to a value between 0 and 512.
        // Map the difference, which is between 0 and the fade period, to a value between 0 at 512.
        int b = map(diff, 0, fadePeriod, 0, 512); // 512, as we'll brighten to 256, then then fade from 256 to 512.

        // Check if we should be bringtning, or fading...
        if(b > 255) {
          brightness = 255 - (b-255);
        }
        else
        {
          brightness = b;
        }

        if(isOn == false) {
          brightness = 0;
        }  
        // Set the brightness.
        analogWrite(ledPin, brightness);

        // And then save the timestamp.
        if(currentMillis - previousMillis >= fadePeriod) {
           previousMillis = currentMillis;     
        }
    }
};

// This #include statement was automatically added by the Particle IDE.
//#include "Buzzer.h"
//#include "FadingLED.h"

// Pins being used by devices.
int LED1_PIN = A4;
int LED2_PIN = A5;
int PIR_PIN = 3;
int BUZZER_PIN = 0;

// Instantiate the objects
FadingLED LED_1(LED1_PIN, 500, 0, true);
FadingLED LED_2(LED2_PIN, 500, 250, true);
//Buzzer buzzer;

// Setup global variables.
bool AllStill = true;

// Setup.
void setup() {
    // Set the PIR pinmode.
    pinMode(PIR_PIN, INPUT);
    //Particle.publish("Device","Board initialised", PUBLIC);
    //buzzer.Beep(100, 2200);
}

// Function to check if movement has been detected.
bool CheckMovement() {
    // Read the pin value.
    int val = digitalRead(PIR_PIN);

    // Has a new movement been detected?
    if(val==true && AllStill==true) {
        //buzzer.Beep(200, 2200);
        AllStill = false;
        //Particle.publish("Device", "Movement Detected", PUBLIC);
    } 
    AllStill = !val; // All still is false if we have movement.

    return val != 0;    
}


void loop() {
    // Check for moment.
    bool val = CheckMovement();
    // Update connected devices.
    LED_1.Update(val);
    LED_2.Update(val);
    //buzzer.Update();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.