Go Down

Topic: attachInterrupt on Pin 21 & 20 won't work? (Arduino Mega 2560 R3) (Read 18341 times) previous topic - next topic



I've been cracking my brains over this the last few days.
For a project for my study I have to develop a model gantry crane which will use 3 rotary encoders.
This shouldn't be a problem since the Arduino Mega 2560 has 6 external interrupt pins (2, 3, 18, 19, 20, 21).
But now comes the problem, I can make pin 2 (INT4), pin 3 (INT5), pin 18 (INT3) & pin 19 (INT2) to work, but whatever I try, I cant seem to get the pins 21 & 20 (INT1 & INT0) to work.

First I thought that the pin mapping was off, but I later found out that the attachInterrupt function uses a switch statement which creates all the confusion.

I've been browsing on the web for hours now and every example that I could find was talking about other boards than the Mega 2560 or were talking about the switch-cases 0  & 1 of the attachInterrupt function (which are perfectly working for me, I have problems with cases 2 & 3).

My guesses are that I have to disable or enable something to be able to use pins 20 & 21 as external interrups, but I can't seem to make that happen.

My code:
- the functions that are executed on the interrupts are 3 of the same
- I use binary to save the last state of the encoder decide which way the encoder is rotating

Code: [Select]
main tab:

int encoder_x_pin_a = 2;
int encoder_x_pin_b = 3;
int encoder_y_pin_a = 21;
int encoder_y_pin_b = 20;
int encoder_z_pin_a = 19;
int encoder_z_pin_b = 18;

volatile int encoder_x_encoded_laatste = 0;
volatile int encoder_y_encoded_laatste = 0;
volatile int encoder_z_encoded_laatste = 0;

volatile long encoder_x_waarde = 0;
volatile long encoder_y_waarde = 0;
volatile long encoder_z_waarde = 0;

void setup()
  pinMode(encoder_x_pin_a, INPUT);
  pinMode(encoder_x_pin_b, INPUT);
  pinMode(encoder_y_pin_a, INPUT);
  pinMode(encoder_y_pin_b, INPUT);
  pinMode(encoder_z_pin_a, INPUT);
  pinMode(encoder_z_pin_b, INPUT);
  Serial.begin (9600);
  attachInterrupt(0, encoder_x, CHANGE);        //  INT4 --> Pin 2
  attachInterrupt(1, encoder_x, CHANGE);        //  INT5 --> Pin 3
  attachInterrupt(2, encoder_y, CHANGE);        //  INT0 --> Pin 21
  attachInterrupt(3, encoder_y, CHANGE);        //  INT1 --> Pin 20
  attachInterrupt(4, encoder_z, CHANGE);        //  INT2 --> Pin 19
  attachInterrupt(5, encoder_z, CHANGE);        //  INT3 --> Pin 18

void loop()
  Serial.print("Value X | Y | Z  -  ");
  Serial.print(" | ");
  Serial.print(" | ");

Code: [Select]
encoder_x tab:
void encoder_x(void)

  int encoder_x_msb = digitalRead(encoder_x_pin_a); //MSB = most significant bit
  int encoder_x_lsb = digitalRead(encoder_x_pin_b); //LSB = least significant bit
  int encoder_x_encoded = (encoder_x_msb << 1) | encoder_x_lsb; //converting the 2 pin value to single number
  int encoder_x_som = (encoder_x_encoded_laatste << 2) | encoder_x_encoded; //adding it to the previous encoded value

  if(encoder_x_som == 0b1101 || encoder_x_som == 0b0100 || encoder_x_som == 0b0010 || encoder_x_som == 0b1011)
  if(encoder_x_som == 0b1110 || encoder_x_som == 0b0111 ||encoder_x_som == 0b0001 || encoder_x_som == 0b1000)
  encoder_x_encoded_laatste = encoder_x_encoded; //store this value for next time 

Code: [Select]
encoder_y tab:
void encoder_y(void)

  int encoder_y_msb = digitalRead(encoder_y_pin_a); //MSB = most significant bit
  int encoder_y_lsb = digitalRead(encoder_y_pin_b); //LSB = least significant bit
  int encoder_y_encoded = (encoder_y_msb << 1) | encoder_y_lsb; //converting the 2 pin value to single number
  int encoder_y_som = (encoder_y_encoded_laatste << 2) | encoder_y_encoded; //adding it to the previous encoded value

  if(encoder_y_som == 0b1101 || encoder_y_som == 0b0100 || encoder_y_som == 0b0010 || encoder_y_som == 0b1011)
  if(encoder_y_som == 0b1110 || encoder_y_som == 0b0111 ||encoder_y_som == 0b0001 || encoder_y_som == 0b1000)
  encoder_y_encoded_laatste = encoder_y_encoded; //store this value for next time 

Code: [Select]
encoder_y tab:
void encoder_z(void)

  int encoder_z_msb = digitalRead(encoder_z_pin_a); //MSB = most significant bit
  int encoder_z_lsb = digitalRead(encoder_z_pin_b); //LSB = least significant bit
  int encoder_z_encoded = (encoder_z_msb << 1) | encoder_z_lsb; //converting the 2 pin value to single number
  int encoder_z_som = (encoder_z_encoded_laatste << 2) | encoder_z_encoded; //adding it to the previous encoded value

  if(encoder_z_som == 0b1101 || encoder_z_som == 0b0100 || encoder_z_som == 0b0010 || encoder_z_som == 0b1011)
  if(encoder_z_som == 0b1110 || encoder_z_som == 0b0111 ||encoder_z_som == 0b0001 || encoder_z_som == 0b1000)
  encoder_z_encoded_laatste = encoder_z_encoded; //store this value for next time 

I've used the Arduino IDE 1.03, 1,04 & 1.52 (BETA) and all of them failed. I even tried an libary (which worked fine for pins2,3,18 & 19, but wouldn't work for pins 20 & 21).
I'd really appreciate some directions where to search, I've asked several other students (some of them are creating robots and programming all the time and even they couldn't help me).



I know this reply is a little late,

I had the same problem: interrupts on pin 2, 3, 18 and 19 are no problem, but interrupts on pin 20 (SDA) and 21 (SCL) won't work.

In my case I found the solution in the hardware,

Pin 20 (SDA) and pin 21 (SLC) is standard connected (on the Arduino board) with a pull up resistor (10k) to +5V. (Result in a constant logic high signal, when noting is connected to ground) See also schematic:http://arduino.cc/en/uploads/Main/arduino-mega2560_R3-sch.pdf

The problem was solved when placing the encoder between pin 20/21 and ground (instead of between pin 20/21 and +5V) (inverting the signal with a transistor is also an option)

Hope this helps


Thanks for the reply anyway!

I've already managed to solve this by only using one Interrupt Port for each rotary encoder, thus only using pin 2, 3 & 18.
This gave me the result I needed, but I'll keep your solution in mind for future (possible) problems!


I would like to make closed loop stepper code for x,y,z router
i saw your codes for rotary encoder x,y,z that look perfect, may use this code for my stepper motors
or if you can send me stepper codes related to your encoder code files.

With best regards,


External Interrupts: 2 (interrupt 0),
3 (interrupt 1),
18 (interrupt 5),
19 (interrupt 4),
20 (interrupt 3),
21 (interrupt 2).
These pins can be configured to trigger an interrupt on a low level, a rising or falling edge, or a change in level. 
for using interrupt 20 use the following syntax:
attachInterrupt(3, toggle, LOW);

hope this is helpful.


Thanks for the reply anyway!

I've already managed to solve this by only using one Interrupt Port for each rotary encoder, thus only using pin 2, 3 & 18.
This gave me the result I needed, but I'll keep your solution in mind for future (possible) problems!
Where did you connect the encoders' b pins?


I was having the same problem trying to do about the same thing, What I found is Pin 20 and 21 are also wired to the top 2 pins (label SCL & SDA) next to GND and AREF and pin 13.   Pins 20,21 are interrupt but the are also used for I2C.(In my case a I2C LCD) So it is easy to plug I2C in at the top and try to use Pins 20 and 21 as interrupts not realizing they are already being used. Hope this save someone a lot of time.

Go Up