Objects interactions methods in OOP

Hello lovely people!
Bigos here.

I would like to know your or generally known methods of interacting with objects in terms of OOP. (Of course, I'm not talking about ready copy-paste code.) I hope my question doesn't sound weird :confused: I'm just an arduino enthusiast, so please forgive me if that doesn't have any sense :wink: . Of course, I'm not talking about ready-made copy-paste code.

I have wrote two libraries.
The first one allows the tact-switch button to be used as toggle switch. The "toggled" function shown in the code below returns true when button is pushed and released, and false when button is not pushed or is held. So the true state is just a pulse. I think this library works very fine as for a novice coder.

The second library adds two functions for LEDs. You can make an object that can blink (you can set the High and Low durations) or fade (you can set speed).

What I'm trying to do is to interact with a button on led's behavior. I want to turn blinking On and of with my virtual toggle switch. I have created what I think is called a machine state (?). The 'state' variable changes when button is toggled. When the 'state' is TRUE, the blinking goes on, when 'state' is false the led is off. This works just fine i think but my intuition tells me that this is not a common way to do that. Shouldn't the object (LED) be shut down or destroyed?

So my question is:

What are the methods of interacting with objects in terms of OOP? What approach is more professional to that? In the next step, I would like to use my toggle button to change functions like skipping melodies, changing pre-set LED sequences etc.

Any concepts or ideas are welcome.
If you would like to see the whole of the libraries I'd be happy to show it.

The code below shows my approach to objects interaction.

#include <Arduino.h> //wrote on VSCode
#include <button.h> //button library
#include <BLINK.h> //LEDs library

bool led1State = false; //LEDs machine state is false for the beginning
const int button1pin = 2; 
const int led1pin = 0;
const int buzzer1pin = 1; //additional buzzer, works the same as LED


Button button1(button1pin); //button object
BLINK led1(led1pin); //LED object
BLINK buzzer1(buzzer1pin); //buzzer object

void setup()
{
  
  pinMode(button1pin, INPUT);
  pinMode(led1pin, OUTPUT);
  pinMode(buzzer1pin, OUTPUT);

}

void loop()
{
  if(button1.toggled()) //toggled function returns true or false
  {
  led1State = !led1State;}
    if(led1State)
        {
      led1.ledblink(50, 2000); //blinking function (HIGH duration, LOW duration)
      buzzer1.ledblink(50,2000); 
        }
    if(!led1State){ //This is what turns LEDs blinking off. Im not sure if this is common way to do this...
      digitalWrite(led1pin,led1State);
      digitalWrite(buzzer1pin,led1State);
    }
}

Back at you and welcome to the forum.

Please post the files for your objects.

button.h, BLINK.h and any *.cpp files you needed.

TIA

a7

show your classes if you want feedback on them

Please check your parentheses. Let the IDE format your code to find misplaced braces.

I'm sorry DrDiettrich, what's wrong with braces? I can't understand you.

Braces in wrong places can be wrong.

Do you really want to handle led1State with every iteration of loop()?

Sure, alto777!

button.h:

#ifndef button_h
#define button_h

#include <Arduino.h>

class Button
{
private:
    int _pin;
    bool _State; 
    bool _toggled;

public:
    Button(int pin);
    bool toggled(void);
};

#endif

button.cpp:

#include <Arduino.h>
#include "button.h"

Button::Button(int pin)
{
    _pin = pin;
    pinMode(_pin, INPUT_PULLUP);

    // default values
    _State = true; 
    _toggled = false;
}

bool Button::toggled(void)
{
    if (_State)
    {

        if (!digitalRead(_pin)) //pullup resistor. when button is pressed, there is LOW on the input pin
        {

            _State = !_State;
            _toggled = true;
            delay(35); //debounce seems to work fine
        }
    }
    else
    {
        if (!digitalRead(_pin))
        {
            _toggled = false;
        }
        else
        {
            _State = !_State;
        }
    }
    return _toggled;
}

BLINK.h: - I need to write this sketch again. There should be no default variables in header as i know... But this is my first library ever..

#ifndef BLINK_h
#define BLINK_h

#include <Arduino.h>

class BLINK
{
public:
    BLINK(int pin);
    void ledblink(unsigned long hight, unsigned long lowt);
    void ledfade(int fadespd);

private: 
    int _pin;
    unsigned long _t1 = 0;
    unsigned long _t2;
    int pinmode = HIGH;
    int brightness = 0;
    int fadeammount = 2;
};

#endif

BLINK.cpp:

#include <Arduino.h>
#include <BLINK.h>

BLINK::BLINK(int pin)
{
    pinMode(pin, OUTPUT);
    _pin = pin;
}
void BLINK::ledblink(unsigned long hight, unsigned long lowt)
{

    _t2 = millis(); // assign actual time to variable t2
    if (_t2 - _t1 >= hight && pinmode == HIGH)
    { // if actual time minus last time = blink time AND pinmode is HIGH change pin state to LOW
        pinmode = LOW;
        digitalWrite(_pin, pinmode);
        _t1 = _t2; // save actual time to the last time variable
    }
    if (_t2 - _t1 >= lowt && pinmode == LOW)
    {
        pinmode = HIGH;
        digitalWrite(_pin, pinmode);
        _t1 = _t2;
    }
}

void BLINK::ledfade(int fadespd)
{
    _t2 = millis(); // assign actual time to variable t2
    if (_t2 - _t1 >= fadespd)
    {
        analogWrite(_pin, brightness);
        brightness = brightness + fadeammount;
        _t1 = _t2; // save actual time to the last time variable
        if (brightness <= 0 || brightness >= 200)
        {
            fadeammount = -fadeammount;
        }
    }
}

This is how it works in the buttons library:

Button's state is read only when _State is TRUE. The _State go FALSE immediately when button is pressed. So, if _State is False now, the button's state is no longer read.

This is actually the toggle mechanism. I can change state with just one Tact Switch button. I hope I've answered your question.

Not really. But if you think that your code does what it should and does not deserve reformatting then I have no further comment for you.

I'd be happy to do that if you argue your point of view.

There is no right or wrong here. You turn off the blinking or fading by simply not calling the methods that would make that happen.

You take care to turn off the things that would otherwise be left wherever they happened to be.

It isn't really interacting with the object so much as ignoring it and usurping its prerogative.

You could add a method to turn off or on the blink or fade, optimally saying whether the value should be left at the precise place or perhaps made maximum or minimum.

Then your loop could call the update method without regard to where it was going or not.

Speaking of minimum and maximum, why do you reverse the fade direction at 200? analogWrite() goes up to 255, and there's quite a bit of brightness gained in that last bit you leave out.

Also, since there is always an LED, it seems harmless to let the blink object live forever. I see no need to destroy and recreate it.

If you use the IDE Tool called Auto format, you may like the layout it produces which is one of several common "standard" formats. At the very least, ppl will find it easier to read.

a7

Consistency: AllClassNamesDoCamelStyle -> Blink

When you think of names, try to distinguish between "things" (nouns) and "actions" (verbs). Object methods should be verbs (find, go, attach, add, make, prolong, blink…), while the objects themselves are… things (nouns like Finder, Adder, Matcher, Blinker).

-> Blinker

If you want to be more precise (and you do, because you make that distinction on methods), put it in the name -> LedBlinker.

Like above -> blink() and fade() will then be enough -> unless you think your object could blink something else than a LED, but then that would for sure violate SRP.

You don't need to set those in the constructor -> set them directly on the fields.

Filed names starting with small letters -> _state

I also don't like the underscores -> don't really see the reason for them -> it's not Python -> state.

Don't do shortcuts, we have big screens -> fadingSpeed.

Or, since the method is already fade, maybe even just speed is enough.

I guess you can get rid of this var and use digitalRead() instead.

Those are called "magic numbers". They have a special meaning, but right now it does not have to be obvious why they are like that.

For starters you could make a comment. But, code is always better than a comment -> extract a constant.

static const int MAX_BRIGHTNESS = 200; would give the magic number a name. If the 200 is special somehow (I don't know why is it 200, why not 100? etc) -> then, if you can think how to put that info in the const name, then it would be best. If you cannot, just add a comment with explanation.

Yeah, I look at this field, and unless I analyse the whole code, I have no idea what this var is for -> think of a better name.


Finally, just as @DrDiettrich said: (auto) format the code. It is a bit messy right now.

why is that in setup()?
That should be part of the class.
Create a new member function .begin() and let .begin() call the pinMode.
--> Don't do it in the constructor, but in a member function.

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