I'm familiar with several programming languages but Arduino is giving me the opportunity to learn another - c++
I've figured out how to make a library and made one to handle the creation and management of simple button switches. This library works fine but I'm having trouble using it in a new library I'm making. Here is a simplified copy of my Button library...
// Button.h
class Button{
public:
Button(int pin);
bool on();
bool click();
int latency;
private:
int _pin;
int _state;
int _last;
unsigned long _click;
};
The code is omitted from Button.cpp only to save space. I am releasing the code under GPL so just hit me up if you want the full file.
So, if I put #include "Button.h" at the beginning of a project, I can use this class like this:
Button myButton = Button(2);
if(myButton.click()){
// do something
}
...but I can only do this in a main project file.
When I try to do that from within another custom library, I get compile errors. I've isolated it to having something to do with declaring the variables or my include statements but I've searched online and tried everything I can think of without success. Here are the new library files (simplified for easy reading):
// Signal.h
class Signal{
public:
TurnSignal();
private:
Button myButton;
};
I seem to recall something from another thread a while ago where you need to put the full path or a relative path to the library header file for it to work.
i.e. Signal.h can't work without including Button.h first, because it refers to a class defined in Button.h. In the snippet you've given, you don't show Signal.h being included at all, though I assume you did - but possibly in the wrong order?
You simply need to include the same library file (in this case, Bounce.h) in the main sketch.
The reason is that the arduino software copies all of the relevant files to a temporary directory to compile them, and it only thinks a file is "relevant" if the .h file is included.
Including the full path will let the compiler find the .h file, but it won't link correctly -- the linker won't be able to find the .cpp file.
@marco_c - I tried "../Button/Button.h", didn't work
@Andy2No - You are correct, in my attempt at minimizing the code example, I left out #include "Signal.h" from Signal.cpp. In my actual file it is there but I get the errors. Also, in my file I had Button.h below Signal.h so I tried switching it to look like your code but it still didn't work
@WizenedEE - I put Button.h in the main sketch below Signal.h and got the same error. I switched it so Button.h came first and got a whole mess of errors starting with "error: no matching function for call to 'Button::Button()'".
Thanks for all the quick suggestions, unfortunately nothing has worked
// Button.h
class Button{
public:
Button(int pin = 0);
bool on();
bool click();
int latency;
private:
int _pin;
int _state;
int _last;
unsigned long _click;
};
@Nick Gammon - hmm, I tried that but it didn't work for me
However, I have found the answer!
When I took the declaring statement Button myButton; out of Signal.h, and declared myButton in the cpp file, I got a different error: 'myButton' was not declared in this scope
I'm still pretty new to c++ so I don't fully understand the use of "extern" but in my searching I found several references to it, none of which directly helped. But, I understand what the scope error was talking about - I had declared it in the constructor which then would not let me use it outside of the constructor. So I have to declare it outside of the constructor. I did this and it worked...
// Signal.h
class Signal{
public:
Signal();
private:
It looks to me like you either need a default constructor for the button class or you need to learn about constructor initializer lists and composition.
Short version:
Define the constructor for your class containing button thus:
Damn, I thought I did solve the problem. I went to bed last night all feeling good about myself too, lol oh well.
I guess my attempts to simplify my examples for this post made things more confusing for y'all so let me try to explain what's going on...
The Button library doesn't do much more than read the input, but it's got one function that keeps track of timing so you can look for a button press and then have some buffer time where it won't return true for half a second - preventing potential multiple reads which would turn the signals on and off repeatedly in a single physical button press - myButton.click()
The signal library uses the button library to handle the on/off buttons - there will be two buttons defined in the signal library once I figure out how to get it working at all.
Also, there is another library I'm trying to use to control a WS2801 controlled strip of RGB LEDs and I'm getting the same results trying to declare it as well so I know it just has something to do with the declarations.
The bottom line is, I need to use a class from one library as a data type for a variable inside a class of another library. I think the fact that c++ splits libraries into two files is what's really tripping me up. Sorry, like I said, I've been programming other languages for a long time but I've just not had the need/opportunity to learn c++ until now so I don't know all of it's quirks yet.
Ah, C++ doesn't split anything into anything. You did that.
You can have multiple libraries in one file, and they can all be inside your project (ie. not libraries at all). Your physical organization of the source files is up to you.
Unless you are planning to have multiple instances of things (eg. multiple buttons) making everything a class is just making things hard for yourself. Even multiple buttons can be managed as an array of buttons.
Sure, classes are useful. But if you aren't comfortable with them do a few tutorials before launching into putting them in your project.
My apologies, I was under the impression that library cpp files required an h file. Like I said I'm new to c++ and I'm just going off of resources I can find on my own.
I don't really need things to be in libraries. I started by putting all my code in the main sketch and everything works just fine. The project was a turn-signal system for my bike and it is working perfectly!
I just thought it would be cool to break up reusable parts of the code by building libraries and in the process learn how libraries work in c++. The logic of my code overall works, I just don't know the exact syntax for using a class from another library in a library and my googling has not found me the correct answer.
Yes, I am overthinking this project. This project is not important, I just want to learn how to do things in c++. Sorry to be just another noob bugging the vets
Well, I've made some progress but I'm still stuck. I figured out how to get the Button instance declared in the Signal.h file but now I can't figure out how to initialize and use it. The error I'm getting on the line that calls the Button constructor is: undefined reference to 'Button::Button()'
Signal\Signal.cpp.o: In function `Signal::go()':
C:\Program Files (x86)\Arduino\libraries\Signal/Signal.cpp:12: undefined reference to `Button::on()'
Signal\Signal.cpp.o: In function `Signal':
C:\Program Files (x86)\Arduino\libraries\Signal/Signal.cpp:6: undefined reference to `Button::Button()'
C:\Program Files (x86)\Arduino\libraries\Signal/Signal.cpp:8: undefined reference to `Button::Button()'
C:\Program Files (x86)\Arduino\libraries\Signal/Signal.cpp:9: undefined reference to `Button::initialize(int)'
Tell you what ... zip up the entire thing (both libraries, sketch etc.) and post that as an attachment (click on Additional Options). I'm not going to spend 20 minutes trying to recreate your exact files and layout.
Yes, I agree. Looks like the sketch needs an include to the button library.
Also, _mybutton is an automatic class variable, it is initialised before the signal library constructor is called.
You do not initialise them in this way:
_mybutton = Button();
This is what happens behind the scene.
Signal::Signal() : _buttonpin(), _mybutton(){ //<<Initialiser list.
_buttonpin = 2;
_mybutton = Button();
_mybutton.initialize(_buttonpin);
}
//allowing you to explicitly write code like below.
Signal::Signal() : _buttonpin( 2 ), _mybutton(){
_mybutton.initialize(_buttonpin);
}