Organizing repetitive ISRs, elegant solutions?

Note: I am a mechanic, machinist, fabricator, but not so much a programmer. I'd like to hear of perhaps better ways to go about organizing similar code or if my reasoning is flawed.

I've read quite a bit of documentation and done some searching but have not found any specific example of an array of structures containing ISRs as member functions. Is that a valid way to declare them for the sake of readability?

I am building a controller for a car seat that has six motors which adjust position.
Each motor has the same set of attributes relevant to my program, so it makes sense to define an array of six structures containing the different variables.
Can I somehow define an ISR within the structure that can be used in the loop for each motor by indexing the array?

Example:

struct Position {
  long saved[4];
  long current;
};

struct Motor {
  const byte sensorPin;           // pins detecting rising edge of Hall sensor signal
  const byte switchPin[2];        // corresponding pins from switches
  const int value;                // corresponding nominal analogRead() values
  bool direction[2];              // [0]: forward    [1]: backward
  Position position;              // positions for each motor/axis (counting revolutions from front limit of travel)
  static unsigned int interruptDetected;  // flag for ISR
//  ISR to set flag
  static void track(void) {
    interruptDetected++;
  }
  void initializeISR() {
    attachInterrupt(digitalPinToInterrupt(sensorPin), track, RISING);
  }
} M[6] = {
  {26, A0, A2, 142},
  {24, A0, A2, 312},
  {22, A0, A2, 626},
  {23, A1, A3, 142},
  {25, A1, A3, 312},
  {27, A1, A3, 626}
};

void setup() {
  for (int m = 0; m < 6; m++)
  M[m].initializeISR();
}

void loop() {

  // read switches, actuate motors, etc...

  // interrupts used to track motors:
  for (int m = 0; m < 6; m++) { 
    if (M[m].interruptDetected) {
      if (M[m].direction[0]) {
        M[m].position.current -= M[m].interruptDetected;
      }
      else if (M[m].direction[1]) {
        M[m].position.current += M[m].interruptDetected;
      }
    M[m].interruptDetected = 0;
    }
  }
}

  

Is there a better way to get around defining 6 separate ISRs at the top of my program and then including attachInterrupt() for each?

Yes.  Don't use interrupts.  This application should be perfectly doable just using polling of encoder inputs.  Can it be presumed that only one axis will be active at a time?

What platform are you using?   ie. UNO, MEGA2560, etc.

For future reference, any variables used inside an ISR need to be declared as volatile: volatile - Arduino Reference

You can't use structure member function as ISR. It should be static non-member function.

it's unclear what you want the code to do. is there a plan to have additional code that manages saved positions that a person can select?

looks like you want to track the position of each motor using the interrupt, but i only see the interrupt incrementing a value. should it add a direction that can be either +/-1 to the position? (the current math operation is not correct)

i don't believe your ISR will be unique for each Motor structure and will increment the interruptDetected value for that struct

looks like you want to allow either switchPin to have an arbitrary direction rather than define pins for + and - directions

don't understand the purpose of struct Position.

so yes, there are a lot of issues with what you're attempting. a clearer explanation would help

does the car seat really have 6 motors, 6 axis? (i'm thinking 3: forward/back, up/down, seat back forward/back)

I have written code to work this way, however there is potential for all six motors to run simultaneously. I haven't yet put the complete circuit together, only so far tested with two motors. I am concerned that pulses will get missed if I am polling all motors while running all the rest of the program.

I am using the Due, and the frequency of the pulses for each motor range from about 120 Hz to 250 Hz. The time taken for a typical loop() to complete for the program so far is about 30 microseconds. If tracking all motors, maybe a little more. However, upon each motor stopping in a new position it saves the position to flash memory which can take a few hundred microseconds.

I included an absolute minimal portion of the code in an effort to be concise. The rest is just long and incomplete and I'm aiming to clean it up a bit. There are several positions for each axis being recorded for recall. Based on the direction that the motor is actuated which is also a member variable, the counted pulses are either added or subtracted to the position value.

The resistor encoded switches provide 4 different voltages (M.value) on 4 different wires (M.switchPin[]) for a total of 16 combinations (2 for each direction of each motor plus 4 for the buttons to select saved positions). M.switchPin[] are the pairs of wires, one for each direction.

There are a total of 9 members within the rest of the Position struct, I figured nesting it within the Motor struct would be the most efficient way to contain all position data for the motors.

There are indeed 6 motors, the three you describe as well as headrest up/down, knee rest up/down, and knee rest front/back. The seats are from a 2011 Mercedes SL 55 AMG (R230) and more sophisticated than the application calls for IMO.

See: Interrupt in class, ESP32 - #44 by PieterP

2 Likes

I read about this in C++ documentation and other forum discussions. Is this because the structure limits the scope of the function? Can an alternative approach be to include a pointer to each static non-member function in the corresponding struct?

Excellent resource. Thank you, I will look into this way of implementing ISRs for my program.

If done correctly, polling is significantly faster than using interrupts. Interrupts have latency, the overhead of saving and restoring register contents, etc.

The speed of the program is actually not so important. What I am uncertain of is if any of these pulses might be go undetected during periods of heavy loads for the microcontroller. Particularly while writing to flash memory.

That is certainly an unusual concern. Have you checked whether the write operation can be interrupted?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.