arandhaw
arandhaw

Reputation: 13

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?

Upvotes: 1

Views: 1021

Answers (1)

relent95
relent95

Reputation: 4732

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);
        ...
    }
    ...
};

Upvotes: 1

Related Questions