Čítačka RFID kariet RC522: Rozdiel medzi revíziami
Zo stránky SensorWiki
Bez shrnutí editace |
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 | 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.

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

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