#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Preferences.h>
// ===== ПИНЫ =====
#define SS_PIN 5
#define RST_PIN 26
#define BTN_PIN 27
#define LCD_ADDR 0x27 // Если не работает, попробуйте 0x3F
// ===== ОБЪЕКТЫ =====
MFRC522 mfrc522(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(LCD_ADDR, 16, 2);
Preferences prefs;
const byte AUTH_UID[4] = {0xDE, 0xAD, 0xBE, 0xEF};
const int MAX_LOGS = 10;
// ===== СОСТОЯНИЯ =====
bool logMode = false;
int currentLogIdx = 0;
int totalLogs = 0;
unsigned long lastBtnPress = 0;
unsigned long logModeTimer = 0;
// ===== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ =====
String formatUID(MFRC522::Uid uid) {
String s = "";
for (byte i = 0; i < uid.size; i++) {
if (uid.uidByte[i] < 0x10) s += "0";
s += String(uid.uidByte[i], HEX);
if (i < uid.size - 1) s += " ";
}
return s.toUpperCase();
}
void saveLog(String entry) {
int idx = totalLogs % MAX_LOGS;
prefs.putString(String(idx), entry);
totalLogs++;
prefs.putInt("count", totalLogs);
}
// ===== НАСТРОЙКА =====
void setup() {
Serial.begin(115200);
SPI.begin();
mfrc522.PCD_Init();
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0); lcd.print("RFID System v1.0");
lcd.setCursor(0, 1); lcd.print("Init memory...");
prefs.begin("rfid_logs", false);
totalLogs = prefs.getInt("count", 0);
pinMode(BTN_PIN, INPUT_PULLUP);
delay(1000);
lcd.clear();
lcd.setCursor(0, 0); lcd.print("READY: Scan Card");
lcd.setCursor(0, 1); lcd.print("[BTN] View Logs");
}
// ===== ОСНОВНОЙ ЦИКЛ =====
void loop() {
// 1. Обработка кнопки
if (digitalRead(BTN_PIN) == LOW && millis() - lastBtnPress > 400) {
lastBtnPress = millis();
logMode = true;
logModeTimer = millis();
// Начинаем с самого свежего лога
currentLogIdx = (totalLogs > 0) ? ((totalLogs - 1) % MAX_LOGS) : -1;
while(digitalRead(BTN_PIN) == LOW) delay(10); // Ждем отпускания
}
// 2. Режим просмотра логов
if (logMode) {
// Автовыход в режим сканирования через 3 сек бездействия
if (millis() - logModeTimer > 3000) {
logMode = false;
lcd.clear();
lcd.setCursor(0, 0); lcd.print("READY: Scan Card");
lcd.setCursor(0, 1); lcd.print("[BTN] View Logs");
return;
}
// Переключение лога при нажатии кнопки
if (digitalRead(BTN_PIN) == LOW && millis() - lastBtnPress > 400) {
lastBtnPress = millis();
logModeTimer = millis(); // Сброс таймера
if (totalLogs > 0) {
int limit = min(totalLogs, MAX_LOGS);
currentLogIdx = (currentLogIdx == 0) ? (limit - 1) : (currentLogIdx - 1);
}
while(digitalRead(BTN_PIN) == LOW) delay(10);
}
if (totalLogs > 0) {
String log = prefs.getString(String(currentLogIdx));
lcd.clear();
// Выводим лог на две строки, если не помещается в 16 символов
lcd.setCursor(0, 0); lcd.print(log.substring(0, 16));
lcd.setCursor(0, 1);
if (log.length() > 16) lcd.print(log.substring(16, 32));
} else {
lcd.clear();
lcd.setCursor(0, 0); lcd.print("No logs stored");
lcd.setCursor(0, 1); lcd.print("Press BTN to exit");
}
return;
}
// 3. Считывание карты (только в обычном режиме)
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) return;
String uidStr = formatUID(mfrc522.uid);
bool granted = (mfrc522.uid.size == 4);
if (granted) {
for (byte i = 0; i < 4; i++) {
if (mfrc522.uid.uidByte[i] != AUTH_UID[i]) { granted = false; break; }
}
}
// Формируем и сохраняем лог
String logEntry = String(millis()/1000) + "s " + (granted ? "OK " : "FAIL") + " " + uidStr;
saveLog(logEntry);
// Вывод результата
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(granted ? "ACCESS GRANTED " : "ACCESS DENIED ");
lcd.setCursor(0, 1);
lcd.print("UID: " + uidStr + " "); // Паддинг пробелами
// Пауза чтобы пользователь увидел результат и убрал карту
delay(1500);
lcd.clear();
lcd.setCursor(0, 0); lcd.print("READY: Scan Card");
lcd.setCursor(0, 1); lcd.print("[BTN] View Logs");
// Сброс состояния ридера
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}