RFID-RC522 в BASCOM-AVR

Кто ищет — тот найдет! Оказывается, существует отличный пример работы с RFID-RC522 на BASIC в BASCOM-AVR.

Прежде чем изобретать велосипед, нужно всегда уточнить — а не изобрел-ли кто-то такой-же велосипед уже давно. Тем более, в наш век торжества Гугл-поиска и ему подобных, оправдывать себя может только откровенно тупой или ленивый.

Вот и я искал, потом еще искал, потом забросил и писал на C. Потом полез на форум BASCOM-дрочеров (таких-же как я) bascomavr.3bb.ru и случайно, именно случайно, наткнулся на пост о RFID-RC522. В посте не более десятка сообщений, причем половина из них от топик-стартера — активности никакой. В свое время эта тема не вызвала ни у кого особого интереса и благополучно сгинула в бесконечных «листах» форумной ленты.

Но главная проблема была в том, что поиск на форуме не работает без регистрации. Т.е., по мнению администрации подобных форумов, человек, ищущий нужную информацию, должен регистрироваться на каждом сайте и форуме. Ну и сколько тогда времени уйдет на поиск информации? Получается, имея в своем распоряжении неограниченный доступ к любой информации, мы сами себя бьем по рукам и везде ограничиваем. В таком случае, действительно, проще изобрести велосипед заново. Кроме того, устаревшие сообщения форума не выдаются поисковиками, по причине их не активности. Вот и все, тупик — похоронили отличную идею на корню, сами того не понимая.

Исходник я проверил — работает идеально, считывает ID и тип чипа, пишет на чип опознавательную информацию. Ниже — текст исходника «как есть», спизженый с форума. Все равно они там его проебут — они даже не знают, что он там есть. Можно скачать архив с с файлом *.BAS

‘*******************************************************************************
$regfile = «m8adef.dat»
$crystal = 4000000
$hwstack = 150
$swstack = 150
$framesize = 200
$baud = 9600

Const Read_write = 1 ‘ 0= only Read TAG ID 1=Read and Write Data to Card
‘Voltage = 3,3V
‘PortB.5 —> SCK RC522
‘PortB.4 —> MISO RC522
‘PortB.3 —> MOSI RC522
‘PortB 2 CS —> SDA RC522
‘PortB.1 —> Rst RC522
‘*******************************************************************************
Config Portb.1 = Output ‘Reset Pin
Rst522 Alias Portb.1
Set Rst522
Config Portb.2 = Output ‘CS Pin
Cs_pn Alias Portb.2
Set Cs_pn
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 16 , Noss = 1
Spiinit
‘*******************************************************************************
Dim Rc522_buffer(18) As Byte ‘out Buffer
Dim Rc522_inbuffer(18) As Byte ‘in Buffer
Dim Tag_typ As Word ‘Tag Typ
Dim Tag_typa(2) As Byte At Tag_typ Overlay
Dim Tag_idw As Dword ‘Tag ID
Dim Tag_id(4) As Byte At Tag_idw Overlay
Dim Tag_crc As Byte ‘Byte5 CRC
Dim Textbyte(16) As Byte
Dim Text As String * 16 At Textbyte(1) Overlay
Const Pcd_authent = &H0E
Const Pcd_transceive = &H0C
Const Bitframingreg = &H0D
Const Commienreg = &H02
Const Commirqreg = &H04
Const Fifolevelreg = &H0A
Const Controlreg = &H0C
Const Fifodatareg = &H09
Const Commandreg = &H01
Const Errorreg = &H06
Const Picc_auth1a = &H60
Dim Tag_fount As Byte
Dim Status As Byte
Dim Lastbits As Byte
Dim Backleng As Byte
Dim Error1 As Byte
Dim Crc_low As Byte
Dim Crc_high As Byte
‘*******************************************************************************
Declare Sub Write522(byval Addr As Byte , Byval Daten As Byte)
Declare Function Read522(byval Addre As Byte) As Byte
Declare Sub Setbitmask(byval Reg As Byte , Byval Mask As Byte)
Declare Sub Clearbitmask(byval Reg As Byte , Byval Mask As Byte)
Declare Sub Initrc522()
Declare Sub Rc522to_card(byval Command As Byte , Byval Sendlen As Byte)
Declare Sub Rc522_request(byval Reqmode As Byte)
Declare Sub Is_card()
Declare Sub Anticoll()
Declare Sub Calculate_crc(byval Leng As Byte)
Declare Sub Rc522_reset()
Declare Sub Rc522_halt()
Declare Sub Rc522_selecttag()
Declare Sub Rc522_auth(byval Authmode As Byte , Byval Blockaddr As Byte)
Declare Sub Rc522_read(byval Block As Byte)
Declare Sub Rc522_write(byval Block As Byte)
Declare Sub Rc522_stop()
‘*******************************************************************************
Call Initrc522()
‘*******************************************************************************
Print «MC LOAD OK»
‘*******************************************************************************
Do
Call Is_card()
If Tag_fount = 1 Then
Call Anticoll() ‘Read Tag ID
Print «Chip fount»
Print «Tag Typ= » ; Hex(tag_typ)
Print «Tag ID= » ; Hex(tag_id(1)) ; » » ; Hex(tag_id(2)) ; » » ; Hex(tag_id(3)) ; » » ; Hex(tag_id(4))
‘*******************************************************************************
#if Read_write = 1
Call Rc522_selecttag()
If Status = 1 Then
Call Rc522_auth(picc_auth1a , 8) ‘Authentication to enable Sector 2 8/4=2 Sector
Call Rc522_read(8) ‘read Data Sector 2 0
Call Rc522_read(9) ‘read Data Sector 2 +1
Call Rc522_read(10) ‘read Data Sector 2 +2
‘Write Data To Card
Text = «Hello Bascom «
Call Rc522_write(8) ‘write Data Sector 2 0
Text = «>NFC RC522 Demo<«
Call Rc522_write(9) ‘write Data Sector 2 +1
Text = «>by Hkipnik< «
Call Rc522_write(10) ‘write Data Sector 2 +2
End If
#endif
‘*******************************************************************************
Call Rc522_stop() ‘Stop Auth Mode
Call Rc522_halt() ‘go to state Wait for new Card
Else
‘Print «No Chip fount»
End If
‘ Call Rc522_halt()
Wait 1
Loop
End
‘*******************************************************************************
‘*******************************************************************************
‘ is Chip Card fount Call RC522 Request (Help Sub)
‘*******************************************************************************
Sub Is_card()
Call Rc522_request(&H26) ‘PICC_REQIDL 0x26
End Sub
‘*******************************************************************************
‘ Anti- collision detection , reading selected card serial number card
‘ only MIFARE Classic Chips 4Byte ID
‘*******************************************************************************
Sub Anticoll()
Call Write522(bitframingreg , &H00) ‘BitFramingReg 0x0D
Rc522_buffer(1) = &H93 ‘PICC_ANTICOLL 0x93
Rc522_buffer(2) = &H20
Call Rc522to_card(pcd_transceive , 2)
If Backleng = 40 Then ‘fount 5 Bytes Byte 5 is CRC
Tag_id(1) = Rc522_inbuffer(1)
Tag_id(2) = Rc522_inbuffer(2)
Tag_id(3) = Rc522_inbuffer(3)
Tag_id(4) = Rc522_inbuffer(4)
Tag_crc = Rc522_inbuffer(5) ‘use in Rc522_selecttag
End If
End Sub
‘*******************************************************************************
‘ Writes a byte to the specified register in the MFRC522 chip
‘*******************************************************************************
Sub Write522(byval Addr As Byte , Byval Daten As Byte)
Shift Addr , Left , 1
Addr = Addr And &H7E ‘0XXXXXX0
Reset Cs_pn
Spiout Addr , 1
Spiout Daten , 1
Set Cs_pn
End Sub
‘*******************************************************************************
‘ Reads a byte from the specified register in the MFRC522 chip
‘*******************************************************************************
Function Read522(byval Addre As Byte) As Byte
Shift Addre , Left , 1
Addre = Addre And &H7E ‘1XXXXXX0
Addre = Addre Or &H80
Reset Cs_pn
Spiout Addre , 1
Spiin Read522 , 1
Set Cs_pn
End Function
‘*******************************************************************************
‘ Sets the bits given in mask in register reg
‘*******************************************************************************
Sub Setbitmask(byval Reg As Byte , Byval Mask As Byte)
Local Rxin As Byte
Rxin = Read522(reg)
Rxin = Rxin Or Mask
Call Write522(reg , Rxin)
End Sub
‘*******************************************************************************
‘ Clears the bits given in mask from register reg
‘*******************************************************************************
Sub Clearbitmask(byval Reg As Byte , Byval Mask As Byte)
Local Inbyte As Byte
Inbyte = Read522(reg)
Mask = Not Mask
Inbyte = Inbyte And Mask
Call Write522(reg , Inbyte)
End Sub
‘*******************************************************************************
‘ Soft Reset RC522
‘*******************************************************************************
Sub Rc522_reset()
Call Write522(commandreg , &H0F) ‘PCD_RESETPHASE 0x0F
End Sub
‘*******************************************************************************
‘ Init RC522
‘*******************************************************************************
Sub Initrc522()
Reset Rst522
Waitms 100
Set Rst522
Call Rc522_reset()
Waitms 500
Call Write522(&H2a , &H8D) ‘TModeReg 8d
Call Write522(&H2b , &H3E) ‘TPrescalerReg a9 3e
Call Write522(&H2d , &H03) ‘TReloadRegL 25ms before timeout.
Call Write522(&H2c , &HE8) ‘TReloadRegH
Call Write522(&H15 , &H40) ‘TxAutoReg
Call Write522(&H11 , &H3D) ‘ModeReg
‘antene On
Call Setbitmask(&H14 , &H03) ‘TxControlReg
End Sub
‘*******************************************************************************
‘ RC522 and ISO14443 card communication
‘*******************************************************************************
Sub Rc522to_card(byval Command As Byte , Byval Sendlen As Byte)
Local Irqen As Byte , Waitirq As Byte , Timeout As Byte
Local Temps As Byte , N As Byte , Dum As Byte
Select Case Command
Case Pcd_authent:
Irqen = &H12
Waitirq = &H14
Case Pcd_transceive:
Irqen = &H77
Waitirq = &H64
End Select

Dum = Irqen Or &H80
Call Write522(commienreg , Dum) ‘CommIEnReg CommIEnReg 0x02
Call Clearbitmask(commirqreg , &H80) ‘CommIrqReg 0x04
Call Setbitmask(fifolevelreg , &H80) ‘ Fifolevelreg 0x0a
Call Write522(commandreg , &H00) ‘CommandReg 01, PCD_IDLE 00
For Dum = 1 To Sendlen
Call Write522(fifodatareg , Rc522_buffer(dum) ) ‘FIFODataReg 0x09
Next
Call Write522(commandreg , Command)
If Command = Pcd_transceive Then
Call Setbitmask(bitframingreg , &H80) ‘BitFramingReg 0x0D
End If
Timeout = 200
Do
Dum = Read522(commirqreg) ‘CommIrqReg 0x04
Decr Timeout
If Dum = Waitirq Then Exit Do ‘Waitirq
‘ If Dum = &H44 Then Exit Do
Loop Until Timeout = 0

Call Clearbitmask(bitframingreg , &H80) ‘BitFramingReg 0x0D
If Timeout > 0 Then
Temps = Read522(errorreg) ‘ErrorReg
Temps = Temps And &H1B
If Temps = 0 Then ‘todo
Error1 = 0
Else
Error1 = 1
Print «Error»
End If
If Command = Pcd_transceive Then ‘Read Back Data
Dum = Read522(fifolevelreg) ‘FIFOLevelReg = 0x0A
N = Dum
Lastbits = Read522(controlreg) ‘.ControlReg)0C & 0x07
Lastbits = Lastbits And &H07
If Lastbits > 0 Then
Decr Dum
Dum = Dum * 8
Backleng = Dum + Lastbits
Else
Backleng = Dum * 8
End If
If N = 0 Then N = 1
For Dum = 1 To N
Rc522_inbuffer(dum) = Read522(fifodatareg) ‘ FIFODataReg = 0x09
Next
End If
End If
End Sub
‘*******************************************************************************
‘ Find cards , read the card type number
‘ H4400 = Mifare_UltraLight
‘ H0400 = Mifare_one(s50)
‘ H0200 = Mifare_one(s70)
‘ H0800 = Mifare_pro(x)
‘ H4403 = Mifare_desfire
‘*******************************************************************************
Sub Rc522_request(byval Reqmode As Byte)
Call Write522(bitframingreg , &H07) ‘BitFramingReg = 0x0D
Rc522_buffer(1) = Reqmode
Call Rc522to_card(pcd_transceive , 1)
If Backleng = 16 Then
Tag_fount = 1 ‘Chip fount
Tag_typa(2) = Rc522_inbuffer(1) ‘Little Endian
Tag_typa(1) = Rc522_inbuffer(2)
Else
Tag_fount = 0
End If
End Sub
‘*******************************************************************************
‘Use the CRC coprocessor in the MFRC522 to calculate a CRC
‘*******************************************************************************
Sub Calculate_crc(byval Leng As Byte)
Local Zbv1 As Byte , Timeou As Word
Call Clearbitmask(&H05 , &H04) ‘ DivIrqReg 0x05
Call Setbitmask(fifolevelreg , &H80) ‘FIFOLevelReg 0x0A
For Zbv1 = 1 To Leng
Call Write522(fifodatareg , Rc522_buffer(zbv1) ) ‘FIFODataReg 0x09
Next
Call Write522(commandreg , &H03) ‘CommandReg 0x01
Timeou = 2000
Do
Zbv1 = Read522(&H05) ‘ DivIrqReg 0x05
Decr Timeou
Loop Until Timeou = 0 Or Zbv1 = &H04 ’04
Crc_low = Read522(&H22) ‘Crcresultregl 0x22
Crc_high = Read522(&H21) ‘Crcresultregm 0x21
End Sub
‘*******************************************************************************
‘Instructs a Chip in state ACTIVE(*) to go to state HALT.
‘*******************************************************************************
Sub Rc522_halt()
Rc522_buffer(1) = &H50 ‘PICC_HALT 0x50
Rc522_buffer(2) = &H00
Call Calculate_crc(2)
Rc522_buffer(3) = Crc_low
Rc522_buffer(4) = Crc_high
Call Rc522to_card(pcd_transceive , 4)
End Sub
‘*******************************************************************************
‘Select card,and read Card storage volume
‘*******************************************************************************
Sub Rc522_selecttag()
Rc522_buffer(1) = &H93 ‘PICC_SElECTTAG = 0x93
Rc522_buffer(2) = &H70
Rc522_buffer(3) = Tag_id(1)
Rc522_buffer(4) = Tag_id(2)
Rc522_buffer(5) = Tag_id(3)
Rc522_buffer(6) = Tag_id(4)
Rc522_buffer(7) = Tag_crc
Call Calculate_crc(7)
Rc522_buffer(8) = Crc_low
Rc522_buffer(9) = Crc_high
Call Rc522to_card(pcd_transceive , 9)
If Backleng = &H18 Then ’24Bit
Status = 1
‘ Print «Storage Volume KByte » ; Rc522_inbuffer(1) ‘read card storage volume /8
Else
Status = 0
End If
End Sub
‘*******************************************************************************
‘ authMode—password verify mode
‘ Block Sector 0 — 4 — 8 — 12 — 16 — 20 — 24 — 28 — 32 — 36 — 40 — 44 — 48 — 52 — 56 — 60
‘ per Sector read and write 4Byte
‘ Byte4 Config Data only write sector trailer when you know what you’re doing
‘*******************************************************************************
Sub Rc522_auth(byval Authmode As Byte , Byval Blockaddr As Byte)
Rc522_buffer(1) = Authmode
Rc522_buffer(2) = Blockaddr
Rc522_buffer(3) = &HFF ‘Defalt buffer A Password
Rc522_buffer(4) = &HFF
Rc522_buffer(5) = &HFF
Rc522_buffer(6) = &HFF
Rc522_buffer(7) = &HFF
Rc522_buffer(8) = &HFF
Rc522_buffer(9) = Tag_id(1)
Rc522_buffer(10) = Tag_id(2)
Rc522_buffer(11) = Tag_id(3)
Rc522_buffer(12) = Tag_id(4)
Call Rc522to_card(pcd_authent , 12)
End Sub
‘*******************************************************************************
‘ Read data
‘ Block = Blockaddr or Blockaddr +1 or Blockaddr +2
‘ Blockaddr + 3 is Config Data from the Card
‘*******************************************************************************
Sub Rc522_read(byval Block As Byte)
Local Temp2 As Byte
Rc522_buffer(1) = &H30 ‘ PICC_READ = 0x30
Rc522_buffer(2) = Block
Call Calculate_crc(2)
Rc522_buffer(3) = Crc_low
Rc522_buffer(4) = Crc_high
Call Rc522to_card(pcd_transceive , 4)
If Backleng = 144 Then ‘144Bit 18Byte
Print «Read Daten- » ; ‘Dump 16Byte Buffer
For Temp2 = 1 To 16
Print Chr(rc522_inbuffer(temp2)) ;
Next
End If
End Sub
‘*******************************************************************************
‘ Write data
‘ Block = Blockaddr or Blockaddr +1 or Blockaddr +2
‘ Blockaddr + 3 is Config Data from the — Warning: only write sector trailer when you know what you’re doing
‘*******************************************************************************
Sub Rc522_write(byval Block As Byte)
Local Zbv As Byte
Print «Write Data»
Rc522_buffer(1) = &HA0 ‘ PICC_WRITE 0xA0
Rc522_buffer(2) = Block
Call Calculate_crc(2)
Rc522_buffer(3) = Crc_low
Rc522_buffer(4) = Crc_high
Call Rc522to_card(pcd_transceive , 4)
For Zbv = 1 To 16
Rc522_buffer(zbv) = Textbyte(zbv) ‘Copy Text Data to RC522 Buffer
Next
Call Calculate_crc(16)
Rc522_buffer(17) = Crc_low
Rc522_buffer(18) = Crc_high
Call Rc522to_card(pcd_transceive , 18)
End Sub
‘*******************************************************************************
‘Stop Auth Mode
‘*******************************************************************************
Sub Rc522_stop()
Call Clearbitmask(&H08 , &H08) ‘Status2Reg = 0x08
End Sub

Несмотря на то, что BASIC давно считается вымирающим и неперспективным языком программирования (я как программист считаю, что так оно и есть), этот старичок еще способен как следует подергать ножки микроконтроллера. А что еще надо для старых МК типа ATtiny или ATmega? Тем более он предельно прост для начального старта и интуитивно понятен. Дело-то в том, что для большинства «гражданских» поделок большей связки и не нужно — функционала «за глаза», стоимость смешная.

Для всех коммерческих проектов я пишу на C (в основном это всегда требование Заказчика), но для мелких, разовых поделок почти всегда на BASIC-е. Люблю его, он такой теплый и как сейчас модно говорить «ламповый».