4

Okay so you aren't able to pass a variable into in ISR. This is causing problems for me. I'm using a rotary encoder, and I need it to be connected to an interrupt pin and running a ISR. When using this method, no pulses are ever skipped and the knob works great.

Currently I have the ISR setup like this:

void vhISR()
{
  // this checks the PINE register for a 1 or 0 on the 5th bit (or 6th)
  // I'm bit shifting the result so that variable is either true or false for comparison, not 16/0 or 32/0
  rotCurrentA = (PINE & B00010000) >> 4; 
  rotB = (PINE & B00100000) >> 5;

if (rotCurrentA != rotLastA) { if (rotCurrentA != rotB) // cw { voltageHigh += knobResolution; rotLastA = rotCurrentA; } else // ccw { voltageHigh -= knobResolution; rotLastA = rotCurrentA; } } }

The code simply varies voltageHigh by 0.1V increments. The problem is this: I need to do this same 0.1 variations on several other variables, depending on which one I select. I need to increase/decrease a voltageLow, a timer, and a resistance, all that need +/- 0.1 increments (but on different ranges. For instance, voltLow is somewhere between 0.1 & 5, and VH is somewhere between 6 & 10). Normally what I would do is just pass the variable I needed by reference into the function and have the function increment/decrement that variable....but an ISR is not a normal function and you cannot pass a variable into it.

How do I get around this? I'm not sure if that's enough information to go off of let me know.

AJ_Smoothie
  • 504
  • 4
  • 13

2 Answers2

8

I would follow Delta_G's advice, and write an ISR that counts the steps and does nothing more. As a general rule, you want to do as little as possible within an ISR. I would even avoid floating point and just count the raw number of steps:

// Count of rotational steps updated in the ISR. Must be unsigned in
// order to avoid signed overflow, which is undefined behavior.
volatile uint16_t rotation_count;

void vhISR() { static uint8_t rotLastA; uint8_t rotCurrentA = (PINE >> 4) & 1; uint8_t rotB = (PINE >> 5) & 1;

if (rotCurrentA != rotLastA)
    return;
if (rotCurrentA != rotB) // cw
    rotation_count++;
else // ccw
    rotation_count--;
rotLastA = rotCurrentA;

}

// Return the number of rotational steps since the last call. Should be // called often enough to avoid overflowing an int16_t. int16_t get_rotation() { static uint16_t last_count;

// Avoid a data race: rotation_count should not be modified while we
// are reading it.
noInterrupts();
uint16_t count_copy = rotation_count;
interrupts();
int16_t delta = count_copy - last_count;  // this is signed!
last_count = count_copy;
return delta;

}

Note that the raw count is an unsigned number which can roll over modulo 216. The value returned by get_rotation(), however, is a signed number which, owing to the rules of modular arithmetic, is immune to the rollover of the raw count. As long as you call get_rotation() often enough (more often than every 32767 steps), the returned value will always be correct.

Then, in your main program, you can use this to update whatever variable you want:

const float knobResolution = 0.1;
float voltageHigh, voltageLow, resistance;

// The variable that the user has selected for changing. enum {VOLTAGE_HIGH, VOLTAGE_LOW, RESISTANCE} selection;

void loop() { // Set a pointer to the selected variable. float *selected_var; switch (selection) { case VOLTAGE_HIGH: selected_var = &voltageHigh; break; case VOLTAGE_LOW: selected_var = &voltageLow; break; case RESISTANCE: selected_var = &resistance; break; }

// Update the selected variable.
*selected_var += get_rotation() * knobResolution;

}

Note here that the selection enum is probably redundant with selected_var. You could use the latter to keep track of the user selection, then you would not need the switch/case.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81
2

Okay so you aren't able to pass a variable into in ISR ...

Not as such, because the ISR is triggered by hardware, and therefore you don't pass arguments to it.

However there is nothing stopping you having a global variable which the ISR can access (preferably declared volatile) so the ISR can change its behaviour depending on what the global variable holds.

Nick Gammon
  • 38,901
  • 13
  • 69
  • 125