There is a relatively simple way for you to add two more encoders with two pin change interrupts. You can leave the existing external interrupts (pin2, pin 3) for two encoders.
You have not posted any interrupt code, but with your two existing external interrupts you want to have them configured for CHANGE, so they will be the same as the new ones you add. You may have already done that, but your initial code was based on RISING. You will get twice the number of counts per rotation as before, and you want to be sure that you are reliably reading them with your setup. If you actually need the full encoder resolution and interrupts on both pins of each encoder, the code will get much more complex, but given your gear ratio and speeds, I believe you will be OK with the half resolution.
A good ISR to use with these interrupts is
if (digitalRead(encoderPinA) == digitalRead(encoderPinB)) {
encoderValue++;
} else {
encoderValue--;
}
You say that you are using digitalReadFast, but if you don't want to use that library, its very simple to change from digitalRead to use bitRead(PINX , number) which is a fast direct reading of the Port without using bitshifts and masks. I'll use that form in my post, but you can always use the digitalReadFast if you prefer.
One of the things which will simplify the pin change interrupts, is that we will add them to pins on different Ports, so you will not have to figure out what pin changed. You should familiarize yourself with the architecture of the AT 328 so you understand about pins, ports and registers. The ATmega328P data sheet is good to have at hand, and a good review can be found at RCArduino: RC Arduino Traction Control - The Traction Alarm - Draft
Two choices for your added interrupts are digital pin8 (PORTB, 0) and analog pin A0 (PORTC, 0). You will declare the pins as input or input pullup as standard. It's easier to keep things straight if you put the non interrupt pin of the encoder on an adjacent pin, e.g. Pin 9 and Pin A1.
The process to add the interrupts is simple. You enable the interrupts on a Port with the Pin Change Interrupt Control Register (PCICR) by setting the correct PCIE (pin change interrupt enable) bit in the register. Then you enable each pin you want on the port with the Pin Change Mask Resister(PCMSK). You do this in setup.
Here's the syntax
//Enable Pin Change Interrupt on Pin 8
PCICR |= (1<<PCIE0); //enable group interrupts on PORTB PCINT[7:0]
PCMSK0 |= (1<<PCINT0); //enable interrupt pin 8
//Enable Pin Change Interrupt Pin A0
PCICR |= (1<<PCIE1); //enable group interrupts on PORTC PCINT[13:8]
PCMSK1 |= (1<<PCINT8); //enable interrupt pin A0
There are now two ISR's to define for what happens when these interrupts occur. ISR's are called PCINT#_vect
//ISR for Pin 8
ISR (PCINT0_vect) // handle pin change interrupt for D8-D13; triggered by 8
{
if(bitRead(PINB,0)== bitRead(PINB,1)) {//(PINB, x) is the syntax to read the input state from PORTB, bit x
encoderValue++;
} else {
encoderValue--;
}
}
//ISR for Pin A0
ISR (PCINT1_vect) // handle pin change interrupt for A0-A5; triggered by A0
{
if(bitRead(PINC, 0)== bitRead(PINC, 1)) {
encoderValue++;
} else {
encoderValue--;
}
}
Here is a sketch which uses Pin Change Interrupts. I am using only one encoder for testing.
//Pin change interrupts on one pin of encoder pins A and B
//reads only half of quadrature states available
//for multiple encoders define encoder0PinA, encoder0Value, etc.
//PORTB pins;
#define encoderPinA 8 //PB0
#define encoderPinB 9 //PB1
//PORTC pins;
//#define encoderPinA A0 //PC0
//#define encoderPinB A1 //PC1
#define buttonPin 5 //reset button for encoder counts
//variables changed within interrupt make volatile
volatile long encoderValue;
long lastEncoderValue = 0;
void setup() {
Serial.begin (115200);
Serial.println("Half of Quadrature Counts");
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(buttonPin, INPUT_PULLUP);
//enable pin change interrupts and set pin masks;
//interrupt pin selection or wires from encoder can be switched for correct cw/ccw
PCICR |= (1<<PCIE0);//enable group interrupts on PORTB PCINT[7:0]
PCMSK0 |= (1<<PCINT0);//enable interrupt pin 8
//PCMSK0 |= (1<<PCINT1);//enable interrupt pin 9
//PCICR |= (1 << PCIE1);//enable group interrupts on PORTC PCINT[8-13]
//PCMSK1 |= (1<<PCINT8);//enable interrupt pin A0
//PCMSK1 |= (1<<PCINT9);//enable interrupt pin A1
}
void loop() {
//With fast counts, you may want to change this routine to only print increments of n counts, or counts per second, etc
if(encoderValue != lastEncoderValue){
Serial.print("Count: ");
Serial.print(encoderValue);
Serial.println();
lastEncoderValue=encoderValue;
}
//reset index
if(digitalRead(buttonPin)==LOW){
encoderValue=0;
}
}
ISR (PCINT0_vect)//handle pin change interrupt for d8 to D13, triggered by 8
{
if( bitRead(PINB,0)== bitRead(PINB,1)) //compare Pin 8 and 9
{
encoderValue++;
}
else
{
encoderValue--;
}
}
/*
ISR (PCINT1_vect)// handles interrupts A0 to A5, triggered by A0
{
if( bitRead(PINC,0)== bitRead(PINC,1)) //compare Pin A0 and A1
{
encoderValue++;
}
else
{
encoderValue--;
}
}
/*
/*
ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7
{ // handle pin change interrupt for D0 to D7
if( bitRead(PIND,#)== bitRead(PIND,#)) //compare Pins
encoderValue++;
} else {
encoderValue--;
}
}
*/