Čítačka RFID kariet RC522: Rozdiel medzi revíziami
Zo stránky SensorWiki
Vytvorená stránka „Záverečný projekt predmetu MIPS / LS2025 - '''Meno Priezvisko''' == Zadanie == Toto je ta citacka: https://techfun.sk/produkt/citacka-rfid-rc522-klucenka-a-karta/ Sem príde text zadania, ak bolo len voľne formulované, rozpíšte ho podrobnejšie 400px|thumb|center|Vývojová doska ACROB. '''Literatúra:''' * [http://ap.urpi.fei.stuba.sk/sensorwiki/index.php/Acrob_technical_description Dokumentácia k doske Acrob] * [http://www.hu…“ |
Bez shrnutí editace |
||
(17 medziľahlých úprav od rovnakého používateľa nie je zobrazených.) | |||
Riadok 4: | Riadok 4: | ||
== Zadanie == | == Zadanie == | ||
Toto je | Toto je čítačka s ktorou pracujem: | ||
https://techfun.sk/produkt/citacka-rfid-rc522-klucenka-a-karta/ | https://techfun.sk/produkt/citacka-rfid-rc522-klucenka-a-karta/ | ||
Čítačka RFID kariet RC522 - spojazdniť, vedieť načítať kartu a jej ID, vytvoriť program ktorý rozozná konkrétnu kartu a rozsvieti LED. | |||
[[Obrázok: | [[Obrázok:UNO.jpg|400px|thumb|center|Vývojová doska Arduino UNO.]] | ||
'''Literatúra:''' | '''Literatúra:''' | ||
* [ | * [https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf Dokumentácia k mikroprocesoru ATmega328P] | ||
* [ | * [https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf Dokumentácia k mikroprocesoru MFRC522] | ||
Riadok 21: | Riadok 21: | ||
== Analýza a opis riešenia == | == Analýza a opis riešenia == | ||
Modul MFRC522 je bezkontaktná RFID čítačka pracujúca na frekvencii 13,56 MHz, je určená na komunikáciu s RFID tagmi štandardu ISO/IEC 14443A. Obsahuje integrovaný vysielač a prijímač, ktorý zabezpečuje komunikáciu s kartami. Ovládanie čítačky prebieha prostredníctvom sústavy riadiacich registrov, ktoré riadia jej činnosť a spracovanie dát. | |||
Napríklad: | |||
*CommandReg (0x01) určuje, aký príkaz má čítačka aktuálne vykonať (napr. soft reset, čítanie, vysielanie...) | |||
*FIFODataReg (0x09) slúži na zápis a čítanie dát, ktoré sa posielajú medzi čítačkou a kartou | |||
*TxControlReg (0x14) umožňuje zapnúť alebo vypnúť anténu čítačky | |||
*BitFramingReg (0x0D) nastavuje počet bitov v poslednom odosielanom bajte a riadi spustenie prenosu | |||
*ErrorReg (0x06) obsahuje príznaky chýb počas komunikácie – napr. chyba parity, kolízia, chyba časovača alebo buffer overflow | |||
Každá operácia, ako napríklad detekcia karty, získanie UID alebo výber konkrétneho tagu, si vyžaduje presnú sekvenciu zápisov do registrov, často vrátane nastavenia prenosových parametrov a čakacích podmienok. Na komunikáciu s RFID čítačkou som použil SPI rozhranie. Najdôležitejšia vec bola preštudovanie datasheetu, spísanie si všetkých registrov a funkcií a ďalej aj normy pre posielanie informácií karte pomocou čítačky. Pre správnu funkciu zariadenia bolo potrebné vhodne inicializovať RC522, vysielať "budiace" signály a sledovať či sa karta ozve. Po tom ako sa karta ozvala si od nej treba vypýtať jej UID a ďalej už len skontrolovať, či sa zhoduje s nami nahratým UID pre "otvorenie dverí" (zapnutie zelenej LED diódy). | |||
[[Obrázok:RC522.png|400px|thumb|center|RFID Čítačka RC522]] | |||
[[Súbor: | Popis zapojenia: | ||
RC522 (slave) je pomocou SPI rozhrania pripojený na Arduino UNO (slave) a ďalej sú k Arduino UNO pripojené 2 LED diódy slúžiace na indikovanie prítomnosti správnej prípadne nesprávnej karty. | |||
*SS -> PB2 (slave select) | |||
*MOSI -> PB3 (master to slave) | |||
*MISO -> PB4 (slave to master) | |||
*SCK -> PB5 (hodinové impulzy) | |||
*RST -> PD7 (voľný pin na reset) | |||
*GND -> GND | |||
*Vcc -> 3,3V | |||
*LED (zelená) -> PD5 | |||
*LED (červená) -> PD6 | |||
[[Súbor:SchemaBeko.png|600px|thumb|center|Schéma zapojenia.]] | |||
=== Algoritmus a program === | === Algoritmus a program === | ||
Algoritmus programu využíva | Algoritmus programu využíva knižnicu uart, ktorú sme vytvárali na niektorom z cvičení tento semester. Okrem toho som vytvoril funkcie: | ||
Výpis kódu je nižšie... | |||
*void USART_send_byte_hex(uint8_t byte) (konverzia bajtu na HEX a poslanie cez uart) | |||
: | |||
*void SPI_init() (inicializácia SPI rozhrania) | |||
*uint8_t SPI_transfer(uint8_t data) (prenos dát cez SPI) | |||
: | |||
*void RC522_write(uint8_t reg, uint8_t value) (zapísanie dát do RC522) | |||
*uint8_t RC522_read(uint8_t reg) (prečítanie dát z RC522) | |||
*bool RC522_command(uint8_t command) (zápis konkrétnej úlohy do command registra RC522) | |||
*void RC522_reset() (pre soft reset RC522) | |||
*void RC522_init() (inicializácia RC522) | |||
: | |||
*bool requestTag(uint8_t *tagType) (na pýtanie sa či, a aká karta je v blízkosti čítačky) | |||
*bool detect_card() | |||
*bool antiCollision(uint8_t *uid) | |||
*void wait_for_card_removal() | |||
V programe nie sú priamo použité všetky funkcie, ktoré som vytváral. Výpis kódu je nižšie... | |||
Riadok 41: | Riadok 78: | ||
#include <avr/io.h> | #include <avr/io.h> | ||
#define F_CPU 16000000UL | |||
#define BAUD 9600 | |||
#include <avr/io.h> | |||
#include <util/delay.h> | |||
#include "uart.h" | |||
#define bool uint8_t | |||
#define true 1 | |||
#define false 0 | |||
// SPI piny pre ATmega328P | |||
#define SS_PIN PB2 // slave select | |||
#define MOSI_PIN PB3 // master to slave | |||
#define MISO_PIN PB4 // slave to master | |||
#define SCK_PIN PB5 // hodiny | |||
#define RST_PIN PD7 // voľný pin na RESET | |||
// ----------------------------- | |||
// USART (UART) FUNKCIE | |||
// ----------------------------- | |||
// Konverzia bajtu na HEX a poslanie cez UART | |||
void USART_send_byte_hex(uint8_t byte) | |||
{ | |||
const char hexChars[] = "0123456789ABCDEF"; | |||
uart_putc(hexChars[(byte >> 4) & 0x0F]); | |||
uart_putc(hexChars[byte & 0x0F]); | |||
} | |||
// ----------------------------- | |||
// SPI FUNKCIE | |||
// ----------------------------- | |||
void SPI_init() | |||
{ | |||
DDRB |= (1 << SS_PIN) | (1 << MOSI_PIN) | (1 << SCK_PIN); | |||
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // SPI enable, Master, nastvenie frekvencie Fosc/16 | |||
PORTB |= (1 << SS_PIN); // SS HIGH = neaktívny | |||
} | |||
uint8_t SPI_transfer(uint8_t data) | |||
{ | |||
SPDR = data; | |||
while (!(SPSR & (1 << SPIF))); //SPI interrupt flag (čakám kým sa odvysiela) | |||
return SPDR; // vráti obsah SPDR | |||
} | |||
// ----------------------------- | |||
// RC522 NÍZKOÚROVŇOVÉ FUNKCIE | |||
// ----------------------------- | |||
void RC522_write(uint8_t reg, uint8_t value) | |||
{ | |||
PORTB &= ~(1 << SS_PIN); // poviem mu, že chcem komunikovať (nastavím 0) | |||
SPI_transfer((reg << 1) & 0x7E); | |||
// posuniem adresu na správne miesto registra a nastavím prvý aj | |||
// posledný bit na 0, MSB určuje read/write (1/0) a LSB musí byť 0 | |||
SPI_transfer(value); // odoslanie dát | |||
PORTB |= (1 << SS_PIN); // ukončím komunikáciu (zapíšem 1) | |||
_delay_ms(1); // potrebný delay, lebo RFID pracuje pomaly | |||
} | |||
uint8_t RC522_read(uint8_t reg) | |||
{ | |||
PORTB &= ~(1 << SS_PIN); // poviem mu, že chcem komunikovať (nastavím 0) | |||
SPI_transfer(((reg << 1) & 0x7E) | 0x80); // posuniem adresu na správne miesto registra a nastavím prvý aj | |||
// posledný bit na 0, MSB určuje read/write (1/0) a LSB musí byť 0 | |||
// nakoniec pomocou "| 0x80" nastavím MSB na 1 (read) | |||
uint8_t val = SPI_transfer(0x00); // dummy write - prijímam dáta | |||
PORTB |= (1 << SS_PIN); // ukončím komunikáciu | |||
_delay_ms(1); // potrebný delay, lebo RFID pracuje pomaly | |||
return val; | |||
} | |||
bool RC522_command(uint8_t command) | |||
{ | |||
RC522_write(0x01, command); // CommandReg = spustenie príkazu | |||
// Počkáme, kým sa dokončí príkaz (max 25 ms timeout) | |||
uint8_t i = 0; | |||
do | |||
{ | |||
_delay_ms(1); | |||
i++; | |||
if (i > 25) return false; // Timeout | |||
} while (RC522_read(0x04) & 0x01); // ComIrqReg, bit 0 = command stále beží | |||
return true; | |||
} | |||
///// DEFINOVANIE COMMANDOV DO COMMAND_REG ///// | |||
#define RFID_CMD_IDLE 0x00 // nečinný režim | |||
#define RFID_CMD_MEM 0x01 // presun pamäte | |||
#define RFID_CMD_RANDOM_ID 0x02 // vygeneruj náhodné ID | |||
#define RFID_CMD_CALC_CRC 0x03 // spočítaj CRC | |||
#define RFID_CMD_TRANSMIT 0x04 // len vysielaj | |||
#define RFID_CMD_NO_CHANGE 0x07 // nezmeň príkaz | |||
#define RFID_CMD_RECEIVE 0x08 // len prijímaj | |||
#define RFID_CMD_TRANSCEIVE 0x0C // vysielaj aj prijímaj | |||
#define RFID_CMD_AUTHENTICATE 0x0E // autentifikácia | |||
#define RFID_CMD_SOFT_RESET 0x0F // soft reset čipu | |||
void RC522_reset() | |||
{ | |||
RC522_write(0x01, RFID_CMD_SOFT_RESET); // CommandReg = SoftReset | |||
_delay_ms(50); | |||
} | |||
// ----- REGISTRE PODĽA DATASHEETU ----- | |||
#define CommandReg 0x01 | |||
#define CommIEnReg 0x02 | |||
#define CommIrqReg 0x04 | |||
#define ErrorReg 0x06 | |||
#define Status1Reg 0x07 | |||
#define FIFODataReg 0x09 | |||
#define FIFOLevelReg 0x0A | |||
#define ControlReg 0x0C | |||
#define BitFramingReg 0x0D | |||
#define ModeReg 0x11 | |||
#define TxModeReg 0x12 | |||
#define RxModeReg 0x13 | |||
#define TxControlReg 0x14 | |||
#define TxASKReg 0x15 | |||
#define TModeReg 0x2A | |||
#define TPrescalerReg 0x2B | |||
#define TReloadRegL 0x2C | |||
#define TReloadRegH 0x2D | |||
// Inicializácia čipu MFRC522 – nastaví registre potrebné pre komunikáciu a zapne anténu | |||
void RC522_init() | |||
{ | |||
RC522_reset(); | |||
RC522_write(TModeReg, 0x8D); | |||
RC522_write(TPrescalerReg, 0x3E); | |||
RC522_write(TReloadRegL, 30); | |||
RC522_write(TReloadRegH, 0); | |||
RC522_write(TxASKReg, 0x40); | |||
RC522_write(ModeReg, 0x3D); | |||
RC522_write(TxControlReg, 0x83); // zapni anténu | |||
} | |||
// ----------------------------- | |||
// RC522 VYŠŠIE FUNKCIE | |||
// ----------------------------- | |||
bool requestTag(uint8_t *tagType) | |||
{ | |||
RC522_write(CommandReg, RFID_CMD_IDLE); | |||
RC522_write(FIFOLevelReg, 0x80); // Flush FIFO | |||
RC522_write(BitFramingReg, 0x07); // Nastav počet bitov na 7 (7 bits = 1 byte - REQA) | |||
RC522_write(FIFODataReg, 0x26); // REQA príkaz | |||
RC522_write(CommandReg, RFID_CMD_TRANSCEIVE); | |||
RC522_write(BitFramingReg, 0x87); // StartSend = 1, nastav počet bitov na 7 | |||
uint8_t i = 0; | |||
while (!(RC522_read(CommIrqReg) & 0x30)) | |||
{ | |||
_delay_ms(1); | |||
if (++i > 25) return false; | |||
} | |||
if ((RC522_read(ErrorReg) & 0x1B) == 0) | |||
{ | |||
uint8_t dlzka = RC522_read(FIFOLevelReg); | |||
if (dlzka >= 2) | |||
{ | |||
tagType[0] = RC522_read(FIFODataReg); | |||
tagType[1] = RC522_read(FIFODataReg); | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
bool detect_card() | |||
{ | |||
uint8_t tagType[2]; | |||
return requestTag(tagType); | |||
} | |||
bool antiCollision(uint8_t *uid) | |||
{ | { | ||
RC522_write(CommandReg, RFID_CMD_IDLE); | |||
RC522_write(FIFOLevelReg, 0x80); // Flush FIFO | |||
RC522_write(BitFramingReg, 0x00); // Počet bitov = 0 | |||
RC522_write(FIFODataReg, 0x93); // Anti-collision command | |||
RC522_write(FIFODataReg, 0x20); // NVB = 0x20 (2 bajty) | |||
RC522_write(CommandReg, RFID_CMD_TRANSCEIVE); | |||
RC522_write(BitFramingReg, 0x80); // StartSend = 1 | |||
uint8_t i = 0; | |||
while (!(RC522_read(CommIrqReg) & 0x30)) | |||
{ | |||
_delay_ms(1); | |||
if (++i > 25) return false; | |||
} | |||
if (RC522_read(ErrorReg) & 0x1B) return false; | |||
uint8_t dlzka = RC522_read(FIFOLevelReg); | |||
if (dlzka < 5) return false; | |||
for (uint8_t j = 0; j < 5; j++) | |||
{ | |||
uid[j] = RC522_read(FIFODataReg); | |||
} | |||
return true; | |||
} | |||
/ | |||
void wait_for_card_removal() | |||
{ | |||
while (detect_card()) | |||
{ | |||
_delay_ms(100); | |||
} | |||
} | |||
int main(void) | |||
{ | |||
uart_init(); | |||
SPI_init(); | |||
RC522_init(); | |||
// inicializácia LED: červená na PD6, zelená na PD7 | |||
DDRD |= (1 << PD6) | (1 << PD5); | |||
PORTD &= ~((1 << PD6) | (1 << PD5)); // LEDky vypnuté | |||
int token = 0; | |||
uint8_t keycard[5] = {0x91, 0x27, 0xE1, 0x2B, 0x7C}; | |||
uart_puts("Inicializujem MFRC522...\r\n"); | |||
_delay_ms(3000); // Delay aby to vyzeralo že to niečo robí (stabilizácia) | |||
uint8_t uid[5]; | |||
while (1) | |||
{ | |||
uart_puts("Priloz kartu \r\n"); | |||
while (!detect_card()); | |||
if(detect_card()); // debugovanie: niečo nefunguje ako má ale s týmto už program plní svoju funkciu | |||
if (detect_card()) | |||
{ | |||
if (antiCollision(uid)) | |||
{ | |||
token = 0; | |||
for (uint8_t i = 0; i < 5; i++) | |||
{ | |||
if (uid[i] == keycard[i]) | |||
token++; | |||
} | |||
if (token != 5) | |||
{ | |||
//zapni cervenu LED | |||
PORTD |= (1 << PD6); | |||
uart_puts("Nespravna karta, tu je jej UID: "); // 91 27 E1 2B 7C | |||
for (uint8_t i = 0; i < 5; i++) { | |||
USART_send_byte_hex(uid[i]); | |||
uart_puts(" "); | |||
} | |||
uart_puts("\r\nNa otvorenie dveri treba: UID: "); | |||
for (uint8_t i = 0; i < 5; i++) { | |||
USART_send_byte_hex(keycard[i]); | |||
uart_puts(" "); | |||
} | |||
//pockaj 3sekundy a vypni cervenu led | |||
_delay_ms(3000); | |||
PORTD &= ~(1 << PD6); | |||
} | |||
else | |||
{ | |||
uart_puts("\r\nSpravna karta, vitajte!"); | |||
//zapni zelenu LED na 3sekundy a potom ju vypni | |||
PORTD |= (1 << PD5); | |||
_delay_ms(3000); | |||
PORTD &= ~(1 << PD5); | |||
} | |||
uart_puts("\r\n\n"); | |||
} | |||
else uart_puts("Chyba v anticollision\r\n"); | |||
} | |||
else uart_puts("Ziadna karta\r\n"); | |||
} | |||
return 0; | |||
} | } | ||
</syntaxhighlight ></tab> | </syntaxhighlight ></tab> | ||
<tab name=" | <tab name="uart.h"><syntaxhighlight lang="c++" style="background: LightYellow;"> | ||
#ifndef UART_H_ | |||
#define UART_H_ | |||
#define BAUD 9600 | |||
#define F_CPU 16000000UL | |||
void uart_init( void ); | |||
void uart_putc( char c ); | |||
void uart_puts( const char *s ); | |||
char uart_getc( void ); | |||
#endif /* UART_H_ */ | |||
</syntaxhighlight ></tab> | |||
<tab name="uart.c"><syntaxhighlight lang="c++" style="background: LightYellow;"> | |||
#include <avr/io.h> | #include <avr/io.h> | ||
//#include <util/setbaud.h> | |||
#define BAUD 9600 | |||
#define F_CPU 16000000UL | |||
void uart_init( void ) | |||
{ | |||
UBRR0 =103; | |||
/* | |||
#if USE_2X | |||
UCSR0A |= _BV(U2X0); | |||
#else | |||
UCSR0A &= ~(_BV(U2X0)); | |||
#endif*/ | |||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */ | |||
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */ | |||
} | |||
void uart_putc(char c) | |||
{ | |||
if (c == '\n') | |||
{ | |||
uart_putc('\r'); | |||
} | |||
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ | |||
UDR0 = c; | |||
} | |||
void uart_puts(const char *s) | |||
{ | |||
/* toto je vasa uloha */ | |||
while(*s!='\0'){ | |||
uart_putc(*s); | |||
s++; | |||
} | |||
} | |||
char uart_getc(void) { | |||
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ | |||
return UDR0; | |||
} | |||
</syntaxhighlight ></tab> | </syntaxhighlight ></tab> | ||
</tabs> | </tabs> | ||
Riadok 65: | Riadok 440: | ||
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'': | Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'': | ||
Zdrojový kód: [[Médiá: | Zdrojový kód: [[Médiá:projektOliverBeko.zip|Beko_Oliver_MFRC522.zip]] | ||
=== Overenie === | === Overenie === | ||
Funkciu zariadenia som overil tak, že som zobral dve karty s rôznymi UID, ktoré som potom prikladal na RFID čítačku a sledoval terminál na monitore a LED diódy signalizujúce priloženie správnej alebo nesprávnej karty. | |||
[[Súbor: | [[Súbor:ZapojenieBeko.jpg|400px|thumb|center|Aplikácia.]] | ||
'''Video:''' | '''Video:''' | ||
<center><youtube> | <center><youtube>dU1uTPvfh3k</youtube></center> | ||
Kľúčové slová 'Category', ktoré sú na konci stránky | Kľúčové slová 'Category', ktoré sú na konci stránky som nemenil. :) | ||
[[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] |
Aktuálna revízia z 20:50, 12. máj 2025
Záverečný projekt predmetu MIPS / LS2025 - Meno Priezvisko
Zadanie
Toto je čítačka s ktorou pracujem: https://techfun.sk/produkt/citacka-rfid-rc522-klucenka-a-karta/
Čítačka RFID kariet RC522 - spojazdniť, vedieť načítať kartu a jej ID, vytvoriť program ktorý rozozná konkrétnu kartu a rozsvieti LED.

Literatúra:
Analýza a opis riešenia
Modul MFRC522 je bezkontaktná RFID čítačka pracujúca na frekvencii 13,56 MHz, je určená na komunikáciu s RFID tagmi štandardu ISO/IEC 14443A. Obsahuje integrovaný vysielač a prijímač, ktorý zabezpečuje komunikáciu s kartami. Ovládanie čítačky prebieha prostredníctvom sústavy riadiacich registrov, ktoré riadia jej činnosť a spracovanie dát. Napríklad:
- CommandReg (0x01) určuje, aký príkaz má čítačka aktuálne vykonať (napr. soft reset, čítanie, vysielanie...)
- FIFODataReg (0x09) slúži na zápis a čítanie dát, ktoré sa posielajú medzi čítačkou a kartou
- TxControlReg (0x14) umožňuje zapnúť alebo vypnúť anténu čítačky
- BitFramingReg (0x0D) nastavuje počet bitov v poslednom odosielanom bajte a riadi spustenie prenosu
- ErrorReg (0x06) obsahuje príznaky chýb počas komunikácie – napr. chyba parity, kolízia, chyba časovača alebo buffer overflow
Každá operácia, ako napríklad detekcia karty, získanie UID alebo výber konkrétneho tagu, si vyžaduje presnú sekvenciu zápisov do registrov, často vrátane nastavenia prenosových parametrov a čakacích podmienok. Na komunikáciu s RFID čítačkou som použil SPI rozhranie. Najdôležitejšia vec bola preštudovanie datasheetu, spísanie si všetkých registrov a funkcií a ďalej aj normy pre posielanie informácií karte pomocou čítačky. Pre správnu funkciu zariadenia bolo potrebné vhodne inicializovať RC522, vysielať "budiace" signály a sledovať či sa karta ozve. Po tom ako sa karta ozvala si od nej treba vypýtať jej UID a ďalej už len skontrolovať, či sa zhoduje s nami nahratým UID pre "otvorenie dverí" (zapnutie zelenej LED diódy).

Popis zapojenia: RC522 (slave) je pomocou SPI rozhrania pripojený na Arduino UNO (slave) a ďalej sú k Arduino UNO pripojené 2 LED diódy slúžiace na indikovanie prítomnosti správnej prípadne nesprávnej karty.
- SS -> PB2 (slave select)
- MOSI -> PB3 (master to slave)
- MISO -> PB4 (slave to master)
- SCK -> PB5 (hodinové impulzy)
- RST -> PD7 (voľný pin na reset)
- GND -> GND
- Vcc -> 3,3V
- LED (zelená) -> PD5
- LED (červená) -> PD6

Algoritmus a program
Algoritmus programu využíva knižnicu uart, ktorú sme vytvárali na niektorom z cvičení tento semester. Okrem toho som vytvoril funkcie:
- void USART_send_byte_hex(uint8_t byte) (konverzia bajtu na HEX a poslanie cez uart)
- void SPI_init() (inicializácia SPI rozhrania)
- uint8_t SPI_transfer(uint8_t data) (prenos dát cez SPI)
- void RC522_write(uint8_t reg, uint8_t value) (zapísanie dát do RC522)
- uint8_t RC522_read(uint8_t reg) (prečítanie dát z RC522)
- bool RC522_command(uint8_t command) (zápis konkrétnej úlohy do command registra RC522)
- void RC522_reset() (pre soft reset RC522)
- void RC522_init() (inicializácia RC522)
- bool requestTag(uint8_t *tagType) (na pýtanie sa či, a aká karta je v blízkosti čítačky)
- bool detect_card()
- bool antiCollision(uint8_t *uid)
- void wait_for_card_removal()
V programe nie sú priamo použité všetky funkcie, ktoré som vytváral. Výpis kódu je nižšie...
#include <avr/io.h>
#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
#define bool uint8_t
#define true 1
#define false 0
// SPI piny pre ATmega328P
#define SS_PIN PB2 // slave select
#define MOSI_PIN PB3 // master to slave
#define MISO_PIN PB4 // slave to master
#define SCK_PIN PB5 // hodiny
#define RST_PIN PD7 // voľný pin na RESET
// -----------------------------
// USART (UART) FUNKCIE
// -----------------------------
// Konverzia bajtu na HEX a poslanie cez UART
void USART_send_byte_hex(uint8_t byte)
{
const char hexChars[] = "0123456789ABCDEF";
uart_putc(hexChars[(byte >> 4) & 0x0F]);
uart_putc(hexChars[byte & 0x0F]);
}
// -----------------------------
// SPI FUNKCIE
// -----------------------------
void SPI_init()
{
DDRB |= (1 << SS_PIN) | (1 << MOSI_PIN) | (1 << SCK_PIN);
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // SPI enable, Master, nastvenie frekvencie Fosc/16
PORTB |= (1 << SS_PIN); // SS HIGH = neaktívny
}
uint8_t SPI_transfer(uint8_t data)
{
SPDR = data;
while (!(SPSR & (1 << SPIF))); //SPI interrupt flag (čakám kým sa odvysiela)
return SPDR; // vráti obsah SPDR
}
// -----------------------------
// RC522 NÍZKOÚROVŇOVÉ FUNKCIE
// -----------------------------
void RC522_write(uint8_t reg, uint8_t value)
{
PORTB &= ~(1 << SS_PIN); // poviem mu, že chcem komunikovať (nastavím 0)
SPI_transfer((reg << 1) & 0x7E);
// posuniem adresu na správne miesto registra a nastavím prvý aj
// posledný bit na 0, MSB určuje read/write (1/0) a LSB musí byť 0
SPI_transfer(value); // odoslanie dát
PORTB |= (1 << SS_PIN); // ukončím komunikáciu (zapíšem 1)
_delay_ms(1); // potrebný delay, lebo RFID pracuje pomaly
}
uint8_t RC522_read(uint8_t reg)
{
PORTB &= ~(1 << SS_PIN); // poviem mu, že chcem komunikovať (nastavím 0)
SPI_transfer(((reg << 1) & 0x7E) | 0x80); // posuniem adresu na správne miesto registra a nastavím prvý aj
// posledný bit na 0, MSB určuje read/write (1/0) a LSB musí byť 0
// nakoniec pomocou "| 0x80" nastavím MSB na 1 (read)
uint8_t val = SPI_transfer(0x00); // dummy write - prijímam dáta
PORTB |= (1 << SS_PIN); // ukončím komunikáciu
_delay_ms(1); // potrebný delay, lebo RFID pracuje pomaly
return val;
}
bool RC522_command(uint8_t command)
{
RC522_write(0x01, command); // CommandReg = spustenie príkazu
// Počkáme, kým sa dokončí príkaz (max 25 ms timeout)
uint8_t i = 0;
do
{
_delay_ms(1);
i++;
if (i > 25) return false; // Timeout
} while (RC522_read(0x04) & 0x01); // ComIrqReg, bit 0 = command stále beží
return true;
}
///// DEFINOVANIE COMMANDOV DO COMMAND_REG /////
#define RFID_CMD_IDLE 0x00 // nečinný režim
#define RFID_CMD_MEM 0x01 // presun pamäte
#define RFID_CMD_RANDOM_ID 0x02 // vygeneruj náhodné ID
#define RFID_CMD_CALC_CRC 0x03 // spočítaj CRC
#define RFID_CMD_TRANSMIT 0x04 // len vysielaj
#define RFID_CMD_NO_CHANGE 0x07 // nezmeň príkaz
#define RFID_CMD_RECEIVE 0x08 // len prijímaj
#define RFID_CMD_TRANSCEIVE 0x0C // vysielaj aj prijímaj
#define RFID_CMD_AUTHENTICATE 0x0E // autentifikácia
#define RFID_CMD_SOFT_RESET 0x0F // soft reset čipu
void RC522_reset()
{
RC522_write(0x01, RFID_CMD_SOFT_RESET); // CommandReg = SoftReset
_delay_ms(50);
}
// ----- REGISTRE PODĽA DATASHEETU -----
#define CommandReg 0x01
#define CommIEnReg 0x02
#define CommIrqReg 0x04
#define ErrorReg 0x06
#define Status1Reg 0x07
#define FIFODataReg 0x09
#define FIFOLevelReg 0x0A
#define ControlReg 0x0C
#define BitFramingReg 0x0D
#define ModeReg 0x11
#define TxModeReg 0x12
#define RxModeReg 0x13
#define TxControlReg 0x14
#define TxASKReg 0x15
#define TModeReg 0x2A
#define TPrescalerReg 0x2B
#define TReloadRegL 0x2C
#define TReloadRegH 0x2D
// Inicializácia čipu MFRC522 – nastaví registre potrebné pre komunikáciu a zapne anténu
void RC522_init()
{
RC522_reset();
RC522_write(TModeReg, 0x8D);
RC522_write(TPrescalerReg, 0x3E);
RC522_write(TReloadRegL, 30);
RC522_write(TReloadRegH, 0);
RC522_write(TxASKReg, 0x40);
RC522_write(ModeReg, 0x3D);
RC522_write(TxControlReg, 0x83); // zapni anténu
}
// -----------------------------
// RC522 VYŠŠIE FUNKCIE
// -----------------------------
bool requestTag(uint8_t *tagType)
{
RC522_write(CommandReg, RFID_CMD_IDLE);
RC522_write(FIFOLevelReg, 0x80); // Flush FIFO
RC522_write(BitFramingReg, 0x07); // Nastav počet bitov na 7 (7 bits = 1 byte - REQA)
RC522_write(FIFODataReg, 0x26); // REQA príkaz
RC522_write(CommandReg, RFID_CMD_TRANSCEIVE);
RC522_write(BitFramingReg, 0x87); // StartSend = 1, nastav počet bitov na 7
uint8_t i = 0;
while (!(RC522_read(CommIrqReg) & 0x30))
{
_delay_ms(1);
if (++i > 25) return false;
}
if ((RC522_read(ErrorReg) & 0x1B) == 0)
{
uint8_t dlzka = RC522_read(FIFOLevelReg);
if (dlzka >= 2)
{
tagType[0] = RC522_read(FIFODataReg);
tagType[1] = RC522_read(FIFODataReg);
return true;
}
}
return false;
}
bool detect_card()
{
uint8_t tagType[2];
return requestTag(tagType);
}
bool antiCollision(uint8_t *uid)
{
RC522_write(CommandReg, RFID_CMD_IDLE);
RC522_write(FIFOLevelReg, 0x80); // Flush FIFO
RC522_write(BitFramingReg, 0x00); // Počet bitov = 0
RC522_write(FIFODataReg, 0x93); // Anti-collision command
RC522_write(FIFODataReg, 0x20); // NVB = 0x20 (2 bajty)
RC522_write(CommandReg, RFID_CMD_TRANSCEIVE);
RC522_write(BitFramingReg, 0x80); // StartSend = 1
uint8_t i = 0;
while (!(RC522_read(CommIrqReg) & 0x30))
{
_delay_ms(1);
if (++i > 25) return false;
}
if (RC522_read(ErrorReg) & 0x1B) return false;
uint8_t dlzka = RC522_read(FIFOLevelReg);
if (dlzka < 5) return false;
for (uint8_t j = 0; j < 5; j++)
{
uid[j] = RC522_read(FIFODataReg);
}
return true;
}
void wait_for_card_removal()
{
while (detect_card())
{
_delay_ms(100);
}
}
int main(void)
{
uart_init();
SPI_init();
RC522_init();
// inicializácia LED: červená na PD6, zelená na PD7
DDRD |= (1 << PD6) | (1 << PD5);
PORTD &= ~((1 << PD6) | (1 << PD5)); // LEDky vypnuté
int token = 0;
uint8_t keycard[5] = {0x91, 0x27, 0xE1, 0x2B, 0x7C};
uart_puts("Inicializujem MFRC522...\r\n");
_delay_ms(3000); // Delay aby to vyzeralo že to niečo robí (stabilizácia)
uint8_t uid[5];
while (1)
{
uart_puts("Priloz kartu \r\n");
while (!detect_card());
if(detect_card()); // debugovanie: niečo nefunguje ako má ale s týmto už program plní svoju funkciu
if (detect_card())
{
if (antiCollision(uid))
{
token = 0;
for (uint8_t i = 0; i < 5; i++)
{
if (uid[i] == keycard[i])
token++;
}
if (token != 5)
{
//zapni cervenu LED
PORTD |= (1 << PD6);
uart_puts("Nespravna karta, tu je jej UID: "); // 91 27 E1 2B 7C
for (uint8_t i = 0; i < 5; i++) {
USART_send_byte_hex(uid[i]);
uart_puts(" ");
}
uart_puts("\r\nNa otvorenie dveri treba: UID: ");
for (uint8_t i = 0; i < 5; i++) {
USART_send_byte_hex(keycard[i]);
uart_puts(" ");
}
//pockaj 3sekundy a vypni cervenu led
_delay_ms(3000);
PORTD &= ~(1 << PD6);
}
else
{
uart_puts("\r\nSpravna karta, vitajte!");
//zapni zelenu LED na 3sekundy a potom ju vypni
PORTD |= (1 << PD5);
_delay_ms(3000);
PORTD &= ~(1 << PD5);
}
uart_puts("\r\n\n");
}
else uart_puts("Chyba v anticollision\r\n");
}
else uart_puts("Ziadna karta\r\n");
}
return 0;
}
#ifndef UART_H_
#define UART_H_
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void );
void uart_putc( char c );
void uart_puts( const char *s );
char uart_getc( void );
#endif /* UART_H_ */
#include <avr/io.h>
//#include <util/setbaud.h>
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void )
{
UBRR0 =103;
/*
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= ~(_BV(U2X0));
#endif*/
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
}
void uart_putc(char c)
{
if (c == '\n')
{
uart_putc('\r');
}
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
}
void uart_puts(const char *s)
{
/* toto je vasa uloha */
while(*s!='\0'){
uart_putc(*s);
s++;
}
}
char uart_getc(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
return UDR0;
}
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:
Zdrojový kód: Beko_Oliver_MFRC522.zip
Overenie
Funkciu zariadenia som overil tak, že som zobral dve karty s rôznymi UID, ktoré som potom prikladal na RFID čítačku a sledoval terminál na monitore a LED diódy signalizujúce priloženie správnej alebo nesprávnej karty.

Video:
Kľúčové slová 'Category', ktoré sú na konci stránky som nemenil. :)