Search code examples
c++arduinomicrocontrollerinterruptinterrupt-handling

Does every interrupt need its own function?


I am currently planning a project which includes multiple rotary encoders which I want to wire to interrupt pins to reliably get inputs from them. I want every encoder to do essentially the same thing but dependent on which encoder is turned, some variables in the code will have to change.

Do I have to write a separate function for each one of them? It is not possible to pass an argument (the interrupt pins number in this case) to the called function from the attachInterrupt and I don't really see any other viable option than to write 5 functions (rotary1() rotary2()...) containing the exact same code with a few variables changed.

One other option I thought of would be to call an "intermediary" function which checks for the currently relevant pin and then calls the rotary function with this information passed down, but this is far from an elegant solution and probably slows down the whole process a lot. I really don't want to have to do a separate check for which encoder is being turned because this information is already there, I just don't know how to access it.

I would appreciate if someone with more experience could point me in the right direction here, as it seems very wrong to me even as a relative beginner to write the same code so many times.


Solution

  • As you found, you need as many ISRs as there are pins. But you don't need to duplicate the code in them.

    Note: Depending on your algorithm, you might need more than one handling function, for example if you use both inputs of a encoder to interrupt.

    The C way

    Write a single separated function that takes as many parameters as you see fit.

    Call this function from your ISRs with the appropriate parameters.

    void handleInterrupt(int which) {
        // do whatever you like to do with "which"
    }
    
    void interruptServiceRoutine1() {
        handleInterrupt(1);
    }
    
    void interruptServiceRoutine2() {
        handleInterrupt(2);
    }
    
    void interruptServiceRoutine3() {
        handleInterrupt(3);
    }
    

    The C++ way

    Write a class to represent a rotary encoder. Include a method that handles the interrupt.

    Call this method with the respective rotary encoder object from your ISRs.

    class RotaryEncoder {
    public:
        void handleInterrupt();
    };
    
    void RotaryEncoder::handleInterrupt() {
        // do whatever you like to do
    }
    
    RotaryEncoder rotaryEncoder1;
    RotaryEncoder rotaryEncoder2;
    RotaryEncoder rotaryEncoder3;
    
    void interruptServiceRoutine1() {
        rotaryEncoder1.handleInterrupt();
    }
    
    void interruptServiceRoutine2() {
        rotaryEncoder2.handleInterrupt();
    }
    
    void interruptServiceRoutine3() {
        rotaryEncoder3.handleInterrupt();
    }