Search code examples
c++classarduinomicrocontrollerinterrupt

create encoder class with interrupts for STM32 (C++)


I'm using an encoder to track the position of a motor. The encoder sends pulses to a stm32 microcontroller, which calls an interrupt function on every rising edge. The ISR must be a global function, with no parameters, and return void.

void setup() {
    attachInterrupt(pin_number, ISR_function, RISING);
}

void ISR_function() {
    //do something
    counter++; 
}

I've created an encoder class, but its kind of ugly. Each encoder needs its own interrupt function, which increments a counter. I only have two encoders, so I wrote two ISR's above my class. In my class, the constructor takes an integer (either 1 or 2) and assigns ISR 1 or ISR 2 depending on this. Hence, I can only have two encoders, and additional encoders require more copy/pasting. Skeleton of my code:

volatile int counter1;
volatile int counter2; 

void ISR1{
     counter1++;
}

void ISR2{
     counter2++;
}

class Encoder{
  private:
    int pin, num;
  public:
    Encoder(int pin, int num){
        if(num == 1){ attachInterrupt(pin, ISR1, RISING); }
        if(num == 2){ attachInterrupt(pin, ISR2, RISING); }
        this-> pin = pin;
        this-> num = num;
    }
    //functions that do things with counter
};

This isn't really a class in the abstract sense. How can I make a class that can handle an arbitrary number of encoders without writing a new ISR for each one? Is there a way to automatically create these functions from inside the class?


Solution

  • If you have attachInterruptParam(), use it like the following.

    class Encoder {
    protected:
        static void staticOnInterrupt(void *this_) {
            ((Encoder *)this_)->onInterrupt();
        }
        void onInterrupt() {
            ...
        }
    public:
        Encoder(int pin, int num) {
            ...
            attachInterruptParam(pin, staticOnInterrupt, RISING, this);
            ...
        }
        ...
    };
    

    If you don't, you probably have this C++ API.

    typedef std::function<void(void)> callback_function_t;
    void attachInterrupt(uint32_t pin, callback_function_t callback, uint32_t mode);
    

    Then, use it like the following.

    class Encoder {
    protected:
        void onInterrupt() {
            ...
        }
    public:
        Encoder(int pin, int num) {
            ...
            attachInterrupt(pin, std::bind(&Encoder::onInterrupt, this), RISING);
            ...
        }
        ...
    };