Страница 1 из 1

Дубликатор/копировальщих домофонных ключей (iButton/RW/DS1990)

Добавлено: Вт дек 01, 2020 9:56 am
TechMike
Надоело покупать у барыг услугу клонирования ключей для домофона, схем в интернете полно, нашел ту, по которой есть вся рассыпуха, повторил, но потребовалась доработка кода https://mysku.ru/blog/aliexpress/42027.html.
Написано в VSC 1.15.1 + PlatformIO IDE 2.2.1 (PACKAGES: framework-arduino-avr 5.0.0, toolchain-atmelavr 1.50400.190710 (5.4.0))

Для копирования:
Включаем устройство (подключаем USB), прозвучит длинный сигнал.
Прикладываем копируемый ключ к считывателю, светодиод начинает мигать, это говорит о том, что код ключа считался в память дубликатора. Если бузер будет при этом пищать, значит считан ключ с некорректным CRC
Нажимаем «зелёную» кнопку записи и держим, светодиод начинает светиться постоянно.
Держим кнопку и прикладываем ключ на который хотим записать, после записи бузер пикнет один раз и светодиод потухнет. Сделать это нужно в течении 6 секунд после нажатия и удержания кнопки.
После сигнала, примерно две секунды ничего не происходит, чтобы можно было убрать записываемый ключ

Для записи «универсального» ключа:
Включаем устройство (подключаем USB) или жмем RESET, прозвучит длинный сигнал.
Не прикладывая к считывателю ключа, нажимаем и держим «зелёную» кнопку записи, светодиод начинает светиться постоянно.
Прикладываем ключ, на который хотим записать, после записи раздается один звуковой сигнал и светодиод тухнет. Сделать это нужно в течении 6 секунд после нажатия и удержания кнопки.
После сигнала, примерно две секунды ничего не происходит, чтобы можно было убрать записываемый ключ

P.S. Нет проверки записался ли ключ или нет, это специально, чтобы не растягивать процесс во времени.

Занято ресурсов mega328:
RAM: [=== ] 31.4% (used 644 bytes from 2048 bytes)
Flash: [== ] 19.6% (used 6016 bytes from 30720 bytes)

Кодя:

Код: Выделить всё

// http://wikihandbk.com/wiki/Arduino:%D0%91%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8/OneWire
#include <OneWire.h>

// https://stackoverflow.com/questions/56923895/auto-increment-build-number-using-platformio
#include <version.h>

#define ibutton_pin 11  // Пин D11 для подлючения iButton (Data)
OneWire ibutton (ibutton_pin); // создаем объект под ibutton
#define OWAddressSize 8 // размер в байтах адреса ключа
byte addr[OWAddressSize];     // для хранения ситываемого адреса ключа
byte ReadID[OWAddressSize]; // считаный ключ
byte UnivesalID[OWAddressSize] = { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F }; // "Универсальный" ключ. Прошивается последовательность 01:FF:FF:FF:FF:FF:FF:2F
byte newID[OWAddressSize];    // для хранения записываемого на ключ адреса

const int buttonPin = 6;    // Пин D6 для подлючения кнопки
const int ledPin = 13;      // Пин D13 для подлючения светодиода (встроенны  в плату nano)
int buttonState = 0;      // состояние кнопки (нажата/отпущена)
int writeflag = 0;
int readflag = 0;
int val = 0;      // счетчик времени нажатия кнопки
char msg[100];   // временный массив для вывода данных
byte crc; // для рассчета контрольной суммы

#define buzzer_pin 2  // Пин D2 для подлючения пищалки
#define write_delay 6  // величина цикла задежки при удержании кнопки, после которой происходит запись ключа

void setup() {
  // инициализирует GPIO
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(buzzer_pin, OUTPUT);

  Serial.begin(115200);
  digitalWrite(buzzer_pin, HIGH);
  delay(1000);
  Serial.println("Start");
  Serial.println(VERSION);    // выводим версию из version.h
  digitalWrite(buzzer_pin, LOW);
  memcpy(ReadID, UnivesalID, OWAddressSize);   // копируем адрес универсального ключа в адрес прочтенного ключа, чтобы можно было не считывая ключ записать универсальный
}

void loop() {

  buttonState = digitalRead(buttonPin);     // читаем статус кнопки
  if (buttonState == HIGH) {
    // нажата кнопка, начинаем отсчет
    digitalWrite(ledPin, HIGH);
    val++;              // копим счетчик времени удержания кнопки (в 1/2 секундах)
    if (val > write_delay){
      // кнопка нажата нужное время, можно пднимать флаг записи ключа
      val = write_delay; // прекращаем отсчет, просто зависаем на одном значении
      writeflag = 1;   // поднимаем флаг необходимости записи ключа
    }else{
      // время еще не пришло, выводим отчет и создаем задержку
      Serial.print(val);
      delay(500);     
    }
  } else {
    // кнопка не нажата, можно читать ключи
    val = 0;    // обнуляем сетчик времени удержания кнопки
    writeflag=0;
    digitalWrite(ledPin, LOW);    // гасим светодиод

    if (!ibutton.search(addr)) {   // если не нашли датиков на шине
      // Serial.println("!ibutton.search");
      ibutton.reset_search();   // Начинаем новый поиск. Следующее использование поиска начнется на первом устройстве.
    }else { 
      // если нашли новое устройство но не нажата кнопка (чтобы не считать на что нужно записать !!!)
      // Serial.println("ibutton.search");
      digitalWrite(ledPin, HIGH);
      delay(50);

      // выводим в UART адрес найденого ibutton
      crc = ibutton.crc8(addr, OWAddressSize-1);
      if (crc==addr[7]) {
        sprintf(msg,"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X CRC:%02X (valid)",addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], crc);
      }else {
        sprintf(msg,"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X CRC:%02X (NOT valid)",addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], crc);
        digitalWrite(buzzer_pin, HIGH);
        delay(50);
        digitalWrite(buzzer_pin, LOW);
        delay(50);
        digitalWrite(buzzer_pin, HIGH);
        delay(50);
        digitalWrite(buzzer_pin, LOW);
      }
      Serial.println(msg);
      memcpy(ReadID, addr, OWAddressSize);   // копируем считаный адрес в массив для записи на ключ
    }
  }

  if (writeflag == 1) {
    // пишем  ключ на ibuton, если в ReadID прочитаный ключ, то запищем его, если ничего не прочитали, то запищем универсальный из настройки
    Serial.println();
    Serial.println("Write key begin");
    ibutton.skip();   // Пропускает выбор устройства. Это работает лишь тогда, когда подключено лишь одно устройство, то есть вы можете не использовать поиск, а сразу получить доступ к своему устройству.
    ibutton.reset();  // Делает сброс шины 1-Wire. Как правило, это нужно перед коммуникацией с каким-либо устройством.
    ibutton.write(0x33); // Отправляем команду "считать ROM"
    
    // Serial.print("  ID before write");
    // считываем из шины ROM прислоненного ключа
    for (byte x = 0; x < 8; x++) {
      addr[x]=ibutton.read();
      // Serial.print(':');
      // Serial.print(ibutton.read(), HEX);  // считываем байт из шины (от Read ROM [33h]) и выводим его
    }
    sprintf(msg,"  ID before write %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
    Serial.println(msg);

    if (memcmp(ReadID, UnivesalID, OWAddressSize)==0){
      // пишем универсальный ключ
      Serial.println("  the universal identifier will be recorded!");
    }
    // send reset
    ibutton.skip();   // Пропускает выбор устройства. Это работает лишь тогда, когда подключено лишь одно устройство, то есть вы можете не использовать поиск, а сразу получить доступ к своему устройству.
    ibutton.reset();  // Делает сброс шины 1-Wire. Как правило, это нужно перед коммуникацией с каким-либо устройством.
    // send 0xD1
    ibutton.write(0xD1);    // разрешаем запись на ключ
    // send logical 0
    digitalWrite(ibutton_pin, LOW); pinMode(ibutton_pin, OUTPUT); delayMicroseconds(60);
    pinMode(ibutton_pin, INPUT); digitalWrite(ibutton_pin, HIGH); delay(10);

    // Serial.print('\n');
    // Serial.print("  Writing iButton ID:\n    ");
    // byte newID[8] = { (ReadID[0]), (ReadID[1]), (ReadID[2]), (ReadID[3]), (ReadID[4]), (ReadID[5]), (ReadID[6]), (ReadID[7]) };
    memcpy(newID, ReadID, OWAddressSize);   // копируем адрес из масива прочтенного ключа в массив для записи
    sprintf(msg,"  ID Writing      %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",newID[0], newID[1], newID[2], newID[3], newID[4], newID[5], newID[6], newID[7]);
    Serial.println(msg);

    ibutton.skip();
    ibutton.reset();
    ibutton.write(0xD5);
    for (byte x = 0; x < 8; x++) {
      writeByte(newID[x]);
      // Serial.print(newID[x], HEX);
      // Serial.print(":");
    }
    // Serial.print('\n');
    ibutton.reset();    // Делает сброс шины 1-Wire. Как правило, это нужно перед коммуникацией с каким-либо устройством.
    // send 0xD1
    ibutton.write(0xD1);  // запрещаем (было уже разрешение) запись на ключ
    //send logical 1
    digitalWrite(ibutton_pin, LOW); pinMode(ibutton_pin, OUTPUT); delayMicroseconds(10);
    pinMode(ibutton_pin, INPUT); digitalWrite(ibutton_pin, HIGH); delay(10);
    writeflag = 0;
    
    // пищим успехом
    digitalWrite(buzzer_pin, HIGH);
    delay(100);
    digitalWrite(buzzer_pin, LOW);
    val = 0;    // чтобы сбросить задерку если кнопку успели нажать во время записи
    digitalWrite(ledPin, LOW);
    Serial.println("Write key end");
    delay(2000);
  }
}

int writeByte(byte data) {
  int data_bit;
  for (data_bit = 0; data_bit < 8; data_bit++) {
    if (data & 1) {
      digitalWrite(ibutton_pin, LOW); pinMode(ibutton_pin, OUTPUT);
      delayMicroseconds(60);
      pinMode(ibutton_pin, INPUT); digitalWrite(ibutton_pin, HIGH);
      delay(10);
    } else {
      digitalWrite(ibutton_pin, LOW); pinMode(ibutton_pin, OUTPUT);
      pinMode(ibutton_pin, INPUT); digitalWrite(ibutton_pin, HIGH);
      delay(10);
    }
    data = data >> 1;
  }
  return 0;
}

Схема в модном и корявом Фритзинге:
Image

Как выглядит устройство:
Image
Image
Image
Image
Image
Image

Исходники, моделька корпуса, схема и т.д.:
http://www.rn3aig.ru/phpBB3/files/Ibutt ... 122020.rar