/******* T1DP.c for PIC18LF2321 * * Use Fosc = 4 MHz for Fcpu = Fosc/4 = 1 MHz. * Sleep for 16 ms (nominal), using watchdog timeout for wakeup. * Toggle RC2 output every 16 milliseconds for measuring looptime with scope. * Blink LED on RA7 for 16 ms every four seconds. * * Current draw = 4 uA * ******* Program hierarchy ***** * * main * Initial * BlinkAlive * ******************************* */ #include // Define PIC18LF4321 registers and bits #include /******************************* * Configuration selections ******************************* */ #pragma config OSC = INTIO1 // Use internal osc, RA6=Fosc/4, RA7=I/O #pragma config PWRT = ON // Enable power-up delay #pragma config LVP = OFF // Disable low-voltage programming #pragma config WDT = OFF // Disable watchdog timer initially #pragma config WDTPS = 4 // 16 millisecond WDT timeout period, nominal #pragma config MCLRE = ON // Enable master clear pin #pragma config PBADEN = DIG // PORTB<4:0> = digital #pragma config CCP2MX = RB3 // Connect CCP2 internally to RB3 pin #pragma config BOR = SOFT // Brown-out reset controlled by software #pragma config BORV = 3 // Brown-out voltage set for 2.1V, nominal #pragma config LPT1OSC = OFF // Deselect low-power Timer1 oscillator /******************************* * Global variables ******************************* */ #define MAX_BYTES 5 unsigned int DELAY; // Counter for obtaining a delay unsigned char ALIVECNT; // Counter for blinking "Alive" LED unsigned int flagDone; unsigned char databits[MAX_BYTES]; unsigned char maskbit; unsigned char index; unsigned int bitCount; unsigned int ledCounter; unsigned char sendbits[MAX_BYTES+2]; unsigned int sendMask; unsigned int sendIndex; unsigned int dataMask; unsigned int dataIndex; unsigned int offset; unsigned char EEADDRESS; // Starting address in EEPROM unsigned char EECNT; // Number of bytes to copy char GIEHCOPY; // Copy of GIEH bit for EEPROM writes char SBORENCOPY; // Copy of SBOREN bit for EEPROM writes char* RAMPTR; // Pointer to RAM array to be copied to EEPROM unsigned char EEStackPtr; /******************************* * Constant strings ******************************* */ const char HEXITS[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; /******************************* * Variable strings ******************************* */ /******************************* * Function prototypes ******************************* */ void Initial(void); void BlinkAlive(void); void Pushbutton(void); void HiPriISR(void); void LoPriISR(void); void xmitGO(void); void InitTX(void); void txHex(unsigned char); /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } #define TXascii(in) TXREG = in; while(!TXSTAbits.TRMT) /////// Main program ////////////////////////////////////////////////////////// /******************************* * main ******************************* */ void main() { Initial(); // Initialize everything InitTX(); while (1) { flagDone = 1; PORTCbits.RC2 ^= 1; // Toggle pin, for measuring loop time Sleep(); Nop(); if (PORTAbits.RA2 == 1) ++ledCounter; if (ledCounter >= 43) // leaves the LED on for about .5 sec with 16ms watchdog PORTAbits.RA2 = 0; if (bitCount > 0 && flagDone) { PORTAbits.RA2 = 1; // turn LED on ledCounter = 0; // reset counter //TXascii('\r'); //TXascii('\n'); xmitGO(); // cleanup for( index = 0; index < MAX_BYTES; index++){ databits[index] = 0; } maskbit = 128; index = 0; bitCount = 0; } } } /******************************* * Interrupt vectors ******************************* */ // For high priority interrupts: #pragma code high_vector=0x08 void interrupt_at_high_vector(void) { _asm GOTO HiPriISR _endasm} #pragma code #pragma interrupt HiPriISR /******************************* * HiPriISR * * Respond to rising and falling edges on INT2 input from RPG. ******************************* */ void HiPriISR() { flagDone = 0; ++bitCount; if(INTCON3bits.INT2IF){ databits[index] |= maskbit; INTCON3bits.INT2IF = 0; //TXascii('1'); } if(INTCON3bits.INT1IF){ INTCON3bits.INT1IF = 0; //TXascii('0'); } maskbit >>= 1; if(!maskbit){ index++; maskbit = 128; } //if( !index && maskbit == 8) } /******************************* * xmitGO * * ******************************* */ void xmitGO() { INTCONbits.GIEH = 0; // this block of code will send the number of bits read over wiegand /*TXascii((char)(bitCount/10 + 48)); TXascii((char)(bitCount%10 + 48)); TXascii(' '); */ offset = (MAX_BYTES * 8) - bitCount; // difference between max bits and bitCount sendIndex = 1 + offset / 8; // first sendBits char array index to use (starting at least at the second byte) sendMask = 128 >> (offset % 8); // first bit to use in first char being used dataIndex = 0; // start at the beginning of databits dataMask = 128; // first bit in databits if (MAX_BYTES * 8 < bitCount) // if we have too many bits, gtfo { TXascii('X'); // send just an X TXascii('\r'); TXascii('\n'); return; } for( index = 0; index < MAX_BYTES+2; index++){ // initialize the send bits to 0 sendbits[index] = 0; } if (sendMask < 128) // add 1 bit BEFORE all of the other bits. why? i don't know. ask HID. sendbits[sendIndex] = (sendMask << 1) & 0xFF; for (index = 0; index < bitCount; index++) { // loop through all bits if (databits[dataIndex] & dataMask) // if databits is 1 at current dataMask sendbits[sendIndex] |= sendMask; // set sendbits to 1 at current sendMask sendMask >>= 1; // move masks to the right dataMask >>= 1; if(!sendMask){ // if at the end of this byte, move to the next byte sendIndex++; sendMask = 128; } if(!dataMask){ dataIndex++; dataMask = 128; } } // compute checksum byte for the last byte for (index = 0; index < MAX_BYTES+1; index++) // checksum is the 8 least signigicant sendbits[MAX_BYTES+1] += sendbits[index]; // bits of the sum of all the other bytes for(index = 0; index < MAX_BYTES+2; index++){ // send the sendbits as hex! txHex(sendbits[index]); } TXascii('\r'); TXascii('\n'); INTCONbits.GIEH = 1; } /******************************* * xmitGO * * ******************************* */ void txHex(unsigned char in) { // send a char as two hexits TXascii( HEXITS[((0xF0 & in)>>4)] ); TXascii( HEXITS[(0x0F & in)] ); } /******************************* * Initial * * This function performs all initializations of variables and registers. ******************************* */ void Initial() { int i; OSCCON = 0b01100010; // Use Fosc = 4 MHz (Fcpu = 1 MHz) ADCON1 = 0b00001111; // RA0,RA1,RA2,RA3 pins analog; others digital TRISA = 0b00001011; // Set I/O for PORTA TRISB = 0b11100110; // Set I/O for PORTB TRISC = 0b10000000; // Set I/O for PORTC PORTA = 0; // Set initial state for all outputs low PORTB = 0b00000000; PORTC = 0; Delay(50000); // Pause for half a second RCONbits.SBOREN = 0; // Now disable brown-out reset ALIVECNT = 247; // Blink immediately WDTCONbits.SWDTEN = 1; // Enable watchdog timer maskbit = 128; index = 0; flagDone = 1; bitCount = 0; ledCounter = 0; for( i = 0; i < MAX_BYTES; i++){ databits[i] = 0; } INTCON2bits.INTEDG1 = 0; INTCON3bits.INT1IP = 1; INTCON3bits.INT1IE = 1; INTCON3bits.INT1IF = 0; INTCON2bits.INTEDG2 = 0; INTCON3bits.INT2IP = 1; INTCON3bits.INT2IE = 1; INTCON3bits.INT2IF = 0; RCONbits.IPEN = 1; INTCONbits.GIEL = 1; INTCONbits.GIEH = 1; } /******************************* * InitTX * * This function initializes the UART for its TX output function. It assumes * Fosc = 4 MHz. For a different oscillator frequency, use Figure 6-3c to * change BRGH and SPBRG appropriately. ******************************* */ void InitTX() { RCSTA = 0b10010000; // Enable UART TXSTA = 0b00100100; // Enable TX SPBRG = 12; //12 // Set baud rate BAUDCON = 0b00000000; // Invert TX output // 19200 BAUD RATE } /**************************** * EEArrayWrite * * Each time this function is called with EECNT != 0, it writes one byte * from the RAM char[] pointed by RAMPTR, into the EEPROM location whose * address is in EEADDRESS. Then it increments RAMPTR and EEADDRESS and * decrements EECNT. RAMPTR, EEADDRESS and EECNT should not be modified * by other code until EECNT is 0. * Variable declaration: * char* RAMPTR; unsigned char EEADDRESS; unsigned char EECNT; * Example usage: * char TEMPARRAY[] = {'a','b','c','d'}; * RAMPTR = TEMPARRAY + 1; * EEADDRESS = 0x20; * EECNT = 2; * After 2 calls of EEArrayWrite, EECNT = 0; * and EEPROM has 'b' and 'c' in address 0x20 and 0x21 respectively. **************************** * void EEArrayWrite() { if(EECNT && !EECON1bits.WR) // Skip to next loop time for second write { EEDATA = *(RAMPTR++); EEADR = EEADDRESS++; EEwrite(); EECNT--; } } /**************************** * EEread * * This function reads from the EEPROM address identified by EEADR * into EEDATA. **************************** * void EEread() { while (EECON1bits.WR); // Wait on the completion of any write EECON1bits.RD = 1; // Set the RD bit to read from EEADR into EEDATA } /**************************** * EEwrite * * This function writes the data contained in EEDATA into the EEPROM * address identified by EEADR. * The write is self-timed and takes about 4 milliseconds. **************************** * void EEwrite() { while (EECON1bits.WR); // Wait on the completion of any write SBORENCOPY = RCONbits.SBOREN; // Copy SBOREN for subsequent restore RCONbits.SBOREN = 1; // Enable brown-out reset GIEHCOPY = INTCONbits.GIEH; // Copy GIEH for subsequent restore INTCONbits.GIEH = 0; // Disable all interrupts EECON1bits.WREN = 1; // Enable write operation EECON2 = 0x55; // Write first key EECON2 = 0xAA; // Write second key EECON1bits.WR = 1; // Set WR bit to initiate write INTCONbits.GIEH = GIEHCOPY; // Restore global interrupt state RCONbits.SBOREN = SBORENCOPY; // Restore brown-out reset state PORTCbits.RC2 ^= 1; // Toggle pin to flag where write occurs Delay(100); // Add a delay to show sleep after 1 ms of writing } */