Help Porting from duemilanove to Mega2560 and with Wiegand 26

Hello,I am still kind of new to the Arduino so any help is greatly appreciated. I am working on a whole house RFID Entry system. I started out with a Arduino Duemilanove and an ID-20. After getting that working I found the cheaper weatherproof Wiegand RFID readers on ebay and decided to order one to try out.

By Modifying the Crazy People code by Mike Cook I got the general concept working and all seemed well except I needed more digital IO pins to control everything, So i purchased a Mega2560, and uploaded the same sketch. My problem is that The Mega never sends the RFID card data over serial. I can send serial data from the computer to the mega and it operates as expected.

I am thinking this has something to do with the interrupts not directly converting over to the mega, but the documentation for this is almost completely non existent (Or at least I can't find it). I also need to add 1 or 2 more readers but all my attempts failed with errors. (For example, I cannot add a volatile variable &PCMSK3, I get an " 'PCMSK3' was not declared in this scope" error when trying to compile, This is where better documentation would come in, Are these not just unsigned int variables? I thought this line

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

was the declaration)

Here is the code: (works on Duemilanove but not Mega, yes I changed the settings in the tools menu)

/* Wiegand Lock System derived from Crazy People By Mike Cook April 2009
 * 4 RFID readers outputing 26 bit Wiegand code to pins
 * Reader A (Front DOOR1) Pins 4 & 5
 * Reader B (First DOOR2) Pins 6 & 7
 * Reader C (Second DOOR3) Pins 8 & 9
 * Reader D (Third DOOR4) Pins 10 & 11?
 * 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"
  int inByte = 0;
  
/*
 * 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 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()
{
  pinMode(2, OUTPUT); //Reader 1 LED
  pinMode(3, OUTPUT); //Reader 1 Buzzer
  pinMode(14, OUTPUT); //Door 1 Unlock
  
  
  Serial.begin(57000);
  // 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 >= 26){
//  Serial.print(" Reader 1 ");Serial.println(reader1,HEX);
  Serial.println("A");Serial.println(reader1 & 0xfffffff);
  reader1 = 0;
  reader1Count = 0;
     }
     
  if(reader2Count >= 26){
  Serial.println("B");Serial.println(reader2 & 0xfffffff);
  reader2 = 0;
  reader2Count = 0;
     }
     
 if(reader3Count >= 26){
  Serial.println("C");Serial.println(reader3 & 0xfffffff);
  reader3 = 0;
  reader3Count = 0;
     }
  
 //====================================================================    
 if (Serial.available() > 0) {
   inByte = Serial.read();
   if (inByte == 'a') {
       delay(10);
       digitalWrite(13,LOW);
       inByte = Serial.read();
       switch (inByte){
       case '1':
         digitalWrite(2,HIGH);
         digitalWrite(14,HIGH);
         delay(3000);
         digitalWrite(2,LOW);
         digitalWrite(14,LOW);
         break;
       case '2':
         for(int index = 1; index<3 ; index++) {
           digitalWrite(2,HIGH);
           delay(100);
           digitalWrite(2,LOW);
           delay(200);
         }
         break;
       default:
         for(int index = 1; index < 6; index++) {
           digitalWrite(2,HIGH);
           digitalWrite(3,HIGH);
           delay(100);
           digitalWrite(2,LOW);
           digitalWrite(3,LOW);
           delay(200);
         }
       }
       digitalWrite(13,HIGH);
   }
 }
    
}

On the PC end I just wrote a simple VB program that receives serial data and decodes the RFID Number into the site code and serial number, and has buttons that trigger the "Grant Access", "Read Error, and "Deny Access" code on the arduino (by sending "a1" , "a2" or "a")

Any ideas why the Mega isn't sending any data? Anybody know of a good set of documentation for interfacing Wiegand and the Arduino? (or a more thorough description of the setup of the interrupts in the crazy people sketch, I am not really new to programming, just to Arduino)
Thanks in advance
-Brad

Hi Brad,
i had same problem porting my code from Ethernet board to Mega 2560 (still no resolve in rx). Try adding a delay(msec) after each Serial.println() and play with msec, or, better, write your own personal serial print function. I know it's not elegant at all, but it works for me.
Hope it can help you.

The interrupt vectors of the two processors are different so I would expect the code not to work when you change processors.
On the 328 the pin change vectors are 4, 5, & 6 where as on the 1280 they are 10, 11 & 12. I also suspect, but have not checked that the request groups are different due to there being more pins on the 1280.

As the 1280 has 8 straight forward interrupts INT0 to INT7 I would be inclined to use those to call the ISRs.

Ok, so after much failed messing around trying to get one (let alone more) interrupt to work on the Mega, I have decided to use 2 Arduino Pro Minis. The mini uses the 328 chip like the duemilanove, so i assume I can use the same code. Also I discovered that I can purchase 2 minis for less than a single Mega. I am going to try to connect their serial pins...in serial? (not for programming, but for use) as shown below. I don't know if it will work but I figure it is worth a try, worst case i have to use two COM ports, but that is not the end of the world.

As for the idea of adding a delay after serial.print, I tried it first but it didn't help, i eventually discovered that the interrupt functions are never firing as the serial part works when i hard code it to send data.

-----|         |----------------|         |----------------|
USB TX---------RX  Arduino1    TX---------RX  Arduino2    TX ----------|
    5V---------5V              5V---------5V               |           |
   GND---------GND            GND---------GND              |           |
    RX----|    |----------------|         |----------------|           |
-----|    |____________________________________________________________|

Thanks For the help,
-Brad