Operácie

Čítačka RFID kariet RC522: Rozdiel medzi revíziami

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
Riadok 30: Riadok 30:
*ErrorReg (0x06) obsahuje príznaky chýb počas komunikácie – napr. chyba parity, kolízia, chyba časovača alebo buffer overflow
*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 (REQA), 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. Okrem vyššie uvedených registrov sa často využíva aj BitFramingReg, ktorý nastavuje počet bitov v poslednom bajte a riadi spustenie prenosu, ďalej ErrorReg, ktorý obsahuje príznaky chýb (napr. kolízia alebo timeout), a ComIrqReg, ktorý indikuje, či bol príkaz dokončený alebo aká udalosť práve nastala.
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.


[[Obrázok:RC522.png|400px|thumb|center|RFID Čítačka RC522]]
[[Obrázok:RC522.png|400px|thumb|center|RFID Čítačka RC522]]

Verzia z 20:48, 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.

Vývojová doska Arduino UNO.

Literatúra:


Analýza a opis riešenia

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). 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.

RFID Čítačka RC522

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


Schéma zapojenia.


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.

Aplikácia.

Video:



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