0

I have created a class in C++. Each object corresponds with an I/O pin on a microcontroller. I can create an array of the objects and then set each pin to an output with a for loop. I would like to be able to set multiple pins to an output at the exact same time. This can be done with the hardware.

I am trying to create a method that works on an array of objects. You would use it like this:

Pin myPins[] = {0,1,2};
myPins.setOuput();

Basically I want to create a method that works on an array of objects. Is it possible to create a setOuput method like this? If yes, how? Thanks.

Update 1

New non-member method

void setOutput(Pin pins[], int size) {
    volatile uint8_t* _DDR = pins[0].getDDR();
    uint8_t _offset = 0;
    for (int i = 0; i < size; i++) {
        _offset |= pins[i].getOffset();
    }
    DDR_HIGH;
}

I am using the _ in the names so that my existing macro works. Not great but less code.

1
  • There's nothing wrong with simply having a non-member function that handles that (ex: setOutput(myPins)) If you need to access private members, you can make it static inside the Pin class. Commented Jul 10, 2015 at 17:12

2 Answers 2

2

Nope, you cannot add a method to a classic array the way you intend to. However, you could create a class that inherits from, say, a std::vector<Pin>, and add methods to it, like this:

class Pins : public std::vector<Pin>
{
public:
    void setOutput() { /* your code here */ }
};

That way, using C++11's uniform initialization, you could use a similar syntax:

Pins myPins = {0, 1, 2};
myPins.setOutput();

Edit: as per the comments, subclass a STL container is a quick and dirty solution and not the best idea. You could, however, create your own wrapper class very simply:

class Pins
{
    std::vector<Pin> mPins;

public:
    Pins (std::initializer_list<Pin> pins) : mPins(pins)
    { }

    void setOutput()
    {
        cout << "Pins in this pinset:" << endl;

        for (Pin & p : mPins)
        {
            cout << "\t" << p << endl;
        }
    }
};

That works exactly the same:

Pins myPins = {0, 1, 2};
myPins.setOutput();
Sign up to request clarification or add additional context in comments.

4 Comments

Deriving a class which is not meant to be used as a base class is dangerous, though. Pins' destructor should never be non-trivial
stackoverflow.com/q/6806173/1116364 I'd advice against subclassing here. This leads to a very rigid design.
Inside the setOuput function for the Pins class, how to I access each Pin? I need to call a function that returns the offset value for each Pin in the vector. Then I bitwise or them all together. In my Pins class I don't have a way to destroy an object. Because it is for use on a microcontroller it isn't really needed. I don't understand the harm of inheriting from vector?
It's the quick and dirty way of doing it. I've edited the answer to provide an alternative class that does not subclass std::vector. In this new class you can access the pins using mPins[i].
0

Most probably your setOutput member function is reading some possibly multi byte value, changing a bit depending on the pin, and writing it back.

C++ arrays can't have member functions.

To achieve a similar effect, you should split the work your original setOutput is doing:

  1. Read some hardware config
  2. Do the bit twiddling
  3. Apply the changes

Then you can let multiple pins do their bit twiddling before applying the final output.

Example:

Pin::Config cfg = Pin::read_config();
// the following could also happen in a loop over an array.
cfg = pin1.enableOutput(cfg);
cfg = pin4.enableOutput(cfg);
// or pass by reference and mutate, if you
// want a less functional style
// e.g. pinN.enableOutput(cfg)!
Pin::write_config(cfg);

This way you still have good encapsulation, but better control. Then you can write a free function to operate on arrays, vectors or whatever collection of pins, if needed:

template<typename It>
void setOutputPins(It start, It end) {
  Pin::Config cfg = Pin::read_config();
  for (; start != end; ++start) {
    cfg = (*start).enableOutput(cfg);
  }
  Pin::write_config(cfg);
};

Using it with C arrays:

Pin array[5]; // or a pointer for dynamic arrays
// ...
setOutputPins(array, array + size);

Don't make everything OO. It'll make your life harder.


[...] a function that returns the offset value for each Pin [...]. Then I bitwise or them all together.

So you don't even need that reading step. And since you bitwise or them, you could even do something like this:

Pin::write_config(pin1.output_mask() | pin4.output_mask());

You can make the function generic, too: Or pass a member function pointer:

template<typename It>
void setPins(It start, It end, Pin::Config (Pin::*fn)(void)) {
  Pin::Config cfg = 0; // identity for bitwise or
  for (; start != end; ++start) {
    cfg |= ((*start).*fn)();
  }
  Pin::write_config(cfg);
};

And the pass a pointer to the member function you want to invoke:

setPins(array, array + size, &Pin::asInput);

Example here.

7 Comments

I understand what you are saying and I was originally thinking of just creating a free function where you input an array of Pins and it loops through the array and gets the offset for each Pin (I have a method for getting the offset) and bitwise ors them together and then sets the register with the combined offset. I think the OO approach looks cleaner to use but it might not be worth it.
Here is the source: github.com/fenichelar/Pin Because I am going to write a bunch of these free methods (setInput, setOuput, setHigh, setLow, ...) I wanted to try and keep them grouped in a class.
Except for the toggle versions (which require state) the method from my latest edit should work
I don't think the toggle is necessary as you wouldn't likely need to toggle multiple pins simultaneously. I updated my questions with the new code for setOutput. Is there a better way of doing this than writing these blocks for every method?
You only need the last function. Then you pass a pointer to the member function that you want.
|

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.