I like the idea of an i/o expander and think it’s the best option. I have problems with the PCINT option in that my software works best with the RISING option. CHANGE can be tricky to code depending on how the sensor is working and the idea of having to read in the state of the pins after the interrupt has inherent problems. What happens if the state of the pin changes between the interrupt happening and the READ?
However, for a bunch of reasons, I’m using the external interrupts and I can see that it is a useful thing to know how to do. So here is a quick example of what I am doing. I have a DC motor that’s moving between two sensors - one on the left and one on the right. I want the motor to switch direction whenever it hits a sensor. The sensors are on Analog pins 5 and 6 of the arduino:
#include <avr/interrupt.h>
#include <avr/io.h>
#define LEFT false
#define RIGHT true
int mPin1 = 5; // H-bridge leg 1
int mPin2 = 6; // H-bridge leg 2
int mEnable = 7;
boolean volatile mDirection = RIGHT;
int volatile mSpeed = 200;
ISR( PCINT1_vect )
{
if( ( ( PINC & _BV( PC4 ) ) && mDirection == LEFT ) ||
( ( PINC & _BV( PC5 ) ) && mDirection == RIGHT ) )
switch_direction();
}
void setup() {
pinMode( mPin1, OUTPUT );
pinMode( mPin2, OUTPUT );
pinMode( mEnable, OUTPUT );
//make analog pins 5 and 6 into pin change interrupts
PCICR |= (1 << PCIE1);
PCMSK1 |= (1 << PCINT12);
PCMSK1 |= (1 << PCINT13);
digitalWrite( mEnable, HIGH );
set_motor();
}
void loop() {
}
void set_motor()
{
boolean speedPin = ( mDirection ) ? mPin1 : mPin2;
boolean unusedPin = ( mDirection ) ? mPin2 : mPin1;
analogWrite( unusedPin, 0 );
analogWrite( speedPin, mSpeed );
}
void switch_direction()
{
mDirection = !mDirection;
set_motor();
}
Hope it helps, and good luck!