Домофон, который знает, как вас зовут — своими руками

image

В мире современных технологий, где мы можем управлять многими устройствами через мобильный телефон или голосового ассистента, удивляет присутствие примитивных элементов, таких как неприятно пищащие зуммеры. Ведь они были изобретены еще в 1831 году! Я решил привнести некоторые современные функции в систему управления доступом (СКУД), которая является ключевой частью любого домофона. Мой проект направлен на создание более интуитивной и приятной для слуха системы управления доступом.

Видео


Всем, у кого нет желания вдаваться в технические подробности описанные в этой статье, могут посмотреть видео. В котором показана подробная работа моей самоделки.

Функциональность


В системе контроля доступа будет несколько режимов:

  1. Обычный режим доступа. Сканирование меток и открытие дверей.
  2. Режим сброса ключей.
  3. Режим добавления мастер ключа.
  4. Режим добавление новых ключей, с привязкой каждого ключа к определенному имени.


В режиме добавления ключей невозможно добавить один и тот же ключ дважды. К каждому имени можно привязать множество ключей в рамках доступной памяти.

Схема


image
Питание устройства 12В берется от вызывной панели домофона и подключается через понижающий преобразователь на выходе которого 5В. Открытие двери осуществляется замыканием линии «Audio» с »+12V», используя оптрон, при подключении которого важно соблюдать полярность. Имейте в виду, что в схеме использует светодиод с общим анодом, который включается сигналом «LOW». При использовании светодиода с общим катодом нужно внести изменения в коде и в схеме подключения светодиода.

Компоненты


image

RFID RC522


В этом проекте используется наиболее распространенный модуль бесконтактной идентификации RFID Mifare RC522. Девайс служит для бесконтактного чтения RFID-тегов, работая на частоте 13.56 МГц. Я выбрал SPI интерфейс для подключения к Arduino, предпочитая его за его надежность по сравнению с UART и I2C. Модуль поддерживает различные типы карт, включая MIFARE S50, MIFARE S70, MIFARE UltraLight, MIFARE Pro, MIFARE DESfire.

Для питания модуля я использовал 3.3 В от пина Arduino, которое в свою очередь поступает от микросхемы CH340, оборудованной встроенным преобразователем. Однако, она обеспечивает максимальный ток всего 80 мА. Были отмечены проблемы с нестабильной работой считывателя при использовании этого питания, но предположительно, причина кроется в недостаточном пиковом токе. Я решил эту проблему, добавив в цепь конденсатор на 47 мкФ, что обеспечило стабильную работу устройства в пиковых нагрузках.

Так как для СКУД важна надежность и безотказность, я использую в коде периодический сброс модуля RFID.

image


MP3-плеер DFPlayer


DFPlayer — это небольшой, но функциональный аудиомодуль, способный читать аудиофайлы MP3 с TF или микро SD карт и воспроизводить их через встроенный в него усилитель. DFPlayer может управляться автономно или через интерфейс UART, подключенный к Arduino или другому микроконтроллеру. В используемом мной модуле установлен плеер на микросхеме MH2024K-24SS.

image


Борьба с помехами и цифровыми шумами


Во время паузы между воспроизведением треков в динамике ясно слышны цифровые шумы, создаваемые встроенным в плеер контроллером. Фильтрация питания с помощью LC-фильтров и установка линейного стабилизатора почти не помогли. Так как в плеере нет отдельного питания для усилителя и ЦАП, то эту проблему невозможно решить аппаратным способом. Вероятно, между внутренним контроллером, ЦАП и УНЧ нет встроенных LC или RC фильтров питания. А если они есть, то они не справляются со своей задачей.

Я нашел способ решить эту проблему программно. Для этого я написал отдельную функцию воспроизведения треков. Как работает эта функция? После воспроизведения трека я уменьшаю громкость до нуля, а перед воспроизведением она восстанавливается до уровня, заданного пользователем. Этот трюк существенно помог решить проблему, но в звуковой тракт в паузах все равно оставался слабый жужжащий звук. Эту проблему мне помог решить мой знакомый, ардуино-энтузиаст Герман. Он выяснил, что это жужжание исходит от UART и чтобы от него избавиться, достаточно было перепрограммировать порт TX Ардуино с выхода на вход, при этом подтянув его внутренним сопротивлением к плюсу питания.

Теперь, после применения этих решений, когда проигрыватель находится в режиме ожидания, никакие посторонние шумы не слышны. Если приложить ухо к динамику, можно услышать только едва уловимый белый шум, создаваемый переходными процессами в полупроводниках на первичных стадиях усиления. И то, что сначала запускается воспроизведение, а потом устанавливается громкость, это не ошибка, а особенность этого модуля.

Привожу код функции, которая убирает шум в режиме простоя:

void mp3play(uint16_t track, uint16_t time)
{
  pinMode(TX, OUTPUT);            // восстанавливаем выход TX  
  mp3_play(track);                // проиграть трек
  mp3_set_volume (volume);        // устанавливаем заданную громкость
  delay(time);                    // длительность проигрывания трека
  mp3_set_volume (0);             // выключаем звук, что бы не было цифрового шума в динамике
  pinMode(TX, INPUT_PULLUP);      // Отключаем TX, что бы в динамике исчезло жужжание
}


Другие проблемы с плеером и их решение


Для отслеживания в DFPlayer статуса проигрывания трека, я сначала использовал сигнал BUSY, но он оказался непредсказуемым. В зависимости от различных факторов, после завершения воспроизведения трека на этом выводе может не появиться ожидаемая логическая единица, и плеер уходит в зависание, так как для ожидания завершения воспроизведения используется цикл while (! digitalRead (BUSY_PIN)). По этой причине для ожидания завершения проигрывания трека пришлось использовать delay ().

Плеер может воспроизводить треки не до конца и обрывать фразы на полуслове без видимых на то причин. При этом плеер продолжает исправно принимать команды по UART. Поэтому я решил выполнять сброс плеера каждые 10 минут.

Динамик


Громкоговоритель от мягкой игрушки показал себя очень хорошо, но для моего корпуса он оказался слишком большим, поэтому пришлось использовать динамическую головку от мобильного телефона.

Для оптимальной работы динамика важно исключить короткое акустическое замыкание. Это происходит, когда давление воздуха с одной стороны головки абсорбируется разрежением с противоположной стороны диффузора. Другими словами, акустические волны взаимно нейтрализуют друг друга в противофазе. Чтобы избежать этого, необходимо обеспечить надежную герметичность громкоговорителя в корпусе. К счастью, динамик от телефона уже хорошо герметизирован и не страдает от вышеупомянутых проблем.

При установке модулей в корпус считывателя следует учесть, что неправильно закрепленные платы могут дребезжать из-за вибрации громкоговорителя. Использование силикона или термоклея должно решить эту проблему.

image


Аудиофайлы


Я нашел весьма удовлетворительным использование TTS от Яндекс Алисы для создания озвучки. Для записи фраз от Алисы, я использовал колонку Яндекс Станция Мини-2, которая обладает линейным аудио выходом. Это позволило записывать любую звуковую информацию с этой колонки, подключив ее к линейному входу звуковой карты аудио кабелем.

Я использовал программу Audacity для создания голосовых фраз. Чтобы заставить колонку произносить нужные фразы, я добавил в популярный мессенджер, телеграм бота Алиса (alice_speaker_bot). После этого, отправив ему сообщение с подготовленным текстом, Алиса произносит его.

Для того чтобы фразы звучали как в научно-фантастических фильмах, в аудиоредакторе к звуковому файлу можно добавить эффект «Эхо». Настройки этого эффекта представлены на скриншоте ниже.

image

Корпус считывателя


Корпус оказался немного маловат по размеру, поэтому вместо стандартного RFID-ридера, я заказал компактную версию устройства из Китая. К сожалению, он приехал неисправным.

image


В корпусе отсутствует встроенная подсветка, поэтому я использовал подсветку из старого разбитого экрана от тестера LCR-T4, который идеально подошел по размеру.

image


В итоге результат оказался весьма впечатляющим. Камера не может передать реальный цвет, в реальности выглядит гораздо красивее.

image


Сборка


Для отладки устройства, я собрал проект на макетной плате. После успешного тестирования, я спаял все платы вместе, используя навесной монтаж. Признаю, что это не лучший вариант из существующих, но у меня нет ни времени, ни желания рисовать и травить кросс-плату. На фотографии ниже приведен пример того, как будут размещены платы, но они еще не закреплены в корпусе, так как RFID-модуль нужно будет заменить на исправный, когда он приедет.

image


Код для Ардуино


Код полностью прокомментирован и доступен для ознакомления.

Нажмите, что бы посмотреть
#include 
#include 
#include 

#define BUSY_PIN 4              // Пин BUSY для MP3 пдеера
#define RST_PIN 9               // Пин RST для rfid модуля
#define SS_PIN 10               // Пин SS для rfid модуля
#define RX 2                    // назначить пин RX SoftSerial
#define TX 3                    // назначить пин TX SoftSerial
#define modeRes 11              // пин для сброса памяти ключей
#define look_PIN 5              // номер пина для подключения к нему реле открытия замка
#define blue_PIN 8
#define green_PIN 7
#define red_PIN 6

#define interval 2000           // интервал сброса RFID модуля в мкс
#define time_reset_mp3 600000   // интервал сброса MP3 плеера
#define volume 25               // громкость MP3 от 0 до 30
#define equalizer 0             // эквалайзер(POP=1) от 0 до 5 Normal/Pop/Rock/Jazz/Classic/Bass
#define sumName 7               // количество имен пользователей записанных на флешке начинаются с 0001.mp3, 0002.mp3 ... и т.д.

uint32_t rebootTimer=0, oldTime=0;           // Переменная для таймера

MFRC522 rfid(SS_PIN, RST_PIN);    // Назначить пины SS и RST
SoftwareSerial mySerial(RX, TX);  // назначить пины RX, TX SoftSerial

void setup() 
{ 
 // pinMode(look_PIN, OUTPUT);          // пин для подключения реле открытия замка
 // digitalWrite(look_PIN, LOW);
  pinMode(red_PIN, OUTPUT);
  pinMode(green_PIN, OUTPUT);
  pinMode(blue_PIN, OUTPUT);
  pinMode(modeRes, INPUT_PULLUP);     // пин сброса памяти ключей

  mySerial.begin (9600);              // Инициализация Soft Serial
  mp3_set_serial (mySerial);    
  delay (1000);
    mp3Reset();                          // инициализация плеера

  uint8_t memClear = digitalRead(modeRes); // проверяем состояние пина сброса памяти
  if(!memClear)                       // Если установлена перемычка на GND и пин D11
  {
    digitalWrite (green_PIN, HIGH);
    digitalWrite (red_PIN, HIGH);
    eeprom_write_byte(0, 255);    // то обнуляем счетчик ключей
    mp3play (113, 13000);         // память обнулена
    while(true);                  // зависаем и ждем нажатия reset
  }

  SPI.begin();                  // Инициализация SPI
  firstStart();                 // проверка наличия Мастер ключа и добавление его
  mp3play (109, 9500);          // система активирована

  //Serial.begin(115200);       // Инициализация Serial
  //wdt_enable(WDTO_8S);
}

void loop() 
{
  digitalWrite (green_PIN, HIGH);
  digitalWrite (red_PIN, HIGH);
  digitalWrite (blue_PIN, HIGH);
  uint8_t  sumKey = eeprom_read_byte(0);     // считываем из EEPROM с адреса 0 информацию о количестве сохраненных ключей 
  uint32_t master = ReadEEPROM_Long(1);      // читаем из EEPROM uid мастер ключа 
  uint32_t uid_tmp = ReadUID();              // ждем когда приложат ключ к считывателю и Читаем UID ключа
  //Serial.println(sumKey);
  //Serial.println(master); 
  //Serial.println(uid_tmp); 
  
  if(uid_tmp == master) 
  { 
    digitalWrite (red_PIN, LOW);
    digitalWrite (blue_PIN, LOW);
    addKey(sumKey);     // если к считывателю поднесли мастер ключ, то переходим в режим добавления новых ключей
  }  
  if(sumKey>=0 && uid_tmp != master)        // если в EEPROM больше 1 ключа и UID прочитан с RFID то сравниваем все имеющиеся в EEPROM ключи со считанным  1
  { 
    uint8_t nameKey = searchKey(sumKey, uid_tmp);  // считываем все ключи по очереди из EEPROM и сравниваем их с UID приложенного к считывателю ключа
    if(nameKey > 0)                                // в nameKey номер(индекс) ключа 
    {               
      sumKey = eeprom_read_byte(nameKey*5); // читаем из EEPROM привязанное к uid имя пользователя 
      //digitalWrite (look_PIN, HIGH);         // открываем замок
      digitalWrite (green_PIN, LOW);
      mp3play (106, 1480);                  // фраза "Здравствуйте"
      mp3play  (sumKey, 1200);              // проигрываем привязанное имя пользователя к uid
      mp3play (107, 5000);                  // фраза "Добро пожаловать"
      //digitalWrite (look_PIN, LOW);        // закрываем замок
    } else { digitalWrite (red_PIN, LOW); mp3play(104, 6500); }          // фраза "Доступ запрещен, Ключ не найден"
  }

  if (millis() - oldTime > time_reset_mp3)    // интервал таймера для сброс плеера
  {
    oldTime = millis();
  }  
}

//*********************************************
uint32_t ReadUID(void)                // опрашиваем считыватель каждую 0,2сек
{
  for (;;)                            // бесконечный цикл
  {
    ResetRFID();                      // перезагружаем RFID модуль каждые 2 секунды
    delay(100);
    if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial())  // Если метка найдена и она прочитана
    {  
      return uidTolong();             // прервать цикл и возвратить UID 
    } 
  }                                                  
}
//-----------------------------------------

uint8_t searchKey( uint8_t sumKey, uint32_t uid )  // поиск ключа в EEPROM. sumKey-количество сохраненных ключей вEEPROM
{
  for (uint8_t i = 1; i <= sumKey; i++) 
  {   
    uint32_t tmp=ReadEEPROM_Long(i*5+1);       //читаем по очереди все сохраненные UID и сравниваем их с UID полученным c RFID
    if(tmp == uid)  { return i; }              // сравниваем считанный из памяти UID с прочитанным UID и если найден, то возвращаем номер совпавшего ключа
  }
  return 0;                                    // если в базе нет такого ключа то возвращаем 0
}
//---------------------------------------

void addKey(uint8_t sumKey)                   // sumKey-количество сохраненных ключей в EEPROM
{
  mp3play(101, 15000);                        // для добавления нового UID после того как услышите имя которое нужно привязать к UID поднесите ключ к считывателю RFID
  for (uint8_t i = 1; i <= sumName; i++)      // перебираем все имена по очереди
  {
    mp3play(110, 1000);                       // проигрывание звука next
    ResetRFID();
    pinMode(TX, OUTPUT);                      // восстанавливаем выход для TX 
    mp3_play (i);                             // проигрываем в фоновом режиме в порядке возрастания все записанные на флешку имена
    mp3_set_volume (volume);                  // устанавливаем заданную громкость
    for (uint8_t ti = 0; ti < 20; ti++)       // цикл таймер, 20*100мс=2 сек на опрос считывателя RFID пока проигрывается имя пользователя
    {
      if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial())  // Если определена метка и она прочитана
      {
        uint32_t uid = uidTolong();            // преобразуем uid из массива в ulong
        uint8_t dub = searchKey(sumKey, uid);  // ищем в EEPROM совпадение, проверяем ключ на дубли
        if(dub == 0)                           // если такого ключа нет в памяти то добавляем его
        {                                      // или если ключ есть то в dub номер ключа
          sumKey++;                            // инкрементируем счетчик ключей                  
          eeprom_write_byte(0, sumKey);        // счетчик ключей в EEPROM 
          eeprom_write_byte(sumKey*5, i);      // сохраняем в EEPROM привязанное к ключу имя 
          WriteEEPROM_Long (sumKey*5+1, uid);  // сохраняем UID ключа в EEPROM 
          delay(500);                          // для того,что бы имя проигралось до конца
          mp3play(103, 4500);                  // фраза "новый ключ сохранен"
          mp3play(112, 9000);                  // фраза "мастер режим завершен"
          return;
        } else 
        { 
          digitalWrite (blue_PIN, HIGH);       
          delay(1000);
          mp3play(111, 9000);                 // прочитанный ключ уже имеется в системе
          digitalWrite (red_PIN, HIGH);
          mp3play(112, 9000);                 // фраза "мастер режим завершен"
          return;
        }         
      }
      delay(100);
    }
  }
  mp3play(108, 9000);                         // Время ожидание ключа истекло.
}
//----------------------------------------

void firstStart(void)
{
  uint8_t tmp = eeprom_read_byte(0);  // проверяем записан ли мастер ключ в EEPROM
  if(tmp==255)                        // если его там нет, то нужно добавить
  {
    mp3play(100, 12500);              // фраза добавить мастер ключ
    uint32_t uid_tmp = ReadUID();     // прочитать UID мастер ключа со считывателя RFID
    if( uid_tmp > 0 )                 // если ключ прочитан то записываем его в EEPROM
    {
      eeprom_write_byte (0, 0);       // по адресу 000 записываем счетчик ключей не более 51 шт.------------------
      WriteEEPROM_Long (1, uid_tmp);  // по адресу 001 может быть записан только мастер ключ
      mp3play(102, 3500);             // фраза мастер ключ добавлен
    }
  }
}
//----------------------------------------

void ResetRFID(void)                  // Таймер сброса RFID защита от зависания
{         
  if (millis() - rebootTimer > interval)    // интервал таймера 
  {
    rebootTimer = millis();           // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);      // Сбрасываем модуль
    delayMicroseconds(100);           // длительность сброса 100 мкс
    digitalWrite(RST_PIN, LOW);       // Отпускаем сброс
    rfid.PCD_Init();                  // Инициализируем RFID
    rfid.PCD_AntennaOn();             // Включаем антенну
  }
}
//---------------------------------------

void mp3Reset(void)                   // можно так же использовать как остановку трека
{
  mp3_reset ();
  delay (1000);
 // mp3_set_device(2);                // 2-работа с SD Card. 1/2/3/4/5 U/SD/AUX/SLEEP/FLASH
 // mp3_DAC (true);
  mp3_set_EQ (equalizer);             // эквалайзер Normal/Pop/Rock/Jazz/Classic/Bass
  delay (100);
  mp3_set_volume (volume);            // устанавливаем громкость
  delay (200);
  pinMode(TX, INPUT_PULLUP);          // Отключаем TX, что бы в динамике исчез шум/наводка
}

void mp3play(uint16_t track, uint16_t time)
{
  pinMode(TX, OUTPUT);                // восстанавливаем выход TX  
  mp3_play(track);                    // проиграть трек
 // mp3_set_volume (volume);            // устанавливаем заданную громкость
  //wdt_reset();
  delay(time);                        // длительность проигрывания
 // mp3_set_volume (0);                 // выключаем звук, что бы не было шума в динамике
  pinMode(TX, INPUT_PULLUP);          // Отключаем TX, что бы в динамике исчез шум/наводка
}
//---------------------------------------

uint32_t uidTolong(void)
{
  uint32_t  uid_long=0;
  uid_long = rfid.uid.uidByte[3];                              // преобразуем uid массив в тип uint32_t
  uid_long = ((uid_long << 8) | rfid.uid.uidByte[2]);
  uid_long = ((uid_long << 8) | rfid.uid.uidByte[1]);  
  return (uid_long = ((uid_long << 8) | rfid.uid.uidByte[0])); //прервать цикл и  передать UID
}

void WriteEEPROM_Long(uint8_t addr, uint32_t data)            //преобразовать из long и сохранить в EEPROM
{           
  eeprom_write_byte((uint8_t*)addr, data & 0xFF);
  eeprom_write_byte((uint8_t*)addr+1, (data & 0xFF00) >> 8);
  eeprom_write_byte((uint8_t*)addr+2, (data & 0xFF0000) >> 16);
  eeprom_write_byte((uint8_t*)addr+3, (data & 0xFF000000) >> 24);
}

uint32_t ReadEEPROM_Long(uint8_t addr)            // считываем значение из EEPROM и преобразуем в long
{
  uint32_t ir_code = eeprom_read_byte((uint8_t*)addr+3); 
  ir_code = (ir_code << 8) | eeprom_read_byte((uint8_t*)addr+2);
  ir_code = (ir_code << 8) | eeprom_read_byte((uint8_t*)addr+1);
  return ((ir_code << 8) | eeprom_read_byte((uint8_t*)addr));
}  

Фразы


Для отладки кода, выкладываю аудио файлы которые нужно скачать, распаковать и скопировать на флешку, а ниже прикладываю их текстовый вариант.

Нажмите, что бы посмотреть
  • 1 — 50 Имена пользователей
  • 100 — В памяти устройства нет сохраненных ключей. Для начала добавьте мастер ключ. Для этого поднесите к считывателю любой ключ который вы хотите сделать основным.
  • 101 — Вы зашли в мастер режим добавления ключей. Что бы добавить новый ключ поднесите его к считывателю.
  • 102 — Мастер ключ добавлен!
  • 103 — Новый ключ добавлен!
  • 104 — Доступ заблокирован! Используемый Вами ключ отсутствует в системе.
  • 105 — Доступ разрешен!
  • 106 — Добрый день!
  • 107 — Добро пожаловать!
  • 108 — Время ожидание ключа истекло. Система бесконтактной идентификации переходит в стандартный режим работы.
  • 109 — Система бесконтактной идентификации готова к работе.
  • 110 — Звуковой сигнал next
  • 111 — Прочитанный ключ уже используется в системе идентификации, попробуйте привязать другую метку.
  • 112 — Мастер режим завершен!
  • 113 — Включен режим обнуления памяти ключей. Все ключи удалены из памяти. Для возврата в стандартный режим не забудьте удалить перемычку и нажать кнопку сброса.

Заключение


К сожалению, проект пока не был доведен до логического завершения из-за неисправности компактного RFID RC522 модуля. Я заказал два таких же модуля у разных продавцов, в надежде, что хотя бы один из них приедет исправным и будет работать. Однако, сроки доставки пока неизвестны. После того, как я установлю считыватель на дверь и протестирую его в реальных условиях, я подготовлю короткий видеоотчет.

Спасибо за внимание! Надеюсь, что эта статья была полезной и вы сможете применить полученные знания в своих проектах. Если у вас есть вопросы, не стесняйтесь задавать их в комментариях. Я с удовольствием на них отвечу.


Читайте также:
b5pjofdoxth14ro-rjsrn7sbmiy.png

© Habrahabr.ru