I use a Bourns PEC12R rotary encoder in one of my designs, with this datasheet suggested filter. It is used to indicate the file number on an SD card to be accessed, which have a limit of 0 to 99, or 0 to FF, the range is selectable with the HEX_FILE_NAMES switch (limited by a 2 character display).
You could do similar, with the rotary encoder pulses being interpreted in the Interrupt Service Routine to count stuff up and down, where loop() then does something with the data.
Nack Gammon wrote this PCINT code to read the rotary encoder turns with the 328P processor.
volatile boolean fired = false;
const byte Encoder_A_Pin = 8; // PB0, pin 12 (TQFP) on board
const byte Encoder_B_Pin = 9; // PB1, pin 13 (TQFP) on board
const unsigned long ROTARY_DEBOUNCE_TIME = 100; // milliseconds
volatile int fileNumber = 0;
#if HEX_FILE_NAMES
const int MAX_FILE_NUMBER = 0xFF;
#else
const int MAX_FILE_NUMBER = 99;
#endif // HEX_FILE_NAMES
In setup:
// pin change interrupt (example for D9)
PCMSK0 = bit (PCINT0) | bit (PCINT1); // want pin 8 and 9
PCIFR = bit (PCIF0); // clear any outstanding interrupts
PCICR = bit (PCIE0); // enable pin change interrupts for D0 to D7
In loop:
if (fired)
{
// debugging display perhaps?
fired = false;
Serial.println ("tick"); // used to tell if the rotary encoder was clicked or not.
} // end if fired
Interrupt Service Routine to handle the PCINTs from the encoder turning:
// handle pin change interrupt for D8 to D13 here
ISR (PCINT0_vect)
{
static byte pinA, pinB;
static boolean ready;
static unsigned long lastFiredTime;
byte newPinA = digitalRead (Encoder_A_Pin);
byte newPinB = digitalRead (Encoder_B_Pin);
if (pinA == newPinA &&
pinB == newPinB)
return; // spurious interrupt
// so we only record a turn on both the same (HH or LL)
// Forward is: LH/HH or HL/LL
// Reverse is: HL/HH or LH/LL
if (newPinA == newPinB)
{
if (ready)
{
if (millis () - lastFiredTime >= ROTARY_DEBOUNCE_TIME)
{
if (newPinA == HIGH) // must be HH now
{
if (pinA == LOW)
fileNumber ++;
else
fileNumber --;
}
else
{ // must be LL now
if (pinA == LOW)
fileNumber --;
else
fileNumber ++;
}
if (fileNumber > MAX_FILE_NUMBER)
fileNumber = 0;
else if (fileNumber < 0)
fileNumber = MAX_FILE_NUMBER;
lastFiredTime = millis ();
fired = true;
}
ready = false;
} // end of being ready
} // end of completed click
else
ready = true;
pinA = newPinA;
pinB = newPinB;
} // end of PCINT2_vect
This demo is a little dark, it shows the filenumber count wrapping around 0 (0 back to FF and down, then back to 0 and up). Note the use of 'volatile' for variables that are used in the ISR.
https://www.youtube.com/watch?v=f51eSlcZt-g


