Now I want to use the functions in one or more libraries of my own creation. Alll the code of PinChangeInt is in a single PinChangeInt.h header file. If the latter is included in multiple places, I unsurprisingly get warnings about duplicated functions.
I could modify PinChangeInt to separate interface and implementation into separate .h and .cpp files. Before I embark on this task, I thought I would ask if anyone else has encountered this issue, and if there is a simpler workaround!
The problem with pin change interrupts is that, on the Atmega328 at least, you get three interrupts (three ISRs).
Some information here:
Now you just can't, for example, have four libraries that each try to implement those ISRs. In fact any library that uses pin change interrupts may "take over" all of them, or at least one of them. In other words, the same ISR can't be implemented more than once.
Maybe a better solution would present itself if you didn't try to describe the low level problem (trying to manage lots of pin change interrupts) but the higher level problem (what you are actually trying to achieve).
Back to the original thread - I don't want to implement lots of interrupts, and I understand the limitations of AVR, but....
I would like to be able to encapsulate low-level stuff within a library, and hide the nuts and bolts from the user. To this end, I would like to be able to attach and detach interrupts within library functions. But as I have to include PinChangeInt.h, which includes the implementation, it seems I can only do this for one library. If I want to attach another pin change interrupt within another library, I can't.
The alternative seems to be to only include PinChangeInt.h in the top sketch, and make all calls to attachInterrupt() and detachInterrupt() in the top sketch. Which seems messy.
Also, in my library code, it seems I have to include desired header files by relative path:
For a start, attachInterrupt/detachInterrupt only refer to the external interrupts, not the pin change ones. They did that by making a level of indirection where the "real" interrupt calls a function stored in an array (by attachInterrupt).
There is a cost ... the attachInterrupt handlers are slower than "pure" interrupt handlers.
If you try to add your own indirection you will be adding this extra cost. Bearing in mind interrupt handlers are supposed to be as fast as possible.
Also I don't like the idea of:
I would like to be able to attach and detach interrupts within library functions ...
I hope you don't mean continuously, because interrupts by their nature are unpredictable. The best you could probably do is chain them, and even that might not be optimal - both for speed reasons, and the question of "which handler gets to be serviced first?".
I'm inclined to ask "what problem are you trying to solve?". The idea of nice libraries is all well and good, but this is a $5 chip with some limitations. At times we have to work within those rather than trying to be too general.
Sorry, laziness on my part. I meant PCintPort::attachInterrupt() and PCintPort::detachInterrupt()
Not intending to be attaching and detaching continually. Just wanted to hide the low level configuration from the end user of a library, so that the attaching is not done in the top sketch. I suppose I could define a preprocessor macro in the library header file, which then gets put in the top sketch, and expanded when the PCintPort methods are in the compiler scope.
peterc12:
Sorry, laziness on my part. I meant PCintPort::attachInterrupt() and PCintPort::detachInterrupt()
Not intending to be attaching and detaching continually. Just wanted to hide the low level configuration from the end user of a library, so that the attaching is not done in the top sketch. I suppose I could define a preprocessor macro in the library header file, which then gets put in the top sketch, and expanded when the PCintPort methods are in the compiler scope.
Point taken about the $5 chip though...
Thanks for your input.
In the header of the PinChangeInt.h file, I write:
The library has been modified so it can be used in other libraries, such as my AdaEncoder library
(Google Code Archive - Long-term storage for Google Code Project Hosting.). When #include'd by another library you should #define
the LIBCALL_PINCHANGEINT macro. For example: #ifndef PinChangeInt_h #define LIBCALL_PINCHANGEINT #include "../PinChangeInt/PinChangeInt.h" #endif
This is necessary because the IDE compiles both your sketch and the .cpp file of your library, and
the .h file is included in both places. But since the .h file actually contains the code, any variable
or function definitions would occur twice and cause compilation errors- unless #ifdef'ed out.