/************************************************************** ***** Mouse-Implanted RFID Project ******* ***** Base Station Code ******* ***** ******* ***** By Dan Golden ******* ***** 09/11/2004 ******* **************************************************************/ /* This code is for the Atmel Mega32 Microcontroller */ /************************************ ***** Port Description ******* ************************************ Inputs: D[2] Base Station Data Output Outputs: C[0:7] LEDs (for testing) /************************************ ***** Encoding Notes ******* ************************************ Manchester encoding is used to communicate from the transponder to the base station. Traditionally, in manchester encoding, the data ALWAYS contains an edge on the clock's falling edge; a logic 1 is a rising edge, a logic 0 is a falling edge. However, this base station INVERTS the received data; hence, a logic 1 is a falling edge on the falling clock edge, and a logic 0 is a rising edge on the falling clock edge. Ex. _ _ _ _ _ _ _ _ CLK |_| |_| |_| |_| |_| |_| |_| |_ _ _ _ ___ ___ _ DATA Sent |_| |___| |_| |___| |_| |_ _ ___ _ ___ _ _ DATA Rec'd _| |_| |_| |___| |___| |_| | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | Obviously, the received data is what is parsed. Clock Periods of Note: Width of one half clock period: 256 us = 64 CLK/64 cycles Width of one full clock period: 513 us = 128 CLK/64 cycles Width of four clock periods (1/2 byte): 2.05 ms = 512 CLK/64 cycles */ /************************************ ***** Includes ******* ************************************/ #include #include #include #include /************************************ ***** Definitions ******* ************************************/ #define dataInput PIND.2 #define debugOut PORTA.0 #define LEDs PORTC /************************************ ***** Global Variables ******* ************************************/ unsigned char count; // General indexing variable unsigned char bitStream[3]; // Used to parse input data unsigned char bitNumber, byteNumber; unsigned char lastEdge, thisEdge, CLKedge, getData; unsigned char data; /* The data byte received at the Base Station from the transponder. */ unsigned char dataReady; // True when the data is ready unsigned char junkByte; // True if the current byte is invalid unsigned char junkCounter; // # of successive junk bytes since last sync char sync; // Sync level // 0: not syncing (receiving data) // -1: not synced (waiting for sync pulse) /************************************ ***** Function Prototypes ******* ************************************/ void initialize(void); /************************************ ***** Interrupts ******* ************************************/ /* This interrupt is used only for FINDING the clock from the initial clock sync byte. Parsing DATA is done separately. */ interrupt [EXT_INT0] void data_edge(void) { thisEdge = dataInput; // If the detected period is too low (T < 200 us), then label // this byte as junk. if(TCNT1 < 50) junkByte = 1; // Label the byte as junk. // 200 us < T < 384 us. This period occurs after a clock edge or a same-bit // boundary (e.g., 1-1 or 0-0). else if (TCNT1 < 96) { // If we're at a clock edge... if (CLKedge) { CLKedge = 0; getData = 1; } else CLKedge = 1; } // 384 us < T < 600 us. // This period occurs after an opposing-bit boundary ONLY. else if (TCNT1 < 150) { CLKedge = 0; getData = 1; } // If the pulse period is too different from any legal values, the byte is junk. else { junkByte = 1; } // Reset timer1 TCNT1 = 0; // If we're on a rising clock edge, it's time to get the data if (getData) { getData = 0; // Shift bitstream down bitStream[0] >>= 1; bitStream[0] |= (bitStream[1] << 7); bitStream[1] >>= 1; bitStream[1] |= (bitStream[2] << 7); bitStream[2] >>= 1; // Insert the most recent bit into bitStream bitStream[2] |= ((!dataInput) << 7); bitNumber++; } // If we have sync, and we've just updated bitStream and bitStream has // all 8 bits of data, then read the data. If the data has been // marked as junk for any reason, then set it to 0xff. if ((~CLKedge) && (sync != -1) && (bitNumber == 8)) { // If the data is junk, make it 0xff. if (junkByte) { data = 0xff; junkCounter++; } else { data = bitStream[2]; junkCounter = 0; } byteNumber++; // Force a sync every 100 data bytes, or if we get three junk // bytes in a row. if ((byteNumber == 100) || (junkCounter > 2)) { sync = -1; TCNT0 = 0; TIMSK |= 0b00000010; // Send 0xff's while syncing } dataReady = 1; bitNumber = 0; junkByte = 0; } // If we're searching for the sync stream... else if ((~CLKedge) && (sync == -1)) { // If we've found the sync, stop searching and get ready for data. if ((bitStream[0] == 0x00) && (bitStream[1] == 0xff) && (bitStream[2] == 0xff)) { sync = 0; TIMSK &= 0b11111101; // Stop sending 0xff's bitNumber = 0; byteNumber = 0; } } } interrupt [TIM0_COMP] void timer0_compare(void) { data = 0xff; dataReady = 1; } /************************************ ***** Main ******* ************************************/ void main(void) { initialize(); while(1) { if (dataReady) // If we have received data... { LEDs = ~data; dataReady = 0; // Prepare for new data printf("%c", data); // send data to USART } if (TIFR & 0x04) // If timer 1 has overflowed (T = 0.26 sec)... { TIFR = TIFR | 0x04; // Clear TOV1. sync = -1; // Start syncing. TCNT0 = 0; TIMSK |= 0b00000010; // Send 0xff's while syncing. } } } /************************************ ***** Function Definitions ******* ************************************/ /************************************ ***** Initialization ******* ************************************/ void initialize(void) { /**** Port initialization ****/ DDRD = 0x00; // D.2 is data input DDRA = 0x01; // A.0 is debug output DDRC = 0xff; // Port C is LED output LEDs = 0xff; // All off initially /**** Interrupt initialization ****/ MCUCR = 0b00000001; // Any edge on INT0 triggers interrupt GICR = 0b01000000; // Enable INT0 /* Timer 1 is used for synchronizing with the transponder's data clock, which should run at around (125e3/64) = 1.95 KHz, which means that edges appear at 3.91 KHz (no opposing bit boundary) or 1.95KHz (at opposing bit boundaries). */ TCCR1B = 0b00000011; // CLK/64 (250 KHz) /* Timer 0 is used to output 0xff data points at the same frequency as the usual data rate when the base is searching for the sync stream. */ TCCR0 = 0b00001101; // CTC on, CLK/1024 (15.6 KHz) OCR0 = 65; // f = 240 Hz (almost 238.5 Hz, the data rate) TIMSK = 0b00000010; // Enable OCIE0 /**** USART initialization ****/ UCSRB = 0b00011000 ; // TXC, RXC enabled UBRRL = 16 ; // 57.6 kbaud @ 16MHz /**** Variable initialization ****/ lastEdge = 0; CLKedge = 0; bitNumber = 0; byteNumber = 0; junkByte = 0; for (count = 0; count < 3; count++) bitStream[count] = 0; data = 0; dataReady = 0; sync = -1; // Initially, we don't have sync /**** Get this party started (enable interrupts) ****/ #asm("sei"); }