Well after a good day of getting used to the basic I/O of some of the PICs I have I decided to tackle a RFID card reader project. The use of an oscilloscope was definitely a huge help in the process. It's taken me about 4 days to get the program to it's current state, really the only thing left to do is replace the "TODO" comments with actual code, but I'll leave that up to whoever actually uses the code. Note: LCD code was taken from pic16.com examples so I can't take credit for that; the original was written in C and I had to port it over to PBP
Here's the hardware:
QL200 Pic Development Board (ebay)
Mini Weigand 26 Card Reader (ebay)
Trine electric strike (16-24 volt model but works fine at 12VDC) (ebay)
PIC 16F8778A (came with the board)
LCD screen (not serial interfaced / connected to portD[0:7])
IRF520 -- interface between PIC output and strike, the strike needs at least 500mA to activate!
RA4 has a pullup resistor
One note about the EEPROM data is that the site code is not stored, it's in a separate constant. The stored data is actually backwards: The first entry is 33971 in hex that is 84B3 so in the EEPROM data it is stored as B3 84. It becomes easier to read that way in the for loop.Code:''''''''''''''''''''''''''''''' ''' Set up I/O ''''''''''''''''''''''''''''''' ADCON1 = %00000111 TRISA = %00000000 TRISD = %00000000 TRISC = %11111111 ''''''''''''''''''''''''''''''' ''' Tell PBP we are running ''' at 20 MHz ''''''''''''''''''''''''''''''' DEFINE osc 20 '''''''''''''''''''''''''' ' Initialize EEPROM ' '''''''''''''''''''''''''' ' 33971 33972 33973 other are 65535 i.e FF or uninitialized DATA @0, 179, 132, 180, 132, 181, 132, 255, 255, 255, 255 DATA @10, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 DATA @20, 03 'Number of users stored in EEPROM ''''''''''''''''''''''''''''''' ''' LCD Screen I/O ''''''''''''''''''''''''''''''' rs var PortA.1 'Register Select (Data/Command Register) rw var PortA.2 'Register Read/Write e var PortA.3 'LCD Enable 'DB0 - DB7 located at PortD ''''''''''''''''''''''''''''''' ''' Temporary variables ''''''''''''''''''''''''''''''' x var byte i var byte ''''''''''''''''''''''''''''''' ''' Most important variables ''''''''''''''''''''''''''''''' CardRead var bit GoodCard var bit PgrmMode var bit BitCount var byte CardWordH var word 'Need two words for 26 bit card CardWordL var word Users var word[10] 'Word array of users containing only user codes NumUsers var byte SiteCode con 209 StrikeTime con 5000 'time in ms to unlock door ''''''''''''''''''''''''''''''' ''' Weigand reader I/O ''''''''''''''''''''''''''''''' Data0 var PORTC.0 Data1 var PORTC.1 Strike var PORTA.5 Buzzer var PORTA.0 GreenLED var PORTA.4 PgrmSw var PORTC.2 ''''''''''''''''''''''''''''''' ''' Initialize variables ''' Card Users and ''' I/O ports For first use ''''''''''''''''''''''''''''''' InitUsers: Read 20, NumUsers if NumUsers = $FF then NumUsers = 0 'Just in case EEPROM has nothing. For i = 0 to NumUsers*2 'Bytes are written reversed For easy reading ;-) Read i, Users.lowbyte(i) Next i BitCount = 0 CardRead = 0 CardWordL = 0 CardWordH = 0 LOW strike HIGH buzzer HIGH GreenLed ''''''''''''''''''''''''''''''' ''' Set up LCD and splash screen ''''''''''''''''''''''''''''''' GoSub LCD_init GoSub write_splash ''''''''''''''''''''''''''''''' ''' Here is the main program ''''''''''''''''''''''''''''''' loop: If PgrmSW = 0 then If CardRead = 1 Then PORTD = %00000001 'clr screen GoSub lcd_cmd For i = 15 to 0 step -1 'This loop writes the Site Code to Line 1 x = 0 x = CardWordH.0(i) x = x | %00110000 'Make x a character GoSub lcd_data Next i PORTD = %11000000 'set the 2nd line display address GoSub lcd_cmd Pause 100 For i = 15 to 0 step -1 'This loop writes the User Code to Line 2 x = 0 x = CardWordL.0(i) x = x | %00110000 'Make x a character GoSub lcd_data Next i CardRead = 0 GoodCard = 0 For i = 0 to NumUsers - 1 If CardWordL = Users[i] and CardWordH = SiteCode Then HIGH Strike 'Activate electric strike LOW GreenLED 'Green LED activated on gnd Pause StrikeTime PORTD = %00000001 'clr screen GoSub lcd_cmd For i = 0 to 15 LOOKUP i, ["CARD ACCEPTED "], x GoSub lcd_data Next i LOW Strike HIGH GreenLED GoodCard = 1 EndIf Next i If GoodCard = 0 then 'Invalid Card For i = 0 to 2 'Beep 3 times LOW Buzzer Pause 100 HIGH Buzzer Pause 100 Next i EndIf CardWordH = 0 CardWordL = 0 EndIf GoSub ReadCard Else 'Init Program Mode While PgrmSw = 1: Wend PgrmMode = 1 PORTD = %00000001 'clr screen GoSub lcd_cmd For i = 0 to 15 LOOKUP i, ["Program Mode "], x GoSub lcd_data Next i While PgrmMode = 1 If PgrmSW = 1 then While PgrmSw = 1: Wend PgrmMode = 0 EndIf 'Main Program Mode Menu Here Wend 'Exit Program Mode / UPDATE EEPROM PORTD = %00000001 'clr screen after exiting program mode GoSub lcd_cmd EndIf Goto loop 'For Program Mode: 'For i = 0 to 1 'Bytes are written reversed For easy reading later ;-) 'write j, CardWordL.lowbyte(i) 'j = j + 1 'Next i ''''''''''''''''''''''''''''''' ''' Card Reading subroutine ''''''''''''''''''''''''''''''' ReadCard: if Data0 = 1 and Data1 = 1 then Return ReadLoop: If Data0 = 0 Then If BitCount > 9 Then ' Bits 0 - 9 go to CardWordH, 10-25 go to CardWordL CardWordL = CardWordL << 1 CardWordL.0 = 0 Else CardWordH = CardWordH << 1 CardWordH.0 = 0 EndIf BitCount = BitCount + 1 While Data0 = 0: Wend EndIf If Data1 = 0 Then If BitCount > 9 Then CardWordL = CardWordL << 1 CardWordL.0 = 1 Else CardWordH = CardWordH << 1 CardWordH.0 = 1 EndIf BitCount = BitCount + 1 While Data1 = 0 : Wend EndIf If BitCount < 26 Then 'TODO: Make sure that we don't end up in an infinite loop here; utilize the i counter i = i + 1 Goto ReadLoop Else BitCount = 0 'TODO: Instead of dropping off parity, check parity and if error clear CardRead and CardWordH/L 'Even Parity: LSB should be 0 'Odd Parity: LSB should be 1 CardWordL = CardWordL >> 1 'Drop odd parity CardWordL.15 = CardWordH.0 'CardWordL contains full user code CardWordH.9 = 0 'Drop even parity CardWordH = CardWordH >> 1 'We copied this bit to CardWordL already so drop it CardRead = 1 EndIf Return ''''''''''''''''''''''''''''''' ''' LCD subroutines below ''''''''''''''''''''''''''''''' LCD_init: PORTD = %00000001 'clr screen GoSub lcd_cmd portd = %00111000 '8 bits 2 lines 5*7 mode. GoSub lcd_cmd portd = %00001101 'display on, cursor off, blink on. GoSub lcd_cmd portd = %00000110 'no shift, cursor move right. GoSub lcd_cmd portd = %10000000 'set ddram address? GoSub lcd_cmd return write_splash: PORTD = %00000001 'clr screen GoSub lcd_cmd For i = 0 to 15 LOOKUP i, ["RFID CONTROLLER "], x GoSub lcd_data Next i PORTD = %11000000 'set the 2nd line display address GoSub lcd_cmd For i = 0 to 15 LOOKUP i, ["(C) TONY FULLER "], x GoSub lcd_data Next i Pause 1000 return lcd_data: PORTD = x 'Set up PORTD[0:7] with correct outputs from temp variable rs = 1 'Data rw = 0 'Write mode e = 0 'make enable port low Pause 10 e = 1 'now create edge return lcd_cmd: rs = 0 'Command rw = 0 'Write mode e = 0 'make enable port low Pause 10 e = 1 'now create edge return ''''''''''''''''''''''''''''''' ''' That's all folks ''''''''''''''''''''''''''''''' end




Bookmarks