이번 글에서는 RFID 기술과 MCU(마이크로컨트롤러)에서 RFID를 다루는 방법을 정리해 봤다.
특히, MFRC522 모듈을 이용해 RFID 태그를 읽고 쓰는 실습을 중심으로 작성했다.
RFID(Radio-Frequency IDentification)는 주파수를 이용해 ID를 식별하는 기술이다.
RFID 시스템은 크게 리더(Reader)와 태그(Tag)로 구성된다.
태그를 리더에 딱 맞춰서 붙일 필요는 없다. 비스듬히 놓여도 인식이 되지만, 너무 각도가 심하면 UID를 못 읽는 경우가 있다.
태그에는 UID(Unique ID)와 사용자 데이터를 저장할 수 있는 메모리가 있다.
MFRC522 기준 메모리 구조는 아래와 같다:
사용자는 나머지 블록에 데이터를 저장하거나 읽을 수 있다. 데이터 읽기/쓰기 전에는 반드시 인증 과정을 거쳐야 한다.
MFRC522의 메모리 정리:
| Sector | Block | 인증 필요 | 설명 |
|---|---|---|---|
| 0 | 0 | X | UID 저장 블록, 읽기만 가능 |
| 0 | 1~3 | O | Key A/B 필요, 보안 관련 데이터 |
| 1~15 | 0~3 | O | Key A/B 필요, 사용자 지정 데이터 |
RFID 리더 모듈은 많은 데이터를 빠르게 주고받아야 하기 때문에 SPI(Serial Peripheral Interface) 통신을 사용한다.
| 핀 | 역할 |
|---|---|
| MOSI | MCU → 모듈 데이터 전송 |
| MISO | 모듈 → MCU 데이터 전송 |
| SCK | 클록 신호, 데이터 타이밍 맞춤 |
| SS | 통신할 슬레이브 선택 |
그리고 MFRC522에는 RST 핀이 있어 리셋과 통신 초기화를 담당한다.
MFRC522 모듈과 Arduino Uno 연결 예시:
참고: RST와 SS 외에는 모듈 내부적으로 핀이 이미 정해져 있으므로 변경할 필요가 없다. Arduino Uno가 아니라면 Arduino IDE에서 지정된 핀을 확인해야 한다.
여기에서 언급되는 클래스는 Arduino IDE에 있는 MFRC522.h에 정의된 클래스를 말한다.
#include <MFRC522.h>
const int RST_PIN = 9;
const int SS_PIN = 10;
MFRC522 rc522(SS_PIN, RST_PIN);
위에서 언급한 대로, 사용자가 직접 변경할 수 있는 핀은 SS, RST다 핀이다. 그러니 클래스에서 설정해 줘야 한다.
if (!rc522.PICC_IsNewCardPresent()) return;
if (!rc522.PICC_ReadCardSerial()) return;
각각 새로운 카드가 존재하는지 여부, UID가 있는지를 확인하는 함수다. 이 코드가 있어야 MFRC522를 인식할 수 있다.
status = rc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, index, &key, &(rc522.uid));
if (status != MFRC522::STATUS_OK)
{
Serial.print("Authentication Failed: ");
Serial.println(rc522.GetStatusCodeName(status));
return;
}
write/read 함수를 쓰려면 인증이 필수적이다. index 위치의 key를 지정해주자.
참고로 따로 key를 설정하지 않았으면, key 값은 0xFF다.
status = rc522.MIFARE_Write(index, (byte*)&data, length);
if (status != MFRC522::STATUS_OK)
{
Serial.print("Write Failed: ");
Serial.println(rc522.GetStatusCodeName(status));
return;
}
index 위치에서 length만큼 byte 단위로 작성한다. 아두이노 우노의 경우, 한 Block이 16Byte니 16byte로 설정했다.
byte buffer[18];
byte length = 18;
status = rc522.MIFARE_Read(index, buffer, &length);
if (status != MFRC522::STATUS_OK)
{
Serial.print("Read Failed: ");
Serial.println(rc522.GetStatusCodeName(status));
}
index 블록에서 length 만큼의 데이터를 읽어 buffer에 저장한다.
일반적으로 buffer는 체크섬/CRC 때문에 length보다 2~3Byte 더 크게 잡기에 18로 length를 지정했다.