Электронный замок на Arduino Nano

Решил впервые поработать с электроникой, а точнее с Arduino, и сделать электронный замок, который будет открываться по карточке.
Замок будет питаться от постоянного тока и иметь запасной источник питания (эта схема пока пробная и собрана на аккумуляторах 18650 и батарейках 1,5 в).

первая версия кода:

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9  // Пин сброса RC522
#define SS_PIN 10  // Пин выбора RC522
#define LOCK_PIN 6  // для управления транзистором замка

MFRC522 mfrc522(SS_PIN, RST_PIN);  // Создание MFRC522

byte validUID1[] = {0xC3, 0xAE, 0xD9, 0x2C};
byte validUID2[] = {0x44, 0xB9, 0xB4, 0x02};

void setup() {
  Serial.begin(9600);  // Serial для отладки
  SPI.begin();        // SPI
  mfrc522.PCD_Init();   // RC522

  pinMode(LOCK_PIN, OUTPUT);  // Настройка пина LOCK_PIN как выход
  digitalWrite(LOCK_PIN, HIGH); // HIGH - подача напряжения
  Serial.println("Замок закрыт.");
}

void loop() {
  // Проверка наличия новой карты
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Чтение карты
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  // Выводим UID карты в Serial
  Serial.print("Card UID:");
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.println();

  // Проверка UID карты
  if (compareUID(mfrc522.uid.uidByte, validUID1) || compareUID(mfrc522.uid.uidByte, validUID2)) {
    Serial.println("Access granted! Opening lock...");
    digitalWrite(LOCK_PIN, LOW);  // открываем замок
    Serial.println("Замок открыт.");
    delay(5000);                    // Задержка 5 секунд
    digitalWrite(LOCK_PIN, HIGH); //  (закрываем замок)
    Serial.println("Замок закрыт.");
  } else {
    Serial.println("Access denied!");
  }

  // Останавливаем чтение карты
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

// для сравнения UID карты с разрешенным UID
bool compareUID(byte cardUID[], byte validUID[]) {
  for (byte i = 0; i < mfrc522.uid.size; i++) {  // Проверка по размеру UID
    if (cardUID[i] != validUID[i]) {
      return false;
    }
  }
  return true;
}

вторая версия кода:

#include <SPI.h>
#include <MFRC522.h>
#define RELAY_PIN 2       // Пин управления реле
#define BATTERY_VOLTAGE_PIN A0 // Аналоговый пин для измерения напряжения батареи
#define ERROR_LED_PIN 13  // LED для индикации ошибки
#define OUTPUT_ENABLE_PIN 8  // Пин управления включением/выключением нагрузки #define PWM_PIN 9           // Пин для PWM управления (если есть
//Параметры батареи
#define MIN_BATTERY_VOLTAGE 10.5 // Минимальное напряжение батареи 
#define MAX_BATTERY_VOLTAGE 12.6 // Максимальное напряжение батареи
#define REFERENCE_VOLTAGE 5.0 // Опорное напряжение Arduino 
//Порог напряжения сети
#define MAIN_VOLTAGE_PRESENT 200 //Если аналоговый порт выдает больше этого значения - сеть есть.
#define MAIN_VOLTAGE_PIN A1 // Пин для измерения напряжения сети 
#define RST_PIN 9  // Пин сброса RC522
#define SS_PIN 10  // Пин выбора RC522
#define LOCK_PIN 6  // для управления транзистором замка
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Создание MFRC522
bool errorState = false;
byte validUID1[] = {0xC3, 0xAE, 0xD9, 0x2C};
byte validUID2[] = {0x44, 0xB9, 0xB4, 0x02};
void setup() {
Serial.begin(9600);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BATTERY_VOLTAGE_PIN, INPUT);
  pinMode(ERROR_LED_PIN, OUTPUT);
  pinMode(OUTPUT_ENABLE_PIN, OUTPUT);
  pinMode(PWM_PIN, OUTPUT);
  pinMode(MAIN_VOLTAGE_PIN, INPUT);
  digitalWrite(RELAY_PIN, LOW); // LOW = Питание от сети 
  digitalWrite(OUTPUT_ENABLE_PIN, HIGH);//Включаем выход нагрузки если есть.
  analogWrite(PWM_PIN, 255);//включаем нагрузку на максимум(если используем)
}
void loop() {
  checkPowerSource();
  checkBatteryState(); //Проверяем состояние батареи - чтобы не перезарядить ее
 if (errorState) {
    handleError();
  }
  //Дальнейший код управления системой, если нужно.
}

void checkPowerSource() {
  if (isMainsPowerPresent()) {
    // Есть напряжение в сети, питаемся от сети
    switchToMains();
  } else {
    // Нет напряжения в сети, переключаемся на батарею
    switchToBattery();
  }
}
bool isMainsPowerPresent() {
  // Используйте делитель напряжения для безопасного измерения напряжения сети
  int mainsVoltageRaw = analogRead(MAIN_VOLTAGE_PIN);

  if(mainsVoltageRaw > MAIN_VOLTAGE_PRESENT){
    return true; //Сеть есть
  } else {
    return false;//Сети нет
  }
}
void checkBatteryState() {
  float batteryVoltage = measureBatteryVoltage();
Serial.print("Battery Voltage: ");
  Serial.println(batteryVoltage);
if (batteryVoltage < MIN_BATTERY_VOLTAGE && isMainsPowerPresent() ) {   Serial.println("Battery low, but mains are present.");
    //Ничего не делаем, заряжаем.
  }
  else if (batteryVoltage > MAX_BATTERY_VOLTAGE && isMainsPowerPresent()) {
     Serial.println("Battery OVERCHARGED turning off battery connection!");
     digitalWrite(RELAY_PIN, LOW); //Возвращаемся к сети
     errorState = true;
  }
  else{
     errorState = false;
  }
  digitalWrite(ERROR_LED_PIN, errorState ? HIGH : LOW);
}
void switchToMains() {
  digitalWrite(RELAY_PIN, LOW); // LOW = Питание от сети (Настройка зависит от типа реле!)
  Serial.println("Switching to Mains Power");
}
void switchToBattery() {
  digitalWrite(RELAY_PIN, HIGH); // HIGH = Питание от батареи (Настройка зависит от типа реле!)
  Serial.println("Switching to Battery Power");
}
float measureBatteryVoltage() {
  int sensorValue = analogRead(BATTERY_VOLTAGE_PIN);
  float voltage = sensorValue * (REFERENCE_VOLTAGE / 1023.0);
  return voltage;
}
void handleError() {
  digitalWrite(OUTPUT_ENABLE_PIN, LOW);
  analogWrite(PWM_PIN, 0);
// Мигаем LED при ошибке
  static unsigned long lastBlink = 0;
  static bool ledState = false;
if (millis() - lastBlink > 500) {
    lastBlink = millis();
    ledState = !ledState;
    digitalWrite(ERROR_LED_PIN, ledState);
  }
}
float measureSolarVoltage() {
  return 0;
}
float measureSolarCurrent() {

  Serial.begin(9600);  // Serial для отладки
  SPI.begin();        // SPI
  mfrc522.PCD_Init();   // RC522
 pinMode(LOCK_PIN, OUTPUT);  // Настройка пина LOCK_PIN как выход
  digitalWrite(LOCK_PIN, HIGH); // HIGH - подача напряжения
  Serial.println("Замок закрыт.");
}
void loop() {
  // Проверка наличия новой карты
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }
 // Чтение карты
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }
 // Выводим UID карты в Serial
  Serial.print("Card UID:");
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.println();
 // Проверка UID карты
  if (compareUID(mfrc522.uid.uidByte, validUID1) || compareUID(mfrc522.uid.uidByte, validUID2)) {
    Serial.println("Access granted! Opening lock...");
    digitalWrite(LOCK_PIN, LOW);  // открываем замок
    Serial.println("Замок открыт.");
    delay(5000);                    // Задержка 5 секунд
    digitalWrite(LOCK_PIN, HIGH); //  (закрываем замок)
    Serial.println("Замок закрыт.");
  } else {
    Serial.println("Access denied!");
  }

  // Останавливаем чтение карты
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}
// для сравнения UID карты с разрешенным UID
bool compareUID(byte cardUID[], byte validUID[]) {
  for (byte i = 0; i < mfrc522.uid.size; i++) {  // Проверка по размеру UID
    if (cardUID[i] != validUID[i]) {
      return false;
    }
  }
  return true;
}

третья версия кода:

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9       // Пин сброса RC522
#define SS_PIN 10       // Пин выбора RC522
#define LOCK_PIN 6      // для управления транзистором замка
#define PWR_SW_PIN 7    // для управления PNP транзистором питания
#define VBAT_SENSE_PIN A0 // для контроля напряжения сети

MFRC522 mfrc522(SS_PIN, RST_PIN);  // Создание MFRC522

byte validUID1[] = {0xC3, 0xAE, 0xD9, 0x2C};
byte validUID2[] = {0x44, 0xB9, 0xB4, 0x02};

bool isPowerBackup = false;
unsigned long lastPowerCheck = 0;
const unsigned long POWER_CHECK_INTERVAL = 1000; // Проверка питания каждую секунду

void setup() {
  Serial.begin(9600);
  
  pinMode(LOCK_PIN, OUTPUT);
  digitalWrite(LOCK_PIN, HIGH); // Замок закрыт
  
  pinMode(PWR_SW_PIN, OUTPUT);
  digitalWrite(PWR_SW_PIN, HIGH); // Изначально питание от сети
  
  SPI.begin();
  mfrc522.PCD_Init();
  
  Serial.println("Система запущена. Замок закрыт.");
}

void loop() {
  // Проверка питания
  if (millis() - lastPowerCheck > POWER_CHECK_INTERVAL) {
    checkPowerSource();
    lastPowerCheck = millis();
  }

  // Проверка наличия новой карты
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Чтение карты
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  // Выводим UID карты
  Serial.print("Card UID:");
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.println();

  // Проверка UID карты
  if (compareUID(mfrc522.uid.uidByte, validUID1) || compareUID(mfrc522.uid.uidByte, validUID2)) {
    Serial.println("Access granted! Opening lock...");
    digitalWrite(LOCK_PIN, LOW);  // открываем замок
    Serial.println("Замок открыт.");
    delay(5000);                  // Задержка 5 секунд
    digitalWrite(LOCK_PIN, HIGH); // закрываем замок
    Serial.println("Замок закрыт.");
  } else {
    Serial.println("Access denied!");
  }

  // Останавливаем чтение карты
  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

// Функция проверки источника питания
void checkPowerSource() {
  int vbatValue = analogRead(VBAT_SENSE_PIN);
  float voltage = vbatValue * (5.0 / 1023.0) * 2; // Предполагаем делитель 1:1
  
  if (voltage < 4.5 && !isPowerBackup) { // Если сетевое питание пропало
    Serial.println("Переключение на резервный аккумулятор!");
    digitalWrite(PWR_SW_PIN, LOW); // Включаем питание от аккумулятора
    isPowerBackup = true;
  } 
  else if (voltage >= 4.7 && isPowerBackup) { // Если сетевое питание восстановилось
    Serial.println("Переключение на сетевое питание!");
    digitalWrite(PWR_SW_PIN, HIGH); // Возвращаемся к сетевому питанию
    isPowerBackup = false;
  }
}

// Функция сравнения UID
bool compareUID(byte cardUID[], byte validUID[]) {
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    if (cardUID[i] != validUID[i]) {
      return false;
    }
  }
  return true;
}

Помогите пожалуйста, сам пытался разобраться, но увы не вышло

Вам не кажется, что Вы забыли написать в чём у Вас проблема? Что не так?

Запомните, всегда необходимо внятно описать;

  1. что хотели сделать (именно внятно, а не “замок”). Конкретно, что должно происходить в каких ситуациях;
  2. что получилось, т.е. как оно работает сейчас. Опять же внятно и подробно;
  3. и, наконец, нужно чётко описать чем №2 отличается от №1 – что собственно не так и что Вы не можете исправить.

Конечно, “по минималкам” хватило и первого пункта. Остальное помогающий мог бы и сам допереть, потратив пару-тройку часов на изучение кода, но скажите честно, Вы верите, что кто-то станет это делать? Если Вам это настолько не нужно, что Вам лень написать три строчки, кто-то станет тратить на это часы? Вы в это верите?

Видимо, как это нередко случается, вопрос решился сам собой при попытке его внятно сформулировать и описать?

1 лайк