Friday, June 1, 2012

RDM6300 RFID with PIC18 Dev Board

After getting a simple LED-blink program working, I moved on to the RFID portion of my project.  It seemed to be the simplest of the three major parts (RFID, SD card, and MP3) because it's basically just configuring the UART to receive and check the card IDs.  I'm using the RDM6300 UART RFID Module from ITeadStudio, which cost $11 for the reader and $0.50 per card.  The datasheet is posted and it describes both the pinout of the module and the data format.  I started out by wiring up the power, ground, and TX line to an FTDI breakout board to verify that the RFID reader worked correctly by reading the data into Docklight.  The data format is 9600bps 8N1 serial.  The datasheet listed 13 bytes (0x02, 10 data bytes, checksum, 0x03), yet I consistently received 14 bytes.  I'm not totally sure what's going on, but I always get the same 14 bytes, so I just recorded those for each of the 10 cards I purchased.  The table below shows the hex values I receive for each of the cards.


The datasheet for the RFID module lists the operating current as <50 mA, which is high enough that I want to be able to turn the module on and off from the PIC instead of just leaving it on all the time.  To do this, I used a 2N3906 PNP transistor in between the board 5V supply and the RFID 5V supply, with the base connected to a GPIO with a 1k resistor.  Turning the GPIO high turns the RFID module on;  setting it low turns the RFID module off.  Using the transistor dropped the supply from 5V to 4.87V, but this is still within the +/-5% of 5V listed on the datasheet spec, and it appears to be working just fine.  I also added a resistor divider to the UART TX line of the RFID module to bring the 5V output down below 3.3V.  The following two pictures show a circuit diagram of this, and then what it looks like soldered onto my development board (some parts/wires were soldered underneath the RFID module).



The PIC C18 compiler comes with a set of peripheral libraries, including one for the USART, which made it very easy to configure the USART and had a good example of using it to send and receive data.  Once I verified that I could receive a single card's data, I set up a demo with three RFID tags programmed into the PIC so that it would toggle an LED based on which card was swiped.  I initially tried to use the "gets1USART" function to read a 14 characters off of the USART, but every once and a while the RFID unit spits out a random bad character (sometimes at power up) that was causing me issues.  Instead, the USART reception is handled using an interrupt service routine, and I pulled the basic setup for it from an Example #6 in an older copy of the C18 Getting Started Guide.  The code is below, followed by a video of the demo.  Note that the code assumes a 16 Mhz clock speed, like my previous post.  You'll need to adjust the USART initialization line and delay line if you're using a different clock speed.

#include <p18lf26j11.h>
#include <delays.h>
#include <usart.h>
#include <string.h>

#pragma config OSC = HS //High speed crystal
#pragma config WDTEN = OFF //Disable watchdog timer
#pragma config XINST = OFF //Disable Extended CPU mode

//LED Pin Configuration
#define LED1Pin LATAbits.LATA0
#define LED1Tris TRISAbits.TRISA0
#define LED2Pin LATAbits.LATA1
#define LED2Tris TRISAbits.TRISA1
#define LED3Pin LATAbits.LATA2
#define LED3Tris TRISAbits.TRISA2

#define RFIDVCCPin LATBbits.LATB4 //Define RFIDVCCPin as PORT B Pin 4
#define RFIDVCCTris TRISBbits.TRISB4 //Define RFIDVCCTris as TRISB Pin 4

//Flags & Data Reception Variables
volatile char tagRecdFlag;
volatile char tagComingFlag;
volatile char tagCounter;
volatile char tagRX[14] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

//RFID Tag IDs
char rfidTag1[14] = {0x02, 0x30, 0x35, 0x30, 0x30, 0x41, 0x44, 0x44, 0x38, 0x46, 0x46, 0x43, 0x3f, 0x03};
char rfidTag2[14] = {0x02, 0x30, 0x35, 0x30, 0x30, 0x41, 0x44, 0x42, 0x46, 0x35, 0x37, 0x36, 0x30, 0x03};
char rfidTag3[14] = {0x02, 0x30, 0x35, 0x30, 0x30, 0x41, 0x45, 0x33, 0x46, 0x36, 0x35, 0x44, 0x33, 0x03};

//Function Prototypes
void rx_handler(void);
//Function Prototypes

#pragma code rx_interrupt = 0x8
void rx_int(void)
{
    _asm goto rx_handler _endasm
}
#pragma code

#pragma interrupt rx_handler
void rx_handler(void)
{
    unsigned char rxByte;
    rxByte = RCREG1; //Read character received from USART

    if (tagComingFlag == 0 && rxByte == 0x02)
    {
        tagRX[tagCounter] = rxByte;
        tagComingFlag = 1;
        tagCounter++;
    }   else if (tagComingFlag == 1)
        {
            tagRX[tagCounter] = rxByte;
            tagCounter++;
            if (tagCounter == 14)
            {
                tagCounter = 0;
                tagComingFlag = 0;
                tagRecdFlag = 1;
            }
        }   else
            {
                tagComingFlag = 0;
                tagCounter = 0;
            }
    PIR1bits.RCIF = 0; //Clear interrupt flag
}

void main()
{
        //Set LED Pins data direction to OUTPUT
        LED1Tris = 0;
        LED2Tris = 0;
        LED3Tris = 0;
        //Set LED Pins to OFF
        LED1Pin = 0;
        LED2Pin = 0;
        LED3Pin = 0;

        tagRecdFlag = 0; //Set in ISR if new RFID tag has been read
        tagComingFlag = 0; //Indicates if a tag is partially received
        tagCounter = 0; //Counts byte index
        
        //USART1 Initialization
        Open1USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW, 25);

        //Interrupts
        RCONbits.IPEN = 1;  //Enable interrupt priority
        IPR1bits.RC1IP = 1;  //Make receive interrupt high priority
        INTCONbits.GIEH = 1; //Enable all high priority interrupts
        
        //Turn on RFID Module
        RFIDVCCTris = 0; //Set to output
        RFIDVCCPin = 1; //Turn on RFID Module

        while(1)
        {
            if (tagRecdFlag)
            {                 
                //Toggle LED corresponding to which card was read
                if (memcmp(tagRX, rfidTag1, 14) == 0)
                {
                    LED1Pin = ~LED1Pin;
                }
                if (memcmp(tagRX, rfidTag2, 14) == 0)
                {
                    LED2Pin = ~LED2Pin;
                }
                if (memcmp(tagRX, rfidTag3, 14) == 0)
                {
                    LED3Pin = ~LED3Pin;
                }

                //Delay 1/2 sec & clear flags to prevent repeated card read
                Delay10KTCYx(200);
                tagRecdFlag = 0; 
                tagComingFlag = 0; 
                tagCounter = 0; 
                }
        }
}