Энкодер от прерывания INT1

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Покритикуйте!
PCINT использовать нельзя, так как обрабатывает еще один энкодер, в loop тоже нельзя, в нём цикл 70 миллисекунд, использовать PCINT на других блоках тоже нельзя, при этом свободны пины INT0 и INT1

Сделал так:

/******* Простой энкодер *******/
#include <RotaryEncoder.h>
RotaryEncoder encoder(4, 5);
volatile int newPos;
unsigned long Freq = 300000;
static int pos = 0;

/*** Обработчик энкодера через ШИМ ***/
void startEncoder(){
     attachInterrupt(1, Encoder2, RISING );
     analogWrite(3,0x80); // установим на пине частоту 
           }              // 490 гц скважность 2

void Encoder2(){          // процедура вызываемая прерыванием
   encoder.tick();  
 } 

void setMyFreq(int myPos){
 Freq = Freq + ((newPos-pos)*100); 
}

void setup(){
  Serial.begin(115200);
  startEncoder();
} // setup()

void loop(){
  newPos = encoder.getPosition();
  if (pos != newPos) {
    setMyFreq(newPos);
    pos = newPos;
    Serial.println(Freq);
  } // if
} // loop ()

// The End

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Неужели всё правильно? Аж не верится...
И еще вариант: (код поправил, с учётом атомарности чтения)
 

/******* Простой энкодер *******/
#include <util/atomic.h> // для атомарности чтения данных в прерываниях
#include <RotaryEncoder.h>
RotaryEncoder encoder_0(2, 3); //Первый энкодер
RotaryEncoder encoder_1(4, 5); //Второй энкодер

volatile int newPos;
unsigned long Freq = 300000;
static int pos = 0;

/*** Обработчик энкодера через ШИМ ***
void startEncoder(){
     attachInterrupt(1, Encoder2, RISING );
     analogWrite(3,0x80); // установим на пине частоту 
           }              // 490 гц скважность 2

void Encoder2(){          // процедура вызываемая прерыванием
   encoder.tick();  
 } 
*/

void setMyFreq(int myPos){
 Freq = Freq + ((newPos-pos)*100); 
}
// Обработчики прерываний
ISR(PCINT0_vect) {
encoder_1.tick(); // just call tick() to check the state.
}
/*
ISR(PCINT1_vect) {
encoder.tick(); // just call tick() to check the state.
}*/
ISR(PCINT2_vect) {
encoder_0.tick(); // just call tick() to check the state.
}


void setup(){
  Serial.begin(115200);
  PCICR  |= (1 << PCIE0);
  PCMSK0 |= (1 << PCINT1); // Обработчик прерывания на пине 9
  analogWrite(9,0x80);     // будем шимить пин с частотой 490 герц
  
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); 
                         
  // startEncoder(); 
  // Configure interrupt for rotary encoder and enable.
  // D8 .. D13 - генерируют запрос прерывания PCINT0
  // PCICR  |= (1 << PCIE0);
  // PCMSK0 |= (1 << PCINT0) | (1 << PCINT1) | (1 << PCINT2) | (1 << PCINT3) | (1 << PCINT4) | (1 << PCINT5);

  // A0 .. A5 - генерируют запрос прерывания PCINT1
  // PCICR  |= (1 << PCIE1);
  // PCMSK1 |= (1 << PCINT8) | (1 << PCINT9) | (1 << PCINT10) | (1 << PCINT11) | (1 << PCINT12) | (1 << PCINT13);

  // D0 .. D7 - генерируют запрос прерывания PCINT2
  // PCICR |= (1 << PCIE2);
  // PCMSK2 |= (1 << PCINT16) | (1 << PCINT17) | (1 << PCINT18) | (1 << PCINT19) | (1 << PCINT20) | (1 << PCINT21) | (1 << PCINT22) | (1 << PCINT23);

  // sei(); //для этой библиотеки в примерах нет этого

} // setup()


void loop(){
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE){newPos = encoder_1.getPosition();}
  if (pos != newPos) {
    setMyFreq(newPos);
    pos = newPos;
    Serial.println(Freq);
  } // if
} // loop ()

// The End

 

Logik
Offline
Зарегистрирован: 05.08.2014

Да. Оба верно, закрывай тему ;)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Logik пишет:

Да. Оба верно, закрывай тему ;)

через три года начал что-то понимать в вашем лживом СИ )))

sadman41
Offline
Зарегистрирован: 19.10.2016

Просто Ложик уже наливки накидался, ему сейчас всё равно.

А так... оба варианта имеют потенциальный баг из-за отсутствия атомарности в операции чтения позиции.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Просто Ложик уже наливки накидался, ему сейчас всё равно.

А так... оба варианта имеют потенциальный баг из-за отсутствия атомарности в операции чтения позиции.

поясни плиз

sadman41
Offline
Зарегистрирован: 19.10.2016
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

 вызываю библиотечную функцию, в примерах автор оборачивать вызов не приводит, может сама функция внутри библиотеки обёрнута?

нет, не обёрнута и, вроде особого смысла нет
 

RotaryEncoder::getPosition() {
  return _positionExt;
} // getPosition()

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Можете за это свечку поставить - авось поможет Господь.

Какая связь между библиотечной функцией, её автором и прерыванием?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Можете за это свечку поставить - авось поможет Господь.

Какая связь между библиотечной функцией, её автором и прерыванием?

сломаться жеж она может только в этой функции, если я что-то понимаю? (строка 28 первого скетча)

sadman41
Offline
Зарегистрирован: 19.10.2016
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

это-то понятно, меня интересует другое, прерывание будет поставлено в очередь и отработано, INT0 и INT1 обязаны, а вот PCINT? Что-то об этом не нашёл

Logik
Offline
Зарегистрирован: 05.08.2014

А воще sadman41 в чем то прав, а в чем то нет. К наливке я еще только вот щас приступлю, тут он не прав. А про атомарность - смотрите  какой несчастный случай возможен. Допустим _positionExt равна 0х000000ff. Мы вызвали getPosition(), она побайтово начинает копировать данные, пусть с конца (без разницы если с начала) скопировало 0хff, и тут прерывание ввалило. И сделало +1, теперь 0х00000100. Вернувшись из прерывания продолжается копирование остальных 3-х байт и имеем 0х000001ff. Херня 8| Правда на следующем вызове getPosition() мы таки получим 0х00000100, но неприятный осадочок останется. 

sadman41
Offline
Зарегистрирован: 19.10.2016

А что, PCINT получило четвертной без права переписки?

https://microchipdeveloper.com/8avr:int

Logik
Offline
Зарегистрирован: 05.08.2014

Испугано глянул себе в либу енкодера.

	word Get(void)
	{
		volatile word t;
		cbi(PCICR, PCIE0);
		t = m_Val;
		sbi(PCICR, PCIE0);
		return t;
	};

Ниче , с наливкой покатит.

 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Logik пишет:

А воще sadman41 в чем то прав, а в чем то нет. К наливке я еще только вот щас приступлю, тут он не прав. А про атомарность - смотрите  какой несчастный случай возможен. Допустим _positionExt равна 0х000000ff. Мы вызвали getPosition(), она побайтово начинает копировать данные, пусть с конца (без разницы если с начала) скопировало 0хff, и тут прерывание ввалило. И сделало +1, теперь 0х00000100. Вернувшись из прерывания продолжается копирование остальных 3-х байт и имеем 0х000001ff. Херня 8| Правда на следующем вызове getPosition() мы таки получим 0х00000100, но неприятный осадочок останется. 

ну так про это Садман и твердил, там тип данных как раз long, был бы байт - без разницы

Logik
Offline
Зарегистрирован: 05.08.2014

ага. Но по моему Вы недооценили эту проблему. Она просто редко проявляться будет, но неприятно.  А в остальном все не плохо, насколько конечно это возможно в ноябре.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Logik пишет:

ага. Но по моему Вы недооценили эту проблему. Она просто редко проявляться будет, но неприятно.  А в остальном все не плохо, насколько конечно это возможно в ноябре.

Это я просто два разных скетча в одной железке пытаюсь подружить, по пинам чтобы не пересечься и чтобы можно было сторонний скетч генератора залить )))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

А что, PCINT получило четвертной без права переписки?

https://microchipdeveloper.com/8avr:int

там так коряво написано )))
22 вектора, значит надо минимум 3 регистра флагов, чтобы их запомнить и обработать, ...работает и ладно, стока энкодеров нет, чтобы проверить

Logik
Offline
Зарегистрирован: 05.08.2014

И там на одном векторе еще и кучка разного может быть. Я их раз  написал в либу енкодера так.

    //управляем прерываниями по изменению состояния от группы ног
#define ENCODER_INTERRUPT_ENABLE        cbi(EICRA, ISC01);sbi(EICRA, ISC00);sbi(PCICR, PCIE0);    /* разрешаем прерывания PCINT3 */  

#define ENCODER_INTERRUPT_DISABLE      cbi(PCICR, PCIE0);     // запрещаем прерывания PCINT0..7   

//разрешим прерватся прм изменении ENCODER_INPUT_PIN1
#define ENCODER_INTERRUPT_PIN1           cbi(PCMSK0, ENCODER_INPUT_PIN2);sbi(PCMSK0, ENCODER_INPUT_PIN1);

//разрешим прерватся прм изменении ENCODER_INPUT_PIN2
#define ENCODER_INTERRUPT_PIN2           cbi(PCMSK0, ENCODER_INPUT_PIN1);sbi(PCMSK0, ENCODER_INPUT_PIN2);

 

И забыл что где ))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Я не Гайвер, мне библиотеки не осилить, пользуюсь наработанным опытом )))
на этой остановился из-за её стабильности...

Считал, что объявление переменных ВОЛАТИЛЬНЫМИ

private:
  int _pin1, _pin2; // Arduino pins used for the encoder. 
  
  volatile int8_t _oldState;
  
  volatile long _position;         // Internal position (4 times _positionExt)
  volatile long _positionExt;      // External position
  volatile long _positionExtPrev;  // External position (used only for direction checking)

  unsigned long _positionExtTime;     // The time the last position change was detected.
  unsigned long _positionExtTimePrev; // The time the previous position change was detected.

заставляет компилятор их должным способом обрабатывать, иначе зачем всё это? Как в присказке получается про барышню и огурец )))
Я еще не научился как DIMAX смотреть в коде, как это выглядит, а было бы интересно...

А Дед (и Садман) был прав - нельзя верить вашему лживому Си

// ATOMIC_BLOCK(ATOMIC_RESTORESTATE){newPos = encoder_1.getPosition();}


516:	f8 94       	cli
 518:	40 91 1d 01 	lds	r20, 0x011D
 51c:	50 91 1e 01 	lds	r21, 0x011E
 520:	60 91 1f 01 	lds	r22, 0x011F
 524:	70 91 20 01 	lds	r23, 0x0120
 528:	40 93 10 01 	sts	0x0110, r20
 52c:	50 93 11 01 	sts	0x0111, r21
 530:	60 93 12 01 	sts	0x0112, r22
 534:	70 93 13 01 	sts	0x0113, r23
 538:	8f bf       	out	0x3f, r24	; 63
 53a:	00 00       	nop
 53c:	00 00       	nop
 53e:	00 00       	nop
 
//  newPos = encoder_1.getPosition();
 
  512:	d0 e0       	ldi	r29, 0x00	; 0
 514:	80 91 1d 01 	lds	r24, 0x011D
 518:	90 91 1e 01 	lds	r25, 0x011E
 51c:	a0 91 1f 01 	lds	r26, 0x011F
 520:	b0 91 20 01 	lds	r27, 0x0120
 524:	80 93 10 01 	sts	0x0110, r24
 528:	90 93 11 01 	sts	0x0111, r25
 52c:	a0 93 12 01 	sts	0x0112, r26
 530:	b0 93 13 01 	sts	0x0113, r27
 534:	00 00       	nop
 536:	00 00       	nop
 538:	00 00       	nop

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ua6em пишет:

А Дед (и Садман) был прав - нельзя верить вашему лживому Си

Никада такого не говорил, Си - честен и чист, как слеза ребёнка, особенно у Онкеля.  Лжив, как Госдеп, тока С++. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em пишет:

А Дед (и Садман) был прав - нельзя верить вашему лживому Си

Никада такого не говорил, Си - честен и чист, как слеза ребёнка, особенно у Онкеля.  Лжив, как Госдеп, тока С++. 

так тама вроде С++ и есть!?

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

Какое  совпадение... :)

третий день с энкодером развлекаюсь.

Вижу тут люди знающие собрались, позвольте вопрос от начинающего ?

Какую библиотеку лучше использовать для работы с энкодером с использованием прерывания INT0/1 ?

(цель - управление кухонным радиоприемником-термометром-часами-МП3-плейером на 328 атмеге, предпочтение - компактность кода - а то хотелок много, как видите)

Попал в затруднительную ситуацию - для решения которой своих знаний/опыта - явно мало:

GyverEncoder.h  в процессе разбухания кода - перестал работать после подключения библиотеки для дисплея Нокия5110 - LCD5110_Basic.h

вместо четкого  - тик влево, тик вправо пока с Serial работал - стал гнать все время вправо...

Да как такое вообще то возможно ? :(

 

 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Oleg Smirnoff пишет:

Какое  совпадение... :)

третий день с энкодером развлекаюсь.

Вижу тут люди знающие собрались, позвольте вопрос от начинающего ?

Какую библиотеку лучше использовать для работы с энкодером с использованием прерывания INT0/1 ?

(цель - управление кухонным радиоприемником-термометром-часами-МП3-плейером на 328 атмеге, предпочтение - компактность кода - а то хотелок много, как видите)

Попал в затруднительную ситуацию - для решения которой своих знаний/опыта - явно мало:

GyverEncoder.h  в процессе разбухания кода - перестал работать после подключения библиотеки для дисплея Нокия5110 - LCD5110_Basic.h

вместо четкого  - тик влево, тик вправо пока с Serial работал - стал гнать все время вправо...

Да как такое вообще то возможно ? :(

я Гайверовскую только глянул, увидел, что он там нагородил (Человек гора) побежал дальше, возьмите попробуйте сделать как у меня на INT1, если он свободен, а лучше схему, что по пинам свободно, к каким пинам сейчас прикручен энкодер?

alkotester1
Offline
Зарегистрирован: 24.11.2019

Oleg Smirnoff пишет:

GyverEncoder.h  в процессе разбухания кода - перестал работать после подключения библиотеки для дисплея Нокия5110 - LCD5110_Basic.h

вместо четкого  - тик влево, тик вправо пока с Serial работал - стал гнать все время вправо...

Да как такое вообще то возможно ? :(

Задайте этот вопрос здесь адептам Гайвера

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

ua6em, у меня проект в стадии когда все что угодно можно прикручивать куда угодно. :) Макет.

Энкодер на 2,3 посажен,(именно с расчетом на INT0 INT1, кнопка на 4 - канонически можно сказать... Пока прерывания больше никому не нужны.

Попробую как у вас , особенно если подскажете есть ли описание библиотеки енкодера - которой вы пользуетесь.

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

alkotester1 , Да вы что ?   :)

Я случайно влез в секту ? :)

За ссылку спасибо.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Oleg Smirnoff пишет:

ua6em, у меня проект в стадии когда все что угодно можно прикручивать куда угодно. :) Макет.

Энкодер на 2,3 посажен,(именно с расчетом на INT0 INT1, кнопка на 4 - канонически можно сказать... Пока прерывания больше никому не нужны.

Попробую как у вас , особенно если подскажете есть ли описание библиотеки енкодера - которой вы пользуетесь.

это стандартная библиотека, доступна через менеджер библиотек называется RotareEncoder by Matthias Hertel v1.3 там есть пример, если PCINT на этом блоке не используются, то проще через них, INT1 я использовал неоднозначно жеж )))

Могу помочь с кодом, там пару десятков строк

/******* Простой энкодер *******/
#include <util/atomic.h> // для атомарности чтения данных в прерываниях
#include <RotaryEncoder.h>
RotaryEncoder encoder(2, 3); //Пины энкодера

volatile long newPos; // Переменная для данных энкодера

ISR(PCINT2_vect) {
encoder.tick(); // На каждый щелчок энкодера запускается эта процедура
}
void setup() {
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); // Настройка прерывания

}

void loop() {
  // Так читать данные с энкодера
 ATOMIC_BLOCK(ATOMIC_RESTORESTATE){newPos = encoder.getPosition();}
}

 

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

ua6em пишет:

это стандартная библиотека, доступна через менеджер библиотек называется RotareEncoder by Matthias Hertel v1.3 там есть пример, если PCINT на этом блоке не используются, то проще через них, INT1 я использовал неоднозначно жеж )))

Могу помочь с кодом, там пару десятков строк

/******* Простой энкодер *******/
#include <util/atomic.h> // для атомарности чтения данных в прерываниях
#include <RotaryEncoder.h>
RotaryEncoder encoder(2, 3); //Пины энкодера

volatile long newPos; // Переменная для данных энкодера

ISR(PCINT2_vect) {
encoder.tick(); // На каждый щелчок энкодера запускается эта процедура
}
void setup() {
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); // Настройка прерывания

}

void loop() {
  // Так читать данные с энкодера
 ATOMIC_BLOCK(ATOMIC_RESTORESTATE){newPos = encoder.getPosition();}
}

 

 

Премного благодарен, и хоть "атомарность" для меня пока слова непонятные, в общем и целом ясно  :) - прям сейчас попробую ваш блок  вставить в свой скетч.

Кстати вопрос - а в этой библиотеке с подавлением дребезга контактов энкодера  все нормально ? или аппаратно давить ?  А то есть неприятный опыт...

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Oleg Smirnoff, вариант 100% не имеющий проблем с дребезгом

http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder?page=5#comment-449417

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Цитата:

Кстати вопрос - а в этой библиотеке с подавлением дребезга контактов энкодера  все нормально ? или аппаратно давить ?  А то есть неприятный опыт...

не надо ничего там аппаратно давить, если энкодер глючит, автор библиотеки советует его просто выкинуть )))

кручу два дня, полёт нормальный пропусков не было, энкодер нонаме, да в библиотеке пины подтягиваются к +5V так что замыкать надо на землю общий контакт

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

Oleg Smirnoff, вариант 100% не имеющий проблем с дребезгом

http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder?page=5#comment-449417

и библиотека не нужна )))

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

ua6em,  ой спасибо !!!

Щелкает тики гладенько, и памяти много не заедает !!

73!   ex UK4PNZ/UA4-094-301

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Oleg Smirnoff пишет:

ua6em,  ой спасибо !!!

Щелкает тики гладенько, и памяти много не заедает !!

73!   ex UK4PNZ/UA4-094-301

подключи сериал, выведи данные с энкодера в порт монитора и посмотри, я так библиотеки подбирал, на этой остановился, так как пропусков и перескакиваний не было

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

dimax пишет:

Oleg Smirnoff, вариант 100% не имеющий проблем с дребезгом

http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder?page=5#comment-449417

 

quote=dimax]

//Энкодер на пинах А0, А1. Используется внутренняя подтяжка.

[/quote]

dimax, благодарю, я обязательно попробую и без библиотеки - особенно если память это сэкономит.

ВОт только я читал что у ардуины на 328-м - прерывания возможны только на D2 и D3....

Видимо заблуждался ? :)

 

Oleg Smirnoff
Offline
Зарегистрирован: 06.01.2018

ua6em пишет:

Oleg Smirnoff пишет:

ua6em,  ой спасибо !!!

Щелкает тики гладенько, и памяти много не заедает !!

73!   ex UK4PNZ/UA4-094-301

подключи сериал, выведи данные с энкодера в порт монитора и посмотри, я так библиотеки подбирал, на этой остановился, так как пропусков и перескакиваний не было

 

Уже... :)

Все четко... :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Oleg Smirnoff пишет:

ua6em пишет:

Oleg Smirnoff пишет:

ua6em,  ой спасибо !!!

Щелкает тики гладенько, и памяти много не заедает !!

73!   ex UK4PNZ/UA4-094-301

подключи сериал, выведи данные с энкодера в порт монитора и посмотри, я так библиотеки подбирал, на этой остановился, так как пропусков и перескакиваний не было

 

Уже... :)

Все четко... :)

то аппаратные, с высоким приоритетом, они для другого могут пригодиться...
В этом варианте даже Садман41 не придерётся, не к чему, вдобавок смотрел ассемблерный код, всё чётко )))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Oleg Smirnoff пишет:

ВОт только я читал что у ардуины на 328-м - прерывания возможны только на D2 и D3....

Видимо заблуждался ? :)

Под прерываниями часто имеют ввиду индивидуальные. Их в меге 328 действительно всего 2. А групповые есть на каждом пине, и они образуют 3 группы. Есть ещё прерывание компаратора, которое тоже  полнофункциональное:) 

Logik
Offline
Зарегистрирован: 05.08.2014

Да. Прерывания есть на всех пинах.Я энкодер на порт B вешаю по прерываниям, все жужу.

dimax, тот код что ссылку выше дали далеко не лучший. Радует что мысль о ненужности конденсаторов принята. Следующая мысль - дребезг вызывает очень большое количество не нужных прерываний. По хорошему надо бы запрещать иногда некоторые, когда они не требуются в алгоритме.

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Чё это не придерусь... Могу, если надо.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:
Чё это не придерусь... Могу, если надо.

ты можешь ))) А вообще нет пределу совершенства и лучшее враг хорошего

sadman41
Offline
Зарегистрирован: 19.10.2016

ua6em пишет:

Могу помочь с кодом, там пару десятков строк

/******* Простой энкодер *******/
#include <util/atomic.h> // для атомарности чтения данных в прерываниях
#include <RotaryEncoder.h>
RotaryEncoder encoder(2, 3); //Пины энкодера

volatile long newPos; // Переменная для данных энкодера

ISR(PCINT2_vect) {
encoder.tick(); // На каждый щелчок энкодера запускается эта процедура
}
void setup() {
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); // Настройка прерывания

}

void loop() {
  // Так читать данные с энкодера
 ATOMIC_BLOCK(ATOMIC_RESTORESTATE){newPos = encoder.getPosition();}
}

Если надо докопатся, то извольте:

1) volatile long newPos - volatile тут уже не требуется, если newPos не будет использоваться в других необычных местах типа обработчика прерывания;
2) библиотеку энкодера я не потрошил, но если она, в принципе, не требует двух пинов с прерываниями, то занимать два external interrupt pin под один энкодер несколько бессмысленно.