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 32: Riadok 32:
*SCK -> PB5 (hodinové impulzy)
*SCK -> PB5 (hodinové impulzy)
*RST -> PD7 (voľný pin na reset)
*RST -> PD7 (voľný pin na reset)
*GND -> GND
*Vcc -> 3,3V
*LED (zelená) -> PD5
*LED (zelená) -> PD5
*LED (červená) -> PD6
*LED (červená) -> PD6
Riadok 61: Riadok 63:




Výpis kódu je nižšie...
V programe nie sú priamo použité všetky funkcie, ktoré som vytváral. Výpis kódu je nižšie...




Riadok 444: Riadok 446:




Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.  
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 07:55, 5. 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).

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