Rotary encoder + interrupt on MEGA 2560 not responsive

I everybody
I have used interrupts with arduino mini and nano on small projects where I have modified some old soldering stations. I put a rotary encoder and OLED or LED display as appropriate. I must say that the result was excellent. I am very satisfied. I specify that I used a Matthias Hertel library, RoraryEncoder.h

Now I want to change an old code for a submersible pump control unit. It uses MEGA2560 Display st7735 and three buttons as data entry (without interrupts). I would like to replace the buttons with a rotary encoder (with interrupt).

First of all I tried with the above library. Which, however, was preset. With the MEGA you have to change the interrupt parameters. I took the MEGA manual and tried unsuccessfully to rewrite these commands (in stars)

// ROTARY ENCODER
#include <RotaryEncoder.h>
RotaryEncoder encoder(A10, A12);
ISR(**PCINT2_vect**) {
  encoder.tick(); // just call tick() to check the state.
}

#define MIN 1
#define MAX 254

// ASSIGN DIGITAL PIN
byte pin_mode    =  A8;    // int5 Rotary encoder MODE

void setup() {

  pinMode (pin_mode, INPUT_PULLUP);

 ....

  // ROTARY - modify the next 2 lines if using other pins than A2 and A3
  PCICR |= (1 << **PCIE2**);    // This enables Pin Change Interrupt 0 will trigger
                                              //if any enabled PCINT25:16 pin toggles.
  PCMSK2 |= (1 << **PCINT18**) | (1 << **PCINT20**);  // This enables the interrupt for pin A10, A12.

  encoder.setPosition(Tset); // starts with value.

It does’t work. This could be a first question: where am I failing?


Then I tried the classic “attachInterrupt” method

I got as the simplest code as possible, and it works. At least it increments and decrements a simple variable, but the encoder is anything but responsive, as it is in the other projects with the Hertel library, where the response to rotation is immediate and quite precise.

I can’t explain it to myself: when I turn the encoder, it does nothing for several clicks, then suddenly it starts to work, then it locks again, if I turn slightly faster it seems to go better, but often for half a turn it does nothing, as if it were not reading .

I thought it was the 1.8 "ST7735 TFT slowing down, so I tried the Serial.print, but it doesn’t change anything. It’s not the display.

the code is this, trivial

const int PinA = 21;  //Rot.Enc A
const int PinB = 19;  // Rot. Enc B
const int PinSW = 3; // button

// Keep track of last rotary value
int preX = 25;

// Updated by the ISR (Interrupt Service Routine)
volatile int X = 60;

void setup() {

  Serial.begin(9600);

  // Rotary pulses are INPUTs
  pinMode(PinA, INPUT_PULLUP);
  pinMode(PinB, INPUT_PULLUP);
  pinMode(PinSW, INPUT_PULLUP);

    // Attach the routine to service the interrupts
  attachInterrupt(digitalPinToInterrupt(PinA), isrUP, FALLING);
  attachInterrupt(digitalPinToInterrupt(PinB), isrDN, FALLING);
  attachInterrupt(digitalPinToInterrupt(PinSW), isrSW, LOW);

}

void loop() {

  // If the current rotary switch position has changed then update everything
  if (X != preX) {
    Serial.println(X);
    // Keep track of this new value
    preX =  X;
  }

}

// ------------------------------------------------------------------
// INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT
// ------------------------------------------------------------------
void isrUP()  {
  X++;
  X = min(100, max(0, X));
}

void isrDN()  {
   X-- ;
  X = min(100, max(0, X));
}

void isrSW()  {
  X = 50 ;

}

How is it possible that with the NANO and the MINI the encoder works without problems, while with the Mega I can’t get decent operation?

Just some ideas:

  1. non Atomic operation. X is a 2 byte int. If you use it in the loop(), you should make a copy of it when interrupts are suspended, and use that copy instead.

  2. min() and max() are macro expansions and can have weird side effects on nesting.

  3. An external interrupt on LOW flank continuously triggers on a LOW level.

  4. The external interrupt numbering system differs between the Arduino abstraction layer and the Mega data sheet numbering system which can cause confusion.

Edit
Your second code does not look like a classic encoder handler where, on detecting a change of state on one pin, the state of the other pin is immediately checked to determine the direction of rotation. However, it should behave consistently.

1 Like

many thanks. Solved.

you were damned right, i adopted this sketch (a classical one)
sketch

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