same code working for arduino uno but not for arduino mega 2560

Hi,i have rfid reader with wiegand out it is working good when i upload following code with arduino uno...but when i upload it using arduino mega2560 its not working...i found that different pin mapping and port registers for uno and mega2560...how can i convert this to the mega compatible code?

This is my code:

/* Crazy People
   By Mike Cook April 2009
   Three RFID readers outputing 26 bit Wiegand code to pins:-
   Reader A (Head) Pins 4 & 5
   Reader B (Body) Pins 6 & 7
   Reader C (Legs) Pins 8 & 9
   Interrupt service routine gathers Wiegand pulses (zero or one) until 26 have been recieved
   Then a sting is sent to processing
*/
#include "pins_arduino.h"
/*
   an extension to the interrupt support for arduino.
   add pin change interrupts to the external interrupts, giving a way
   for users to have interrupts drive off of any pin.
   Refer to avr-gcc header files, arduino source and atmega datasheet.
*/

/*
   Theory: all IO pins on Atmega168 are covered by Pin Change Interrupts.
   The PCINT corresponding to the pin must be enabled and masked, and
   an ISR routine provided.  Since PCINTs are per port, not per pin, the ISR
   must use some logic to actually implement a per-pin interrupt service.
*/

/* Pin to interrupt map:
   D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
   D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
   A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
*/

volatile uint8_t *port_to_pcmask[] = {
  &PCMSK0,
  &PCMSK1,
  &PCMSK2
};

typedef void (*voidFuncPtr)(void);

volatile static voidFuncPtr PCintFunc[24] = {
  NULL
};

volatile static uint8_t PCintLast[3];

/*
   attach an interrupt to a specific pin using pin change interrupts.
   First version only supports CHANGE mode.
*/
void PCattachInterrupt(uint8_t pin, void (*userFunc)(void), int mode) {
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  uint8_t slot;
  volatile uint8_t *pcmask;

  if (mode != CHANGE) {
    return;
  }
  // map pin to PCIR register
  if (port == NOT_A_PORT) {
    return;
  }
  else {
    port -= 2;
    pcmask = port_to_pcmask[port];
  }
  slot = port * 8 + (pin % 8);
  PCintFunc[slot] = userFunc;
  // set the mask
  *pcmask |= bit;
  // enable the interrupt
  PCICR |= 0x01 << port;
}

void PCdetachInterrupt(uint8_t pin) {
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *pcmask;

  // map pin to PCIR register
  if (port == NOT_A_PORT) {
    return;
  }
  else {
    port -= 2;
    pcmask = port_to_pcmask[port];
  }

  // disable the mask.
  *pcmask &= ~bit;
  // if that's the last one, disable the interrupt.
  if (*pcmask == 0) {
    PCICR &= ~(0x01 << port);
  }
}

// common code for isr handler. "port" is the PCINT number.
// there isn't really a good way to back-map ports and masks to pins.
static void PCint(uint8_t port) {
  uint8_t bit;
  uint8_t curr;
  uint8_t mask;
  uint8_t pin;

  // get the pin states for the indicated port.
  curr = *portInputRegister(port + 2);
  mask = curr ^ PCintLast[port];
  PCintLast[port] = curr;
  // mask is pins that have changed. screen out non pcint pins.
  if ((mask &= *port_to_pcmask[port]) == 0) {
    return;
  }
  // mask is pcint pins that have changed.
  for (uint8_t i = 0; i < 8; i++) {
    bit = 0x01 << i;
    if (bit & mask) {
      pin = port * 8 + i;
      if (PCintFunc[pin] != NULL) {
        PCintFunc[pin]();
      }
    }
  }
}

SIGNAL(PCINT0_vect) {
  PCint(0);
}
SIGNAL(PCINT1_vect) {
  PCint(1);
}
SIGNAL(PCINT2_vect) {
  PCint(2);
}

// End of interrupts code and start of the reader code

volatile long reader1 = 0, reader2 = 0, reader3 = 0;
volatile long ReaderA, Default = 268435455;
volatile int reader1Count = 0, reader2Count = 0,  reader3Count = 0;

void reader1One(void) {
  if (digitalRead(4) == LOW) {
    reader1Count++;
    reader1 = reader1 << 1;
    reader1 |= 1;
  }
}

void reader1Zero(void) {
  if (digitalRead(5) == LOW) {
    reader1Count++;
    reader1 = reader1 << 1;
  }
}

void reader2One(void) {
  if (digitalRead(6) == LOW) {
    reader2Count++;
    reader2 = reader2 << 1;
    reader2 |= 1;
  }
}

void reader2Zero(void) {
  if (digitalRead(7) == LOW) {
    reader2Count++;
    reader2 = reader2 << 1;
  }
}

void reader3One(void) {
  if (digitalRead(8) == LOW) {
    reader3Count++;
    reader3 = reader3 << 1;
    reader3 |= 1;
  }
}

void reader3Zero(void) {
  if (digitalRead(9) == LOW) {
    reader3Count++;
    reader3 = reader3 << 1;
  }
}

void setup()
{
  Serial.begin(9600);
  // Attach pin change interrupt service routines from the Wiegand RFID readers
  PCattachInterrupt(4, reader1One, CHANGE);
  PCattachInterrupt(5, reader1Zero, CHANGE);
  PCattachInterrupt(6, reader2One, CHANGE);
  PCattachInterrupt(7, reader2Zero, CHANGE);
  PCattachInterrupt(8, reader3One, CHANGE);
  PCattachInterrupt(9, reader3Zero, CHANGE);
  delay(10);
  // the interrupt in the Atmel processor mises out the first negitave pulse as the inputs are already high,
  // so this gives a pulse to each reader input line to get the interrupts working properly.
  // Then clear out the reader variables.
  // The readers are open collector sitting normally at a one so this is OK
  for (int i = 4; i < 10; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH); // enable internal pull up causing a one
    digitalWrite(i, LOW); // disable internal pull up causing zero and thus an interrupt
    pinMode(i, INPUT);
    digitalWrite(i, HIGH); // enable internal pull up
  }
  delay(10);
  // put the reader input variables to zero
  reader1 = reader2 = reader3 = 0;
  reader1Count = reader2Count =  reader3Count = 0;
  digitalWrite(13, HIGH);  // show Arduino has finished initilisation
}

void loop() {
  if (reader1Count >= 34) {
    Serial.print("ReaderA:");
    ReaderA = reader1 & 0xfffffff;
    ReaderA = (Default - ReaderA) / 2;
    Serial.println(ReaderA);
    reader1 = 0;
    reader1Count = 0;
  }
  /*
    if(reader2Count >= 34){
    Serial.print("ReaderB:");Serial.println(reader2 & 0xffff);
    reader2 = 0;
    reader2Count = 0;
    }

    if(reader3Count >= 26){
    Serial.print("ReaderC:");Serial.println(reader3 & 0xfffffff);
    reader3 = 0;
    reader3Count = 0;
    }
  */
}

Read the data sheet for the mega processor and make the appropriate changes.

I found that PCINT20 And PCINT21 in UNO and Mega are 4,5 AND A12,A13 ...Respectively...I have substituted A12,A13 instead
of 4,5 ..And same on Hardware but No Luck.... :confused:

Respectively...I have substituted A12,A13 instead
of 4,5 ..

No surprise, it sounds wrong.
I haven't got a Mega 2560 so I can't check it out, but some on rewrote my code so try this:-

// WiegandReader
// credit to Mike Cook
// http://www.thebox.myzen.co.uk/Hardware/Crazy_People.html

// version 0.05.00

#include "pins_arduino.h"

#define ID_LEN 26
#define DATA_PIN_0 4
#define DATA_PIN_1 5

/*
 pins_arduino.h is an extension to the interrupt support for arduino.
 add pin change interrupts to the external interrupts, giving a way
 for users to have interrupts drive off of any pin.
 Refer to avr-gcc header files, arduino source and atmega datasheet.

 Theory: all IO pins on Atmega168 are covered by Pin Change Interrupts.
 The PCINT corresponding to the pin must be enabled and masked, and
 an ISR routine provided.  Since PCINTs are per port, not per pin, the ISR
 must use some logic to actually implement a per-pin interrupt service.

 Pin to interrupt map:
 D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
 D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
 A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
*/


////////////////////////////////////////////////////////
// interrupt code
////////////////////////////////////////////////////////

volatile uint8_t *port_to_pcmask[] = { &PCMSK0, &PCMSK1, &PCMSK2 };
typedef void (*voidFuncPtr)(void);
volatile static voidFuncPtr PCintFunc[24] = { NULL };
volatile static uint8_t PCintLast[3];

////////////////////////////////////////
// attach an interrupt to a specific pin using pin change interrupts.
void PCattachInterrupt(uint8_t pin, void (*userFunc)(void), int mode) 
{

  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  uint8_t slot;
  volatile uint8_t *pcmask;

  if (mode != CHANGE) 
  {
    return;
  }

  // map pin to PCIR register
  if (port == NOT_A_PORT) 
  {
    return;
  } 
  else 
  {
    port -= 2;
    pcmask = port_to_pcmask[port];
  }

  slot = port * 8 + (pin % 8);
  PCintFunc[slot] = userFunc;

  // set the mask
  *pcmask |= bit;

  // enable the interrupt
  PCICR |= 0x01 << port;

}

////////////////////////////////////////
void PCdetachInterrupt(uint8_t pin) 
{
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *pcmask;

  // map pin to PCIR register
  if (port == NOT_A_PORT) 
  {
    return;
  } 
  else 
  {
    port -= 2;
    pcmask = port_to_pcmask[port];
  }

  // disable the mask.
  *pcmask &= ~bit;

  // if that's the last one, disable the interrupt.
  if (*pcmask == 0) 
  {
    PCICR &= ~(0x01 << port);
  }
}

////////////////////////////////////////
// common code for isr handler. "port" is the PCINT number.
// there isn't really a good way to back-map ports and masks to pins.
static void PCint(uint8_t port) 
{
  uint8_t bit;
  uint8_t curr;
  uint8_t mask;
  uint8_t pin;

  // get the pin states for the indicated port.
  curr = *portInputRegister(port+2);
  mask = curr ^ PCintLast[port];
  PCintLast[port] = curr;

  // mask is pins that have changed. screen out non pcint pins.
  if ((mask &= *port_to_pcmask[port]) == 0) 
  {
    return;
  }

  // mask is pcint pins that have changed.
  for (uint8_t i=0; i < 8; i++) 
  {
    bit = 0x01 << i;
    if (bit & mask) 
    {
      pin = port * 8 + i;
      if (PCintFunc[pin] != NULL) 
      {
        PCintFunc[pin]();
      }
    }
  }
}

////////////////////////////////////////
SIGNAL(PCINT0_vect) 
{
  PCint(0);
}

////////////////////////////////////////
SIGNAL(PCINT1_vect) 
{
  PCint(1);
}

////////////////////////////////////////
SIGNAL(PCINT2_vect) 
{
  PCint(2);
}

////////////////////////////////////////////////////////
// end of interrupt code
////////////////////////////////////////////////////////

volatile long reader1 = 0; 
volatile int reader1Count = 0;

////////////////////////////////////////
void read0(void) 
{
  if(digitalRead(DATA_PIN_0) == LOW)
  {
    reader1Count++;
    reader1 = reader1 << 1;  
    Serial.print("0");
  }
}

////////////////////////////////////////
void read1(void) 
{
  if(digitalRead(DATA_PIN_1) == LOW)
  {
    reader1Count++;
    reader1 = reader1 << 1;
    reader1 |= 1;
    Serial.print("1");
  }
}

////////////////////////////////////////
void setup()
{

  Serial.begin(57000);

  // Attach pin change interrupt service routines from the Wiegand RFID readers
  PCattachInterrupt(DATA_PIN_0, read0, CHANGE);
  PCattachInterrupt(DATA_PIN_1, read1, CHANGE);
  
  delay(10);

  // the interrupt in the Atmel processor misses out the first negative pulse as the inputs are already high,
  // so this gives a pulse to each reader input line to get the interrupts working properly.
  // Then clear out the reader variables.
  // The readers are open collector sitting normally at a one so this is OK
  for(int i = 4; i<10; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH); // enable internal pull up causing a one
    digitalWrite(i, LOW);  // disable internal pull up causing zero and thus an interrupt
    pinMode(i, INPUT);
    digitalWrite(i, HIGH); // enable internal pull up
  }

  delay(10);

  // clear the reader input variables
  reader1 = 0;
  reader1Count = 0; 
  digitalWrite(13, HIGH);  // show Arduino has finished initialisation

  Serial.println("");
  Serial.println("****************");
  Serial.println("setup done");
  Serial.println("****************"); 

}

////////////////////////////////////////
void loop() 
{
  if(reader1Count >= ID_LEN)
  {
    Serial.println("");
    Serial.println("---------------------");    

    Serial.print("bits: ");
    Serial.println(reader1Count);
    Serial.print("data: ");
    Serial.println(reader1 & 0xfffffff);

    Serial.print("hex: ");
    Serial.println(reader1, HEX);

    Serial.println("---------------------"); 
    
    reader1 = 0;
    reader1Count = 0;
  }
    
}

The PCINT pins on the Mega are ports/pins B0..B7, E0, J0, J1, K0..K7.

mapping to arduino pin numbers:
B0 53
B1 52
B2 51
B3 50
B4 10
B5 11
B6 12
B7 13
E0 0
J0 15
J1 14
K0 A8
K1 A9
K2 A10
K3 A11
K4 A12
K5 A13
K6 A14
K7 A15

The datasheet will explain the mapping from PCINT registers to these ports/pins (there are only
3 PCINT 8-bit registers, so a max of 24 pins can be mapped.

Grumpy_Mike:
No surprise, it sounds wrong.
I haven't got a Mega 2560 so I can't check it out, but some on rewrote my code so try this:-

// WiegandReader

// credit to Mike Cook
// http://www.thebox.myzen.co.uk/Hardware/Crazy_People.html

// version 0.05.00

#include "pins_arduino.h"

#define ID_LEN 26
#define DATA_PIN_0 4
#define DATA_PIN_1 5

/*
pins_arduino.h is an extension to the interrupt support for arduino.
add pin change interrupts to the external interrupts, giving a way
for users to have interrupts drive off of any pin.
Refer to avr-gcc header files, arduino source and atmega datasheet.

Theory: all IO pins on Atmega168 are covered by Pin Change Interrupts.
The PCINT corresponding to the pin must be enabled and masked, and
an ISR routine provided.  Since PCINTs are per port, not per pin, the ISR
must use some logic to actually implement a per-pin interrupt service.

Pin to interrupt map:
D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
*/

////////////////////////////////////////////////////////
// interrupt code
////////////////////////////////////////////////////////

volatile uint8_t *port_to_pcmask[] = { &PCMSK0, &PCMSK1, &PCMSK2 };
typedef void (*voidFuncPtr)(void);
volatile static voidFuncPtr PCintFunc[24] = { NULL };
volatile static uint8_t PCintLast[3];

////////////////////////////////////////
// attach an interrupt to a specific pin using pin change interrupts.
void PCattachInterrupt(uint8_t pin, void (*userFunc)(void), int mode)
{

uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  uint8_t slot;
  volatile uint8_t *pcmask;

if (mode != CHANGE)
  {
    return;
  }

// map pin to PCIR register
  if (port == NOT_A_PORT)
  {
    return;
  }
  else
  {
    port -= 2;
    pcmask = port_to_pcmask[port];
  }

slot = port * 8 + (pin % 8);
  PCintFunc[slot] = userFunc;

// set the mask
  *pcmask |= bit;

// enable the interrupt
  PCICR |= 0x01 << port;

}

////////////////////////////////////////
void PCdetachInterrupt(uint8_t pin)
{
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *pcmask;

// map pin to PCIR register
  if (port == NOT_A_PORT)
  {
    return;
  }
  else
  {
    port -= 2;
    pcmask = port_to_pcmask[port];
  }

// disable the mask.
  *pcmask &= ~bit;

// if that's the last one, disable the interrupt.
  if (*pcmask == 0)
  {
    PCICR &= ~(0x01 << port);
  }
}

////////////////////////////////////////
// common code for isr handler. "port" is the PCINT number.
// there isn't really a good way to back-map ports and masks to pins.
static void PCint(uint8_t port)
{
  uint8_t bit;
  uint8_t curr;
  uint8_t mask;
  uint8_t pin;

// get the pin states for the indicated port.
  curr = *portInputRegister(port+2);
  mask = curr ^ PCintLast[port];
  PCintLast[port] = curr;

// mask is pins that have changed. screen out non pcint pins.
  if ((mask &= *port_to_pcmask[port]) == 0)
  {
    return;
  }

// mask is pcint pins that have changed.
  for (uint8_t i=0; i < 8; i++)
  {
    bit = 0x01 << i;
    if (bit & mask)
    {
      pin = port * 8 + i;
      if (PCintFunc[pin] != NULL)
      {
        PCintFuncpin;
      }
    }
  }
}

////////////////////////////////////////
SIGNAL(PCINT0_vect)
{
  PCint(0);
}

////////////////////////////////////////
SIGNAL(PCINT1_vect)
{
  PCint(1);
}

////////////////////////////////////////
SIGNAL(PCINT2_vect)
{
  PCint(2);
}

////////////////////////////////////////////////////////
// end of interrupt code
////////////////////////////////////////////////////////

volatile long reader1 = 0;
volatile int reader1Count = 0;

////////////////////////////////////////
void read0(void)
{
  if(digitalRead(DATA_PIN_0) == LOW)
  {
    reader1Count++;
    reader1 = reader1 << 1; 
    Serial.print("0");
  }
}

////////////////////////////////////////
void read1(void)
{
  if(digitalRead(DATA_PIN_1) == LOW)
  {
    reader1Count++;
    reader1 = reader1 << 1;
    reader1 |= 1;
    Serial.print("1");
  }
}

////////////////////////////////////////
void setup()
{

Serial.begin(57000);

// Attach pin change interrupt service routines from the Wiegand RFID readers
  PCattachInterrupt(DATA_PIN_0, read0, CHANGE);
  PCattachInterrupt(DATA_PIN_1, read1, CHANGE);
 
  delay(10);

// the interrupt in the Atmel processor misses out the first negative pulse as the inputs are already high,
  // so this gives a pulse to each reader input line to get the interrupts working properly.
  // Then clear out the reader variables.
  // The readers are open collector sitting normally at a one so this is OK
  for(int i = 4; i<10; i++)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH); // enable internal pull up causing a one
    digitalWrite(i, LOW);  // disable internal pull up causing zero and thus an interrupt
    pinMode(i, INPUT);
    digitalWrite(i, HIGH); // enable internal pull up
  }

delay(10);

// clear the reader input variables
  reader1 = 0;
  reader1Count = 0;
  digitalWrite(13, HIGH);  // show Arduino has finished initialisation

Serial.println("");
  Serial.println("");
  Serial.println("setup done");
  Serial.println("
");

}

////////////////////////////////////////
void loop()
{
  if(reader1Count >= ID_LEN)
  {
    Serial.println("");
    Serial.println("---------------------");

Serial.print("bits: ");
    Serial.println(reader1Count);
    Serial.print("data: ");
    Serial.println(reader1 & 0xfffffff);

Serial.print("hex: ");
    Serial.println(reader1, HEX);

Serial.println("---------------------");
   
    reader1 = 0;
    reader1Count = 0;
  }
   
}

hi mike sir,
i have connected wiegand0 to 4 number pin and wiegand1 to 5 and tried your code but no data on serial monitor

its should work its just change of interrupt pins Right ? :confused:

when added SoftwareSerial library with mikes code on UNO it is also conflicting ...and giving "multiple pin defination"error...is there any solution to this?
can i use software serial on analog pins ?

one simple question to the mike sir,
can i use hardware serial 0(rx)and 1(tx) along with your code?
because i want to add gprs module ...i thought that it is not possible with SoftwareSerial..so planning to use hardware serial port ..will it interfere with your code?

can i use hardware serial 0(rx)and 1(tx) along with your code?

Yes I don't see why not.