[SOLVED] My (oversized?) ISR is sluggish/missing counts.

Hello good people of Arduino land! :slight_smile:

I am (still) working on my code for the water drop controller.
I have decided to ditch the six potentiometer control (mechanical memory issues),in favour of a single rotary encoder (with six counters) which is debounced and uses a hardware interrupt on digital pin 2.

The rotary encoder I am using is the Keyes KY-040, and I am using a generic (I2C) 16x2 LCD to display the 'live' data, and six tactile switches to select the relevant value.
(I will probably refine this to a two button 'up/down' or 'left/right. system later....or maybe a switch/case menu)

All was going well with a single value...so I added another counter within the interrupt, and that too worked well.

Since I need the single rotary encoder to produce six values, I added all six counters within the ISR.
This has worked to an extent, but now I am seeing a drastic reduction in performance.

The counters (encoderPos# in my case) within the ISR, are very sluggish, and missing counts regularly.
I sort of knew this was going to happen, since I am aware that ISRs should be 'short-and-sweet'.

I would like to know if there is any way to compress the lengthy code within my ISR, and still maintain the same functionality?
Or would 'Pin Change Interrupts' be the answer?
(Pin Change Interrupts seem complex and a little scary to me as a beginner, but if it's the only answer, then I am willing to learn)

Full sketch is in the next post.

Thank you in advance, and please forgive my clunky/awkward coding....I'm still very much a beginner!
(Of course I would welcome any general advice on tidying up my code to make it more efficient too.)

Full sketch:

#include <digitalIOPerformance.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

const byte encPinA = 2;
const byte encPinB = 3;
const byte encSw = 4;

const byte button1 = 6;
const byte button2 = 7;
const byte button3 = 8;
const byte button4 = 9;
const byte button5 = 10;
const byte button6 = 11;

int value1Last = 0;
int value2Last = 0;
int value3Last = 0;
int value4Last = 0;
int value5Last = 0;
int value6Last = 0;

bool button1state = HIGH;
bool button2state = HIGH;
bool button3state = HIGH;
bool button4state = HIGH;
bool button5state = HIGH;
bool button6state = HIGH;

volatile int encoderPos1 = 0;
volatile int encoderPos2 = 0;
volatile int encoderPos3 = 0;
volatile int encoderPos4 = 0;
volatile int encoderPos5 = 0;
volatile int encoderPos6 = 0;

void isr () {

  static unsigned long debounceLast = 0;
  unsigned long debounce = millis();

  if (debounce - debounceLast > 5) {
    if (digitalRead(button1) == LOW) {
      if (digitalRead(encPinB) == LOW) {
        encoderPos1++ ;
      } else {
        encoderPos1-- ;
      }
    }

    if (digitalRead(button2) == LOW) {
      if (digitalRead(encPinB) == LOW) {
        encoderPos2++ ;
      } else {
        encoderPos2-- ;
      }
    }

    if (digitalRead(button3) == LOW) {
      if (digitalRead(encPinB) == LOW) {
        encoderPos3++ ;
      } else {
        encoderPos3-- ;
      }
    }

    if (digitalRead(button4) == LOW) {
      if (digitalRead(encPinB) == LOW) {
        encoderPos4++ ;
      } else {
        encoderPos4-- ;
      }
    }

    if (digitalRead(button5) == LOW) {
      if (digitalRead(encPinB) == LOW) {
        encoderPos5++ ;
      } else {
        encoderPos5-- ;
      }
    }

    if (digitalRead(button6) == LOW) {
      if (digitalRead(encPinB) == LOW) {
        encoderPos6++ ;
      } else {
        encoderPos6-- ;
      }
    }
    encoderPos1 = min(199, max(0, encoderPos1));
    encoderPos2 = min(199, max(0, encoderPos2));
    encoderPos3 = min(199, max(0, encoderPos3));
    encoderPos4 = min(199, max(0, encoderPos4));
    encoderPos5 = min(199, max(0, encoderPos5));
    encoderPos6 = min(199, max(0, encoderPos6));
  }
  debounceLast = debounce;
}

void setup() {

  Serial.begin(9600);

  lcd.init();
  lcd.backlight();
  lcd.begin(16, 2);
  lcd.clear();

  pinMode(encPinA, INPUT_PULLUP);
  pinMode(encPinB, INPUT_PULLUP);
  pinMode(encSw, INPUT_PULLUP);
  
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);
  pinMode(button4, INPUT_PULLUP);
  pinMode(button5, INPUT_PULLUP);
  pinMode(button6, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(encPinA), isr, LOW);
}

void loop() {

  button1state = digitalRead(button1);
  button2state = digitalRead(button2);
  button3state = digitalRead(button3);
  button4state = digitalRead(button4);
  button5state = digitalRead(button5);
  button6state = digitalRead(button6);

  lcd.setCursor(1, 0);
  lcd.print(encoderPos1);
  lcd.setCursor(5, 0);
  lcd.print(encoderPos2);
  lcd.setCursor(9, 0);
  lcd.print(encoderPos3);
  lcd.setCursor(1, 1);
  lcd.print(encoderPos4);
  lcd.setCursor(5, 1);
  lcd.print(encoderPos5);
  lcd.setCursor(9, 1);
  lcd.print(encoderPos6);

  ///////////////////////////////////
  ////          VALUE 1          ////
  ///////////////////////////////////

  if (button1state == LOW) {

    lcd.setCursor(0, 0);
    lcd.print(">");
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(8, 0);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(4, 1);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(" ");

    digitalWrite(button1, LOW);
    digitalWrite(button2, HIGH);
    digitalWrite(button3, HIGH);
    digitalWrite(button4, HIGH);
    digitalWrite(button5, HIGH);
    digitalWrite(button6, HIGH);

    if (!digitalRead(encSw)) {
      encoderPos1 = 0;
      lcd.setCursor(1, 0);
      lcd.print(encoderPos1);
      lcd.setCursor(1, 0);
      lcd.print("   ");
      while (!digitalRead(encSw))
        delay(10);
    }

    if (encoderPos1 != value1Last) {
      lcd.setCursor(1, 0);
      lcd.print(encoderPos1);
      lcd.setCursor(1, 0);
      lcd.print("   ");
      value1Last = encoderPos1;
    }
  }

  ///////////////////////////////////
  ////          VALUE 2          ////
  ///////////////////////////////////

  if (button2state == LOW) {

    lcd.setCursor(0, 0);
    lcd.print(" ");
    lcd.setCursor(4, 0);
    lcd.print(">");
    lcd.setCursor(8, 0);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(4, 1);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(" ");

    digitalWrite(button1, HIGH);
    digitalWrite(button2, LOW);
    digitalWrite(button3, HIGH);
    digitalWrite(button4, HIGH);
    digitalWrite(button5, HIGH);
    digitalWrite(button6, HIGH);

    if (!digitalRead(encSw)) {
      encoderPos2 = 0;
      lcd.setCursor(5, 0);
      lcd.print(encoderPos2);
      lcd.setCursor(5, 0);
      lcd.print("   ");
      while (!digitalRead(encSw))
        delay(10);
    }

    if (encoderPos2 != value2Last) {
      lcd.setCursor(5, 0);
      lcd.print(encoderPos2);
      lcd.setCursor(5, 0);
      lcd.print("   ");
      value2Last = encoderPos2;
    }
  }

  ///////////////////////////////////
  ////          VALUE 3          ////
  ///////////////////////////////////

  if (button3state == LOW) {

    lcd.setCursor(0, 0);
    lcd.print(" ");
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(8, 0);
    lcd.print(">");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(4, 1);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(" ");

    digitalWrite(button1, HIGH);
    digitalWrite(button2, HIGH);
    digitalWrite(button3, LOW);
    digitalWrite(button4, HIGH);
    digitalWrite(button5, HIGH);
    digitalWrite(button6, HIGH);

    if (!digitalRead(encSw)) {
      encoderPos3 = 0;
      lcd.setCursor(9, 0);
      lcd.print(encoderPos3);
      lcd.setCursor(9, 0);
      lcd.print("   ");
      while (!digitalRead(encSw))
        delay(10);
    }

    if (encoderPos3 != value3Last) {
      lcd.setCursor(9, 0);
      lcd.print(encoderPos3);
      lcd.setCursor(9, 0);
      lcd.print("   ");
      value3Last = encoderPos3;
    }
  }

....the final part of the sketch is on the next page due to the 9000 char limit!

....final piece of the sketch:

  ///////////////////////////////////
  ////          VALUE 4          ////
  ///////////////////////////////////

  if (button4state == LOW) {

    lcd.setCursor(0, 0);
    lcd.print(" ");
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(8, 0);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print(">");
    lcd.setCursor(4, 1);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(" ");

    digitalWrite(button1, HIGH);
    digitalWrite(button2, HIGH);
    digitalWrite(button3, HIGH);
    digitalWrite(button4, LOW);
    digitalWrite(button5, HIGH);
    digitalWrite(button6, HIGH);

    if (!digitalRead(encSw)) {
      encoderPos4 = 0;
      lcd.setCursor(1, 1);
      lcd.print(encoderPos4);
      lcd.setCursor(1, 1);
      lcd.print("   ");
      while (!digitalRead(encSw))
        delay(10);
    }

    if (encoderPos4 != value4Last) {
      lcd.setCursor(1, 1);
      lcd.print(encoderPos4);
      lcd.setCursor(1, 1);
      lcd.print("   ");
      value4Last = encoderPos4;
    }
  }

  ///////////////////////////////////
  ////          VALUE 5          ////
  ///////////////////////////////////

  if (button5state == LOW) {

    lcd.setCursor(0, 0);
    lcd.print(" ");
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(8, 0);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(4, 1);
    lcd.print(">");
    lcd.setCursor(8, 1);
    lcd.print(" ");

    digitalWrite(button1, HIGH);
    digitalWrite(button2, HIGH);
    digitalWrite(button3, HIGH);
    digitalWrite(button4, HIGH);
    digitalWrite(button5, LOW);
    digitalWrite(button6, HIGH);

    if (!digitalRead(encSw)) {
      encoderPos5 = 0;
      lcd.setCursor(5, 1);
      lcd.print(encoderPos5);
      lcd.setCursor(5, 1);
      lcd.print("   ");
      while (!digitalRead(encSw))
        delay(10);
    }

    if (encoderPos5 != value5Last) {
      lcd.setCursor(5, 1);
      lcd.print(encoderPos5);
      lcd.setCursor(5, 1);
      lcd.print("   ");
      value5Last = encoderPos5;
    }
  }

  ///////////////////////////////////
  ////          VALUE 6          ////
  ///////////////////////////////////

  if (button6state == LOW) {

    lcd.setCursor(0, 0);
    lcd.print(" ");
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(8, 0);
    lcd.print(" ");
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(4, 1);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(">");

    digitalWrite(button1, HIGH);
    digitalWrite(button2, HIGH);
    digitalWrite(button3, HIGH);
    digitalWrite(button4, HIGH);
    digitalWrite(button5, HIGH);
    digitalWrite(button6, LOW);

    if (!digitalRead(encSw)) {
      encoderPos6 = 0;
      lcd.setCursor(9, 1);
      lcd.print(encoderPos6);
      lcd.setCursor(9, 1);
      lcd.print("   ");
      while (!digitalRead(encSw))
        delay(10);
    }

    if (encoderPos6 != value6Last) {
      lcd.setCursor(9, 1);
      lcd.print(encoderPos6);
      lcd.setCursor(9, 1);
      lcd.print("   ");
      value6Last = encoderPos6;
    }
  }
}

Once again, many thanks for any suggestions or guidance. :slight_smile:

Why are you doing so much in the ISR ?
The normal strategy is to do as little as possible, perhaps the save the current time from millis() and a flag variable to indicate that it has occurred. Then, in loop(), if the interrupt has occurred do whatever is required

There is also the question as to whether you need the ISR in the first place

bongobreak:
Since I need the single rotary encoder to produce six values, I added all six counters within the ISR.

I am struggling to understand what this means, can you elaborate on what you're trying to do?

Hi UKHeliBob, thanks for the reply.
(Fellow East Anglian here!!)

UKHeliBob:
Why are you doing so much in the ISR ?

A lack of knowledge is the simple answer to that!
I've only recently begun to understand rotary encoders and interrupts, so I'm at the bottom of a steep (to me) learning curve!

The normal strategy is to do as little as possible, perhaps the save the current time from millis() and a flag variable to indicate that it has occurred. Then, in loop(), if the interrupt has occurred do whatever is required

You're right of course, I did indeed realise that ISRs should be short, and I expected to have issues, I just wondered if there was a way to mitigate which is easy to understand for a thicko like me!
I will take your advice and learn about how to use a flag variable, thanks Bob!

There is also the question as to whether you need the ISR in the first place

Indeed, I realise that interrupts are way faster than is needed for a human controlled rotary encoder, but I've tried it without interrupts, and due to the cheapness/noisy contacts, I've yet to satisfactorily get clean counts.

Again, a lack of knowledge is somewhat letting me down here - I am willing to learn however.

Hi @wildbill, thanks for your reply.

wildbill:
I am struggling to understand what this means, can you elaborate on what you're trying to do?

My thinking is to simply reduce the number of pins I'm using on my ATMega328P-PU chips.
I was using six potentiometers to vary the values, but since I only have six analog pins, and I'm already using two of those for I2C, I surmised that a different input method was needed.

I began with trying to use six rotary encoders, but again, I ran into I/O pin shortage - each encoder needs three pins, so that's 18 in total - not possible for the 328.

So that lead me down the path of trying to use a single rotary encoder to vary the six values.
I've had a partial success, as aforementioned, but it's sluggish, and so I wondered if there was anything I could do to compress my ISR and have it run a lot quicker.

I don’t see why you don’t just track the one physical rotary encoder, however you decide, and then use what it tells you to control values elsewhere defending on the state of your program.

If the rotary value changes, adjust whatever parameter(s) you are talking to at the moment.

If you use an ISR, all it needs to do is handle one thing. It is overkill maybe. If you can manage a look at the encoder every millisecond or so in your main loop you be fine.

Explain why you’d need to handle, wherever, all six things always.

a7

Firstly, rotary encoders debounce themselves if done correctly. They output a two bit grey code, and only one bit changes at any one point in the rotation. So there’s no need to do your own debounce, unless you want to make life difficult.

Secondly, when you don’t know how to do something, start with one of them and, when you have that working, extend to handle switching between 6 of them.

I would also suggest ditching the ISR, at least until you get the rotary encoder working. Just check the two inputs from the encoder each time through loop, check for changes since last time, and by comparing the grey codes detect the direction of rotation.

There are many libraries available for handling encoders, but if you want to roll your own (good learning exercise, so I’ve no problem with that), however I would suggest studying first to see how it works.

Edit: As an example with good explanation of how it works see here.

void isr () {

  static unsigned long debounceLast = 0;

Forgot to declare debounceLast as volatile....

Yes, pin-change interrupts may be useful - upto 8 pins mapped to each ISR on the Uno. You'd
use bit masks to detect the subset of pins that have actually changed and only iterate through that
set (probably only one in your application).

However you might want to consider using direct-port-manipulation here to get snappier ISR
response. The code is highly repetitive which suggests you should be using arrays for the
button pin numbers and encoder position variables (won't speed it up, will make it readable and
easy to change in the future).

Hi @alto777, thanks for your reply.

alto777:
I don’t see why you don’t just track the one physical rotary encoder, however you decide, and then use what it tells you to control values elsewhere defending on the state of your program.

Simply put, I don't know how to do that yet!
Of course your advice makes perfect, logical sense, and it's something that I will need to learn how to do.

If the rotary value changes, adjust whatever parameter(s) you are talking to at the moment.

I initially tried to do something along those lines, but ended up getting into all kinds of knots!
So I thought I'd dump all the counters into the ISR....and we know how that turned out!

If you use an ISR, all it needs to do is handle one thing. It is overkill maybe. If you can manage a look at the encoder every millisecond or so in your main loop you be fine.

Of course you're right, it is overkill, but it's the only way I know (so far) to get clean increments/decrements, all the other methods I've tried seem to either only count in one direction (whichever way I turn it) or not count cleanly.
I know this is almost certainly related to switch bounce (and a distinct lack of knowledge on my part), and for sure I will learn how to debounce them more efficiently.

Explain why you’d need to handle, wherever, all six things always.

I don't need to, but I'm struggling to find a way to avoid it.
I really am in need of some nudges in the right direction!

Thanks for the advice @pcbbc.

pcbbc:
Firstly, rotary encoders debounce themselves if done correctly. They output a two bit grey code, and only one bit changes at any one point in the rotation. So there’s no need to do your own debounce, unless you want to make life difficult.

Thanks for the good advice pcbbc, duly noted.
The key part of your sentence however, is '...if done correctly.'
This is the bit I'm struggling with!

That said, it seemed fairly straightforward to add a simple debounce to the ISR.
It works well enough, and I think I can understand it.

Secondly, when you don’t know how to do something, start with one of them and, when you have that working, extend to handle switching between 6 of them.

Quite right. I initially thought I was getting somewhere when I achieved a decent result using a single value, so maybe I tried to 'run before I could walk' when I expanded it to six values.

I would also suggest ditching the ISR, at least until you get the rotary encoder working. Just check the two inputs from the encoder each time through loop, check for changes since last time, and by comparing the grey codes detect the direction of rotation.

Good advice, but I had spent quite a while trying to achieve satisfactory results without using an ISR, and it drove me round the bend!!
I realise that this is mainly because I don't know enough yet...something I am addressing as we speak!
However, when I moved to an ISR, everything just worked perfectly!
I really do appreciate your advice, and the time taken to respond -

There are many libraries available for handling encoders, but if you want to roll your own (good learning exercise, so I’ve no problem with that), however I would suggest studying first to see how it works.

Good advice again, thanks.

So I shall pare down my code again, and start with a single encoder/single value but I think I will be sticking with the ISR approach for now...it just seems more efficient to me so far.

Hi @MarkT, thanks for replying.

MarkT:

void isr () {

static unsigned long debounceLast = 0;



Forgot to declare debounceLast as volatile....

Does it need to be volatile, when it is only used inside the ISR?
Or have I grossly misunderstood the meaning of 'volatile'?
(This is entirely likely!)

Thanks to everyone that has taken the time to offer advice, it is most appreciated! :slight_smile:

I'd use the interrupt to set a single encoder count and a flag to indicate that something changed. In loop, check the flag and if it's set, see what happened on the encoder. Then check which button is pressed and apply the change to its count & reset the flag.

Actually, having written that, maybe it's easier to have two flags: count up & count down which you clear after applying a change to the counter for the button that's pressed.

wildbill:
I'd use the interrupt to set a single encoder count and a flag to indicate that something changed. In loop, check the flag and if it's set, see what happened on the encoder. Then check which button is pressed and apply the change to its count & reset the flag.

Actually, having written that, maybe it's easier to have two flags: count up & count down which you clear after applying a change to the counter for the button that's pressed.

Thanks @wildbill.

I am struggling to wrap my head around the concept of 'flags'
I know I must seem like an awful thicko, sorry about that!

I am sure that I will have that 'Eureka' - 'light-bulb-moment' soon enough, but so far the light bulb is definitely still off!!

So my pared down ISR now looks like this:

void isr () {

  static unsigned long debounceLast = 0;
  unsigned long debounce = millis();

  if (debounce - debounceLast > 5) {
    if (digitalRead(encPinB) == LOW) {
      encoderPos++ ;
    } else {
      encoderPos-- ;
    }
    encoderPos = min(199, max(0, encoderPos));
  }
  debounceLast = debounce;
}

....where encoderPos is declared as volatile, naturally.

I'm still not sure where I would place the flags, and where to respond to them in my code.

Would the pseudo code look something like this:

volatile bool countUpFlag = false;
volatile bool countDnFlag = false;

void isr () {

  if (change in encpinB) {
    countUpFlag = true;
    encoder++;
    } else {
    countDnFlag = true;
    encoder--;
  }
}

And would I write a statement in each 'button press' statement like:

  if (button1state == LOW) {
    countUpFlag = false;

....followed by the rest of the code within that section.

Edit
It's very plain that I do not know what I'm talking about - that last question makes no sense! :smiley:

Probably best to see if either flag is set. If so turn interrupts off just while you copy the flags to non volatile variables.

Then check whether each button is pressed and if so, inc or dec its count as the copied flags indicate.

wildbill:
Probably best to see if either flag is set. If so turn interrupts off just while you copy the flags to non volatile variables.

Then check whether each button is pressed and if so, inc or dec its count as the copied flags indicate.

I can't thank you enough for the time you're spending in walking me through this!

Please forgive my chronic thickness however...
...would I place an another 'if' statement in the ISR to check the flags, like this:

void isr () {

  if (digitalRead(encpinB) == LOW) {
    if(countUpFlag == false || countDnFlag == false) {
      countUpFlag = true;
      encoder++;
      } else {
      countDnFlag = true;
      encoder--;
    }
  }
}

And I presume I would need something like this within the 'button press' bit:

  if (button1state == LOW) {
    noInterrupts();
    countUpFlag = false;
    countDnFlag = false;
    count1 = encoderPos;
    interrupts();
...
...

Where 'count1' is the individual non volatile value (one of the six)

It would be a miracle if this were right!! :smiley:

Forget checking the flags in the interrupt. Just set one or the other where you currently increment or decrement the encoder count.

In your main code, if a flag is set, check your buttons to see which one needs its count adjusted.

Thanks again wildbill, I think I'm getting somewhere...

So my ISR would look like this:

void isr () {

  static unsigned long debounceLast = 0;
  unsigned long debounce = millis();

  if (debounce - debounceLast > 5) {
    if (digitalRead(encPinB) == LOW) {
      countUpFlag = true;
      encoderPos++ ;
    } else {
      countDnFlag = true;
      encoderPos-- ;
    }
    encoderPos = min(199, max(0, encoderPos));
  }
  debounceLast = debounce;
}

And then (to take my button1 as an example) in the main code would I place the flag check there instead?
Like this:

  if (button1state == LOW) {
    if (countUpFlag == true || countDnFlag == true) {
      noInterrupts();
      count1 = encoderPos;
      interrupts();

      lcd.setCursor(0, 0);
      lcd.print(">");
      lcd.setCursor(4, 0);
      lcd.print(" ");
      lcd.setCursor(8, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(4, 1);
      lcd.print(" ");
      lcd.setCursor(8, 1);
      lcd.print(" ");

      digitalWrite(button1, LOW);
      digitalWrite(button2, HIGH);
      digitalWrite(button3, HIGH);
      digitalWrite(button4, HIGH);
      digitalWrite(button5, HIGH);
      digitalWrite(button6, HIGH);

      if (!digitalRead(encSw)) {
        count1 = 0;
        lcd.setCursor(1, 0);
        lcd.print(count1);
        lcd.setCursor(1, 0);
        lcd.print("   ");
        while (!digitalRead(encSw))
          delay(10);
      }

      if (count1 != value1Last) {
        lcd.setCursor(1, 0);
        lcd.print(count1);
        lcd.setCursor(1, 0);
        lcd.print("   ");
        value1Last = count1;
      }
    }
      countUpFlag = false;
      countDnFlag = false;
  }

Am I getting close?
There might be a faint glimmer in the 'light bulb'....not sure yet!

Once again, thank you for spending time on this wildbill!

Sorry, I think that's just a reflection on the light bulb :wink:

I may be misunderstanding this, but what I think you're trying to do is adjust six things using one encoder and the button pressed tells you which one you should apply changes to.

If that's the case, what I envisage is that you give up counting encoderPos in the interrupt and just use the two flags (up & down).

When a flag is set, you look to see which button is currently pressed and then adjust it's own encoder position variable. The encoderPos variable is meaningless because you may have been moving it around all over the place for other buttons. In the example you gave, I'd expect:

  if (button1state == LOW) {
      if(countUpFlag)
        {
        count1++;
        }
      if(countDnFlag)
        {
        count1--;
        }

wildbill:
Sorry, I think that's just a reflection on the light bulb :wink:

You may be right!! :smiley:

I may be misunderstanding this, but what I think you're trying to do is adjust six things using one encoder and the button pressed tells you which one you should apply changes to.

You're not misunderstanding it, that's exactly what I would like to see happen.

If that's the case, what I envisage is that you give up counting encoderPos in the interrupt and just use the two flags (up & down).

When a flag is set, you look to see which button is currently pressed and then adjust it's own encoder position variable. The encoderPos variable is meaningless because you may have been moving it around all over the place for other buttons. In the example you gave, I'd expect:

  if (button1state == LOW) {

if(countUpFlag)
       {
       count1++;
       }
     if(countDnFlag)
       {
       count1--;
       }

I think that makes sense, but what would my ISR look like without the encoderPos counter?

Something like this perhaps:

void isr () {

  static unsigned long debounceLast = 0;
  unsigned long debounce = millis();

  if (debounce - debounceLast > 5) {
    if (digitalRead(encPinB) == LOW) {
      countUpFlag = true;
    } else {
      countDnFlag = true;
    }
  }
  debounceLast = debounce;
}

So the ISR is now there to report the flag conditions, monitor encPinB and debounce?

BTW, I have just tried my 'idea(?)', and while it seems to increment/decrement well for each button press, the value is carried over to the next button/value, so you're absolutely right, the encoderPos variable is relatively meaningless!
Just had to see for myself!! :smiley:

On a side note...does this:

if (countUpFlag)

mean the same as this:

if (countUpFlag == true)

bongobreak:
I think that makes sense, but what would my ISR look like without the encoderPos counter?

Something like this perhaps:

void isr () {

static unsigned long debounceLast = 0;
  unsigned long debounce = millis();

if (debounce - debounceLast > 5) {
    if (digitalRead(encPinB) == LOW) {
      countUpFlag = true;
    } else {
      countDnFlag = true;
    }
  }
  debounceLast = debounce;
}




So the ISR is now there to report the flag conditions, monitor encPinB and debounce?

Yes, that's it.

On a side note...does this:

if (countUpFlag)

mean the same as this:

if (countUpFlag == true)

Yes. Once you see it the simpler way, a construct like if (countUpFlag == true) is like fingernails on a blackboard.

wildbill:
...Once you see it the simpler way, a construct like if (countUpFlag == true) is like fingernails on a blackboard.

Sorry about that...it'll never happen again! :wink:

Anyway, I've had a breakthrough....the light has finally turned on!!

I don't know how to thank you enough wildbill, it works perfectly now!

I indeed removed the encoderPos counter out of the ISR, and put a separate counter in each button press section, with a flag reset immediately after it, and it works like a charm!

I didn't place an interrupt() or noInterrupt() in though - seems to work well enough without them, but if I should put them in, would they be immediately before and after the countUpFlag / countDnFlag statements?

Nevertheless, many, many thanks wildbill!!

I'll post the entire revised code in the next post, and mark this thread [SOLVED]

Have a great day wildbill, and thanks once again

(Is that enough 'thank you's'? :smiley: )