Дубликатор домофонных ключей на Arduino

Дим M
Topic author, Администратор
Администратор
Avatar
Дим M
Topic author, Администратор
Администратор
Reputation: 74
Posts: 1197
Joined: 5 Apr 2013
With us: 6 years 2 months

#1by Дим » 11 Jun 2019, 20:02

Встретилась интересная статья про дубликатор домофонных ключей на Arduino, дабы не забыть решил оставить её тут.
Можно копировать ключи и без использования терминала, наблюдая только за светодиодом.
Схема устройства
Дубликатор домофонных ключей на Arduino.jpg
Дубликатор домофонных ключей на Arduino
Дубликатор домофонных ключей на Arduino.jpg (115.54 KiB) Viewed 50 times
Скетч

Code: Select all

#include <OneWire.h>

const int switchPin = 2; // Будем использовать аппаратное прерывание INT0, поэтому кнопка должна быть подключена к 2-му пину
const int dataPin = 12; // Data пин считывателя ключей
const int ledPin = 13; // Пин контрольного светодиода
volatile boolean writeMode = false; // Режим записи: 1 - включен; 0 - выключен (режим чтения)
boolean recoveryMode = false; // Режим восстановления нечитаемых ключей (с записанным по ошибке нулевым первым байтом)
byte oldID[8]; // Считанный ID ключа
byte newID[8]; // Записываемый ID ключа
const byte defaultID[8] = { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F }; // По умолчанию прошивается "Универсальный" ID: 01:FF:FF:FF:FF:FF:FF:2F
byte crc; // Контрольная сумма CRC

OneWire ibutton (dataPin);


void setup() {
  Serial.begin(115200);
  loadDefaultID();
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP);
  // При включении устройства, удерживая кнопку нажатой, активируется режим восстановления
  if (digitalRead(switchPin) == LOW) recoveryMode = true;
  attachInterrupt(0, int0, LOW); // при нажитии кнопки срабатывает 0-е прерывание, обработчик прерывания (ISR) - функция int0()
  Serial.println("Device is ready. Send 'h' for help.");
}


// Загрузка дефолтного "универсального" ID 
void loadDefaultID() {
  for (byte x = 0; x < 8; x++) oldID[x] = defaultID[x];
}


// Переключение режима: Чтение/Запись
void changeMode () {
  // Перестраховка от записи некорректного ID
  if (!writeMode) {
    crc = ibutton.crc8(newID, 7); // Вычисление контрольной суммы записываемого ID
    if (newID[0] != 1 || newID[7] != crc) {
      Serial.println(F("ID is incorrect! Writing is not permitted."));
      writeModeOff();
      return;
    }
  }
  writeMode = !writeMode;
  digitalWrite(ledPin, writeMode);
  if (writeMode) {
    Serial.print(F("Waiting for the key to WRITE the new ID: "));
    for (byte x = 0; x < 8; x++) {
      Serial.print(newID[x], HEX);
      Serial.print(' ');
    }
    Serial.println(" ...");
  }
  else {
    writeModeOff();
  }
}


// Автоматическое отключение режима восстановления после записи и вывод приглашения считать новый ключ
void writeModeOff() {
  if (recoveryMode) {
    recoveryMode = false;
    Serial.println(F("Recovery mode disabled."));
  }
  Serial.println(F("Waiting for the key to READ the ID..."));
}


// Обработчик прерывания по нажатию кнопки: переключает режим: Чтение/Запись (отфильтровывая дребезг контактов)
void int0() {
  static unsigned long millis_prev;
  if ( millis() - millis_prev > 100 ) changeMode();
  millis_prev = millis();
}


// Вывод считанного ID в терминал
void printID() {
  for (byte x = 0; x < 8; x++) {
    Serial.print(oldID[x], HEX);
    Serial.print(" ");
  }
  crc = ibutton.crc8(oldID, 7); // Вычисление контрольной суммы считанного ID
  Serial.print(" CRC: ");
  Serial.print(crc, HEX);
  if (oldID[0] !=  0x01) Serial.print(F(" Family code is not valid!"));
  if (crc != oldID[7]) Serial.print(F(" CRC is not valid!"));
  Serial.println();
}


void loop() {
  // Обработка команд, посылаемых через терминал COM-порта
  if (Serial.available() > 0) {
    byte com; // Команда, отправляемая через терминал COM-порта
    com = Serial.read(); 
    switch 
( com ) {
      case 'h': {
        Serial.println(F("Help:"));
        Serial.println(F("d - load default ID"));
        Serial.println(F("w - switch read/write mode"));
        Serial.println(F("m - enter ID manually"));
        Serial.println(F("r - enable recovery mode (send 'r' again to disable)"));
        Serial.println(F("h - show this help"));
        break;
      }
      case 'd': {
        if (writeMode) {
          writeMode = false;
          digitalWrite(ledPin, LOW);
        }
        loadDefaultID();
        Serial.println(F("Default ID is loaded."));
        printID();
        break;
      }
      case 'w': {
        changeMode();
        break;
      }
      case 'r': {
        writeMode = false;
        recoveryMode = !recoveryMode;
        Serial.println(recoveryMode ? F("Recovery mode enabled.") : F("Recovery mode disabled."));
        break;
      }
      case 'm': {
        byte inputID[8]; // Введённый вручную ID ключа
        char inputChar; // Код введённого символа
        char inputNum = 2; // Порядковый номер вводимого сивмола (от 0 до 15). Начинаем вводить со 2-го символа, т.к. 0-ой и 1-ый - фиксированные.
        char charEncode; // 16-ричное число (от 0 до F), в которое преобразуется каждый вводимый ASCII символ
        boolean even = 0; // Признак чётности порядкового номера вводимого символа
        Serial.println(F("Enter the new ID, or press 'Esc' to cancel."));
        inputID[0] = 1;
        Serial.print(F("The new ID is: 01 "));
        while (inputNum < 14) {
          if (Serial.available() > 0) {
            inputChar = Serial.read();
            if (inputChar == 27) {
              Serial.flush();
              Serial.println();
              Serial.print(F("Canceled..."));
              break;
            }
            else {
              if      ( inputChar >= 48 && inputChar <= 57  ) charEncode = inputChar - 48;
              else if ( inputChar >= 65 && inputChar <= 70  ) charEncode = inputChar - 55;
              else if ( inputChar >= 97 && inputChar <= 102 ) charEncode = inputChar - 87;
              else inputNum = -1;
              if ( inputNum != -) {
                Serial.write(inputChar);
                if (!even) inputID[inputNum/2] = charEncode << 4;
                else {
                  inputID[inputNum/2] = inputID[inputNum/2] + charEncode;
                  Serial.print(' ');
                }
                even = !even;
                inputNum++;
              }
            }
          }
        }
        if (inputNum == 14) {
          inputID[7] = ibutton.crc8(inputID, 7); // Автоматическое вычисление контрольной суммы введённого ID
          for (byte i=0; i<8; i++) oldID[i] = inputID[i];
        }
        Serial.println(oldID[7], HEX);
        printID();
        break;
      }
    }
  }

  for (byte x = 0; x < 8; x++) newID[x] = oldID[x];
  // Проверяем, приложен ли ключ
  if (!ibutton.search (oldID)) {
    ibutton.reset_search();
    delay(50);
    if (!recoveryMode) return;
  }

    // Режим чтения
  if (!writeMode) {
    digitalWrite(ledPin, HIGH);
    delay(50);
    printID();
    digitalWrite(ledPin, LOW);
  }

  // Режим записи
  if (writeMode) {
    delay(200);
    digitalWrite(ledPin, LOW);
    ibuttonCommand(0x33, 1, 1);
    Serial.print("Old ID: ");
    for (byte x = 0; x < 8; x++) {
      Serial.print(ibutton.read(), HEX);
      Serial.print(' ');
    }
    ibuttonCommand(0xD1, 1, 1);
    // устанавливаем на линии логический 0
    digitalWrite(dataPin, LOW); pinMode(dataPin, OUTPUT); delayMicroseconds(60);
    pinMode(dataPin, INPUT); digitalWrite(dataPin, HIGH); delay(10);
    Serial.print("  New ID: ");
    for (byte x = 0; x < 8; x++) {
      Serial.print(newID[x], HEX);
      Serial.print(' ');
    }
    ibuttonCommand(0xD5, 1, 1);
    Serial.print("Writing... ");
    for (byte x = 0; x < 8; x++) {
      writeByte(newID[x]);
      Serial.print('*');
    }
    Serial.println(F(" OK!"));
    ibuttonCommand(0xD1, 0, 1);
    // устанавливаем на линии логическую 1
    digitalWrite(dataPin, LOW); pinMode(dataPin, OUTPUT); delayMicroseconds(10);
    pinMode(dataPin, INPUT); digitalWrite(dataPin, HIGH); delay(10);
    changeMode();
  }
}


// Отправка команды iButton
void ibuttonCommand(uint8_t command, boolean sk, boolean rs) {
  if (sk) ibutton.skip();
  if (rs) ibutton.reset();
  ibutton.write(command); 
}


// Побайтовая запись нового ID
void writeByte(byte data) {
  for (int data_bit = 0; data_bit < 8; data_bit++) {
    digitalWrite(dataPin, LOW); pinMode(dataPin, OUTPUT);
    if (data & 1) delayMicroseconds(60);
    pinMode(dataPin, INPUT); digitalWrite(dataPin, HIGH);
    delay(10);
    data = data >> 1;
  }
}

Возможности устройства
Чтение ID ключа с последующей записью в перезаписываемую "болванку" (RW1990);
Запись "универсального" ID, заранее заданного в скетче (в данном случае используется ID: 01:FF:FF:FF:FF:FF:FF:2F );
Защита от случайной записи некорректного значения ID;
Восстановление нечитаемых ключей, случайно испорченных при неудачной записи;
Ввод ID вручную в терминале;
Возможность работы без COM-терминала (при наличии источника питания постоянного тока на 5В с USB разъёмом).
Работа с устройством
Устройство можно использовать как с COM-терминалом (предпочтительно), так и без него. Для работы с терминалом на компьютере должны быть установлены драйверы для платы Arduino (FTDI, CH341 или др., в зависимости от того, какой чип установлен на Вашей плате). Если плата удачно программируется в среде разработки Arduino-IDE, значит нужный драйвер в системе уже установлен. Терминал COM-порта можно использовать любой, какой больше нравится, например, монитор порта среды Arduino-IDE или Гипертерминал. Можно и PuTTY). В настройках терминала нужно выбрать виртуальный COM-порт, под которым определилась наша плата, и скорость обмена, выставленную в скетче, в этом примере- 115200).

Итак, подключаем устройство к компьютеру и запускаем терминал COM-порта (Arduino при этом автоматически перезагружается). Светодиод несколько раз мигает в процессе загрузки. Через пару секунд устройство готово к работе, светодиод при этом гаснет, а в терминале выводится сообщение о готовности системы.
Список доступных команд через терминал
d - загрузка в буфер "универсального" ключа (в данном случае: 01:FF:FF:FF:FF:FF:FF:2F);
w - переключение режима чтение/запись;
m - переход в режим ручного ввода ID;
r - переход в режим восстановления нечитаемых ключей;
h - показать справку по командам.

Cчитать ID ключа
Для этого, прикладываем ключ к контактной площадке. Светодиод при этом начинает часто моргать, а в терминале отображается считанный ID, который сохраняется в буфере (переменной oldID ) до тех пор, пока в неё не будет загружен другой ID. Идентификатор состоит из восьми бит, которые отображаются в шестнадцатеричном виде: 01 XX XX XX XX XX XX YY. Здесь первый бит - это Family code, для ключей ibutton он всегда будет равен 1. Если считанный Family code будет отличаться от 1, в терминал будет выведено соответствующее предупреждение и записывать данный ID устройство откажется.
Следующие шесть бит - это, собственно, уникальный идентификатор ключа. А восьмой бит - это, так называемый, "избыточный код" CRC или, другими словами, контрольная сумма, вычисляемая по специальному алгоритму из предыдущих семи бит. Контрольная сумма проверяется, и если её значение не верно, то, опять же, в терминал выводится предупреждение об этом и запись такого ID будет невозможна.
Записать ID в перезаписываемый ключ
В терминале нужно отправить символ "w", либо нажать кнопку на устройстве. При этом зажигается светодиод, что говорит о готовности устройства к записи. Прикладываем записываемый ключ к контактной площадке: светодиод при этом гаснет, а примерно через секунду начинает часто моргать, что говорит о завершении процесса записи и переключении устройства обратно в режим чтения. Если в терминале мы видим, что считывается только что записанный ID, без каких либо предупреждений, значит всё прошло успешно. С таким же успехом можно копировать ключи и без использования терминала, наблюдая только за светодиодом.

Если записываемый ID был некорректный (с неверным Family code, или CRC), в терминал выведется соответствующее сообщение и запись будет отменена. Таким образом, устройство предохраняет ключ от записи в него некорректных данных. Тем не менее, всё же может случиться так, что данные запишутся с ошибками. Такое может произойти, например, если ключ будет недостаточно плотно приложен к контактной площадке при записи данных. Более того, ключ в этом случае может вовсе перестать читаться некоторыми устройствами (включая данный дубликатор), если в первый бит будет записано нулевое значение. А при экспериментах с ключами такое частенько бывает, особенно по неопытности! Так что не зная можно и подумать, что ключик умер.
Восстановления нечитаемого ключа
Нужно перевести устройство в соответствующий режим. Для этого в терминале нужно отправить символ "r", либо включить устройство, удерживая кнопку нажатой. Светодиод начнёт часто моргать, независимо от того, приложен ключ, или нет (для выхода из режима восстановления отправьте символ "r" снова, или пере подключите устройство).
Прикладываем ключ к контактной площадке. Если он читаемый, то его ID считается так же, как и в обычном режиме чтения. Если же ключ не читается, соответственно ничего не произойдёт. Удерживая ключ приложенным, нажимаем кнопку. При этом в ключ принудительно будет записан "универсальный" ID, прописанный в скетче (здесь: 01:FF:FF:FF:FF:FF:FF:2F) либо другой, ранее загруженный в буфер. По окончанию записи устройство вернётся в обычный режим чтения.
Загрузить в буфер универсальный ID
Можно отправив в терминале символ "d", либо просто перезагрузив устройство (он используется по умолчанию, если не был введён какой-либо другой ID).

Кроме всего прочего, в устройстве предусмотрена возможность сделать дубликат ключа, даже не имея под рукой оригинала! Достаточно лишь знать его идентификатор.
Перевод устройства в режим ручного ввода ID
Для этого в терминале нужно отправить символ "m". После этого появляется приглашение ввести ID, либо выйти из ручного режима (по нажатию Esc). После этого можно ввести любой ID (в шестнадцатеричном виде). При этом первый бит (Family code) всегда должен быть равным 1 и программа подставляет его автоматически, а так же, автоматически вычисляет CRC и подставляет в восьмой бит. Таким образом, нам нет необходимости вводить Family code и вычислять контрольную сумму CRC, достаточно ввести только значения битов со второго по седьмой.
В итоге мы имеем вполне функциональное, полезное в хозяйстве устройство за смешные дениги. Теперь скопировать на скорую руку ключик на дежурную болванку можно где угодно, при наличии источника питания на 5В постоянного тока с USB разъёмом!
i love you mxIni Mysql

! ! !


Дим M
Topic author, Администратор
Администратор
Avatar
Дим M
Topic author, Администратор
Администратор
Reputation: 74
Posts: 1197
Joined: 5 Apr 2013
With us: 6 years 2 months

считывание данных с домофонных ключей на Arduino

#2by Дим » 11 Jun 2019, 20:21

Есть ещё простецкая схема и скетч, для считывания данных с домофонных ключей на Arduino. В мониторе порта можно увидеть адрес устройства.
считывания данных с домофонных ключей на Arduino.png
считывание данных с домофонных ключей на Arduino
считывания данных с домофонных ключей на Arduino.png (19.03 KiB) Viewed 47 times

Code: Select all

#include <OneWire.h>
 
/* 
 * test 1-Wire whith DS1990A 
 */
 
OneWire  ds
(10);  // на  digital pin 10
 
void setup
(void) {
  Serial.begin(9600);
}
 
void loop
(void) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
   
  if 
( !ds.search(addr)) {
      Serial.print("No more addresses.\n");
      ds.reset_search();
      return;
  }
   
  Serial
.print("R=");
  for( i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }
 
  if 
( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.print("CRC is not valid!\n");
      return;
  }
   
  if 
( addr[0] != 0x01) {
      Serial.print("Device is not a DS1990A family device.\n");
      return;
  }
  Serial.println();
  ds.reset();
   
  delay
(1000);
}
i love you mxIni Mysql

Дим M
Topic author, Администратор
Администратор
Avatar
Дим M
Topic author, Администратор
Администратор
Reputation: 74
Posts: 1197
Joined: 5 Apr 2013
With us: 6 years 2 months

#3by Дим » 12 Jun 2019, 22:45

Нашел ещё схему дубликатора домофонных ключей на Arduino.
Видео
phpBB [media]
схема
Дубликатор домофонных ключей на Arduino.png
схема дубликатора домофонных ключей на Arduino
Дубликатор домофонных ключей на Arduino.png (337.94 KiB) Viewed 34 times
Подстроечный резистор 10 kOm, настраивается на 2.8 v, только после заливки скетча.

Code: Select all

#include <OneWire.h>
#include "pitches.h"

#define iButtonPin A5      // Линия data ibutton
#define R_Led 2            // RGB Led
#define G_Led 3
#define B_Led 4
#define ACpinGnd 5         // Земля аналогового компаратора Cyfral/Metacom
#define ACpin 6            // Вход аналогового компаратора 3В для Cyfral/Metacom
#define BtnPin 7           // Кнопка переключения режима чтение/запись
#define BtnPinGnd 8        // Земля кнопки переключения режима 
#define speakerPin 9       // Спикер, он же buzzer, он же beeper
#define speakerPinGnd 10    // земля Спикера

OneWire ibutton (iButtonPin); 
byte addr
[8];                             // временный буфер
byte keyID[8];                            // ID ключа для записи
bool readflag = false;                    // флаг сигнализируе, что данные с ключа успечно прочианы в ардуино
bool writeflag = false;                   // режим запись/чтение
bool preBtnPinSt = HIGH;
enum emRWType {TM01, RW1990_1, RW1990_2, TM2004};                            // тип болванки
enum emkeyType {keyUnknown, keyDallas, keyTM2004, keyCyfral, keyMetacom};    // тип оригинального ключа  
emkeyType keyType;

void setup() {
  pinMode(BtnPin, INPUT_PULLUP);                            // включаем чтение и подягиваем пин кнопки режима к +5В
  pinMode(BtnPinGnd, OUTPUT); digitalWrite(BtnPinGnd, LOW); // подключаем второй пин кнопки к земле
  pinMode(speakerPin, OUTPUT);
  pinMode(speakerPinGnd, OUTPUT); digitalWrite(speakerPinGnd, LOW); // подключаем второй пин спикера к земле
  pinMode(ACpin, INPUT);                                            // Вход аналогового компаратора 3В для Cyfral
  pinMode(ACpinGnd, OUTPUT); digitalWrite(ACpinGnd, LOW);           // подключаем второй пин аналогового компаратора Cyfral к земле 
  pinMode(R_Led, OUTPUT); pinMode(G_Led, OUTPUT); pinMode(B_Led, OUTPUT);  //RGB-led
  clearLed();
  digitalWrite(B_Led, HIGH);                                //awaiting of origin key data
  Serial.begin(115200);
  Sd_StartOK();
}

void clearLed(){
  digitalWrite(R_Led, LOW);
  digitalWrite(G_Led, LOW);
  digitalWrite(B_Led, LOW);  
}
//*************** dallas **************
emRWType getRWtype(){    
   byte answer
;
  // TM01 это неизвестный тип болванки, делается попытка записи TM-01 без финализации для dallas или c финализацией под cyfral или metacom
  // RW1990_1 - dallas-совместимые RW-1990, RW-1990.1, ТМ-08, ТМ-08v2 
  // RW1990_2 - dallas-совместимая RW-1990.2
  // TM2004 - dallas-совместимая TM2004 в доп. памятью 1кб
  // пробуем определить RW-1990.1
  ibutton.reset(); ibutton.write(0xD1); // проуем снять флаг записи для RW-1990.1
  ibutton.write_bit(1);                 // записываем значение флага записи = 1 - отключаем запись
  delay(10); pinMode(iButtonPin, INPUT);
  ibutton.reset(); ibutton.write(0xB5); // send 0xB5 - запрос на чтение флага записи
  answer = ibutton.read();
  //Serial.print("\n Answer RW-1990.1: "); Serial.println(answer, HEX);
  if (answer == 0xFE){
    Serial.println(" Type: dallas RW-1990.1 ");
    return RW1990_1;            // это RW-1990.1
  }
  // пробуем определить RW-1990.2
  ibutton.reset(); ibutton.write(0x1D);  // проуем установить флаг записи для RW-1990.2 
  ibutton.write_bit(1);                  // записываем значение флага записи = 1 - включаем запись
  delay(10); pinMode(iButtonPin, INPUT);
  ibutton.reset(); ibutton.write(0x1E);  // send 0x1E - запрос на чтение флага записи
  answer = ibutton.read();
  //Serial.print("\n Answer RW-1990.2: "); Serial.println(answer, HEX);
  if (answer == 0xFE){
    ibutton.reset(); ibutton.write(0x1D); // возвращаем оратно запрет записи для RW-1990.2
    ibutton.write_bit(0);                 // записываем значение флага записи = 0 - выключаем запись
    delay(10); pinMode(iButtonPin, INPUT);
    Serial.println(" Type: dallas RW-1990.2 ");
    return RW1990_2; // это RW-1990.2
  }
  //}
  // пробуем определить TM-2004
  ibutton.reset(); ibutton.write(0x33);                     // посылаем команду чтения ROM для перевода в расширенный 3-х байтовый режим
  for ( byte i=0; i<8; i++) ibutton.read();                 //читаем данные ключа
  ibutton.write(0xAA);                                      // пробуем прочитать регистр статуса для TM-2004    
  ibutton.write(0x00); ibutton.write(0x00);                 // передаем адрес для считывания
  answer = ibutton.read();                                  // читаем CRC комманды и адреса
  //Serial.print("TM2004 CRC: "); Serial.println(answer, HEX);
  byte m1[3] = {0xAA, 0,0};                                 // вычисляем CRC комманды
  if (OneWire::crc8(m1, 3) == answer) {
    answer = ibutton.read();                                  // читаем регистр статуса
    //Serial.print(" status: "); Serial.println(answer, HEX);
    Serial.println(" Type: dallas TM2004");
    ibutton.reset();
    return TM2004; // это Type: TM2004
  }
  ibutton.reset();
  Serial.println(" Type: dallas unknown, trying TM-01! ");
  return TM01;                              // это неизвестный тип DS1990, нужно перебирать алгоритмы записи (TM-01)
}

bool write2iBtnTM2004(){                // функция записи на TM2004
  byte answer; bool result = true;
  ibutton.reset();
  ibutton.write(0x3C);                                      // команда записи ROM для TM-2004    
  ibutton.write(0x00); ibutton.write(0x00);                 // передаем адрес с которого начинается запись
  for (byte i = 0; i<8; i++){
    digitalWrite(R_Led, !digitalRead(R_Led));
    ibutton.write(keyID[i]);
    answer = ibutton.read();
    //if (OneWire::crc8(m1, 3) != answer){result = false; break;}     // crc не верный
    delayMicroseconds(600); ibutton.write_bit(1); delay(50);         // испульс записи
    pinMode(iButtonPin, INPUT);
    Serial.print('*');
    Sd_WriteStep();
    if (keyID[i] != ibutton.read()) { result = false; break;}    //читаем записанный байт и сравниваем, с тем что должно записаться
  } 
  if 
(!result){
    ibutton.reset();
    Serial.println(" The key copy faild");
    Sd_ErrorBeep();
    digitalWrite(R_Led, HIGH);
    return false;    
  
}
  ibutton.reset();
  Serial.println(" The key has copied successesfully");
  Sd_ReadOK();
  delay(500);
  digitalWrite(R_Led, HIGH);
  return true;
}

bool write2iBtnRW1990_1_2_TM01(emRWType rwType){              // функция записи на RW1990.1, RW1990.2, TM-01C(F)
  byte rwCmd, rwFlag = 1;
  switch (rwType){
    case TM01: rwCmd = 0xC1; break;                   //TM-01C(F)
    case RW1990_1: rwCmd = 0xD1; rwFlag = 0; break;  // RW1990.1  флаг записи инвертирован
    case RW1990_2: rwCmd = 0x1D; break;              // RW1990.2
  }
  ibutton.reset(); ibutton.write(rwCmd);       // send 0xD1 - флаг записи
  ibutton.write_bit(rwFlag);                   // записываем значение флага записи = 1 - разрешить запись
  delay(10); pinMode(iButtonPin, INPUT);
  ibutton.reset(); ibutton.write(0xD5);        // команда на запись
  for (byte i = 0; i<8; i++){
    digitalWrite(R_Led, !digitalRead(R_Led));
    if (rwType == RW1990_1) BurnByte(~keyID[i]);      // запись происходит инверсно для RW1990.1
      else BurnByte(keyID[i]);
    Serial.print('*');
    Sd_WriteStep();
  } 
  ibutton
.write(rwCmd);                     // send 0xD1 - флаг записи
  ibutton.write_bit(!rwFlag);               // записываем значение флага записи = 1 - отключаем запись
  delay(10); pinMode(iButtonPin, INPUT);
  digitalWrite(R_Led, LOW);       
  if 
(!dataIsBurningOK()){          // проверяем корректность записи
    Serial.println(" The key copy faild");
    Sd_ErrorBeep();
    digitalWrite(R_Led, HIGH);
    return false;
  }
  Serial.println(" The key has copied successesfully");
  if ((keyType == keyMetacom)||(keyType == keyCyfral)){      //переводим ключ из формата dallas
    ibutton.reset();
    if (keyType == keyCyfral) ibutton.write(0xCA);       // send 0xCA - флаг финализации Cyfral
      else ibutton.write(0xCB);                       // send 0xCA - флаг финализации metacom
    ibutton.write_bit(1);                             // записываем значение флага финализации = 1 - перевезти формат
    delay(10); pinMode(iButtonPin, INPUT);
  }
  Sd_ReadOK();
  delay(500);
  digitalWrite(R_Led, HIGH);
  return true;
}

void BurnByte(byte data){
  for(byte n_bit=0; n_bit<8; n_bit++){ 
    ibutton
.write_bit(data & 1);  
    delay
(5);                        // даем время на прошивку каждого бита до 10 мс
    data = data >> 1;                // переходим к следующему bit
  }
  pinMode(iButtonPin, INPUT);
}

bool dataIsBurningOK(){
  byte buff[8];
  if (!ibutton.reset()) return false;
  ibutton.write(0x33);
  ibutton.read_bytes(buff, 8);
  byte Check = 0;
  for (byte i = 0; i < 8; i++) 
    if 
(keyID[i] == buff[i]) Check++;      // сравниваем код для записи с тем, что уже записано в ключе.
  if (Check != 8) return false;             // если коды совпадают, ключ успешно скопирован
  return true;
}

bool write2iBtn(){
  int Check = 0, CheckSumNewKey = 0;
  Serial.print("The new key code is: ");
  for (byte i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX); Serial.print(":");
    CheckSumNewKey += keyID[i];  
    if 
(keyID[i] == addr[i]) Check++;    // сравниваем код для записи с тем, что уже записано в ключе.
  }
  if (Check == 8) {                     // если коды совпадают, ничего писать не нужно
    digitalWrite(R_Led, LOW); 
    Serial
.println(" it is the same key. Writing in not needed.");
    Sd_ErrorBeep();
    digitalWrite(R_Led, HIGH);
    delay(500);
    return false;
  }
  byte rwType = getRWtype(); // определяем тип RW-1990.1 или 1990.2 или TM-01
  Serial.print("\n Burning iButton ID: ");
  if (rwType == TM2004) return write2iBtnTM2004();  //шьем TM2004
    else return write2iBtnRW1990_1_2_TM01(rwType); //пробуем прошить другие форматы
}

bool readiBtn(){
  for (byte i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX); Serial.print(":");
    keyID[i] = addr[i];                               // копируем прочтенный код в ReadID
  }
  if (addr[0] == 0x01) {                         // это ключ формата dallas
    keyType = keyDallas;
    if (getRWtype() == TM2004) {
      //Serial.println(" Type: dallas TM2004");
      keyType = keyTM2004;
    } //else Serial.println(" Type: dallas RW1990.x");
    if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      Sd_ErrorBeep();
      digitalWrite(B_Led, HIGH);
      return false;
    }
    Sd_ReadOK();
    return true;
  }
  if ((addr[0]>>4) == 0x0E) Serial.println(" Type: unknown family dallas. May be cyfral in dallas key.");
    else Serial.println(" Type: unknown family dallas");
  keyType = keyUnknown;
  return true;
}

//************ Cyfral ***********************
unsigned long pulseAComp(bool pulse, unsigned long timeOut = 20000){  // pulse HIGH or LOW
  bool AcompState;
  unsigned long tStart = micros();
  do {
    AcompState = ACSR & _BV(ACO);  // читаем флаг компаратора
    if (AcompState == pulse) {
      tStart = micros();
      do {
        AcompState = ACSR & _BV(ACO);  // читаем флаг компаратора
        if (AcompState != pulse) return (long)(micros() - tStart);  
      
} while ((long)(micros() - tStart) < timeOut);
      return 0;                                                 //таймаут, импульс не вернуся оратно
    }             // end if
  } while ((long)(micros() - tStart) < timeOut);
  return 0;
}

void ACsetOn(){
  ADCSRA &= ~(1<<ADEN);      // выключаем ADC
  ADCSRB |= (1<<ACME);        //включаем AC
  ADMUX = 0b00000101;        // подключаем к AC Линию A5
}

bool read_cyfral(byte* buf, byte CyfralPin){
  unsigned long ti; byte j = 0;
  digitalWrite(CyfralPin, LOW); pinMode(CyfralPin, OUTPUT);  //отклчаем питание от ключа
  delay(200);
  ACsetOn();    //analogComparator.setOn(0, CyfralPin); 
  pinMode(CyfralPin, INPUT_PULLUP);  // включаем пиание Cyfral
  for (byte i = 0; i<36; i++){    // чиаем 36 bit
    ti = pulseAComp(HIGH);
    if ((ti == 0) || (ti > 200)) break;                      // not Cyfral
    //if ((ti > 20)&&(ti < 50)) bitClear(buf[i >> 3], 7-j);
    if ((ti > 50) && (ti < 200)) bitSet(buf[>> 3], 7-j);
    j++; if (j>7) j=0; 
  
}
  if (ti == 0) return false;
  if ((buf[0] >> 4) != 0b1110) return false;   /// not Cyfral
  byte test;
  for (byte i = 1; i<4; i++){
    test = buf[i] >> 4;
    if ((test != 1)&&(test != 2)&&(test != 4)&&(test != 8)) return false;
    test = buf[i] & 0x0F;
    if ((test != 1)&&(test != 2)&&(test != 4)&&(test != 8)) return false;
  }
  return true;
}

bool searchCyfral(){
  for (byte i = 0; i < 8; i++) addr[i] = 0;
  bool rez = read_cyfral(addr, iButtonPin);
  if (!rez) return false; 
  keyType 
= keyCyfral;
  for (byte i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX); Serial.print(":");
    keyID[i] = addr[i];                               // копируем прочтенный код в ReadID
  }
  Serial.println(" Type: Cyfral ");
  return true;  
}
//*************************************

void loop() {
  bool BtnPinSt = digitalRead(BtnPin);
  bool BtnClick;
  if ((BtnPinSt == LOW) &&(preBtnPinSt!= LOW)) BtnClick = true;
    else BtnClick = false;
  preBtnPinSt = BtnPinSt;
  if ((Serial.read() == 't') || BtnClick) {  // переключаель режима чтение/запись
    if (readflag == true) {
      writeflag = !writeflag;
      clearLed(); 
      if 
(writeflag) digitalWrite(R_Led, HIGH);
        else digitalWrite(G_Led, HIGH);
      Serial.print("Writeflag = "); Serial.println(writeflag);  
    
} else {
      clearLed();   
      Sd_ErrorBeep
();
      digitalWrite(B_Led, HIGH);
    }
  }
  if ((!writeflag) && (searchCyfral())) {  // запускаем поиск cyfral
    digitalWrite(G_Led, LOW);
    Sd_ReadOK();
    readflag = true;
    clearLed(); digitalWrite(G_Led, HIGH);
  }
  //goto l1;
  if (!ibutton.search(addr)) {  // запускаем поиск dallas
    ibutton.reset_search();
    delay(200);
    return;
  }
  if (!writeflag){ 
    digitalWrite
(G_Led, LOW);
    readflag = readiBtn();       // чиаем ключ dallas
    if (readflag) {
      clearLed(); digitalWrite(G_Led, HIGH);
    }
  }else{
    if (readflag == true) write2iBtn();
      else {          // сюда испонение не должно попасть
        clearLed();
        Sd_ErrorBeep();
        digitalWrite(B_Led, HIGH);
    }
  }
  l1:
  delay(300);
}


//***************** зуки****************
void Sd_ReadOK() {  // звук ОК
  for (int i=400; i<6000; i=i*1.5) { tone(speakerPin, i); delay(20); }
  noTone(speakerPin);
}

void Sd_WriteStep(){  // звук "очередной шаг"
  for (int i=2500; i<6000; i=i*1.5) { tone(speakerPin, i); delay(10); }
  noTone(speakerPin);
}

void Sd_ErrorBeep() {  // звук "ERROR"
  for (int j=0; j <3; j++){
    for (int i=1000; i<2000; i=i*1.1) { tone(speakerPin, i); delay(10); }
    delay(50);
    for (int i=1000; i>500; i=i*1.9) { tone(speakerPin, i); delay(10); }
    delay(50);
  }
  noTone(speakerPin);
}

void Sd_StartOK(){   // звук "Успешное включение"
  tone(speakerPin, NOTE_A7); delay(100);
  tone(speakerPin, NOTE_G7); delay(100);
  tone(speakerPin, NOTE_E7); delay(100); 
  tone
(speakerPin, NOTE_C7); delay(100);  
  tone
(speakerPin, NOTE_D7); delay(100); 
  tone
(speakerPin, NOTE_B7); delay(100); 
  tone
(speakerPin, NOTE_F7); delay(100); 
  tone
(speakerPin, NOTE_C7); delay(100);
  noTone(speakerPin); 
}

pitches.h

Code: Select all

/*************************************************
 * Public Constants
 *************************************************/

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978     
i love you mxIni Mysql

Дим M
Topic author, Администратор
Администратор
Avatar
Дим M
Topic author, Администратор
Администратор
Reputation: 74
Posts: 1197
Joined: 5 Apr 2013
With us: 6 years 2 months

#4by Дим » 13 Jun 2019, 19:43

phpBB [media]

Собрал и я себе дубликатор домофонных ключей на Arduino. Работает нормально, ключи дублирует. Только кнопка для записи срабатывает не всегда с первого раза. Но да это не критично, индикатор всё равно сигнализирует что сейчас происходит. Синий - режим ожидания, зелёный - считывание и красный это запись.
i love you mxIni Mysql


  • Similar Topics
    Replies
    Views
    Last post

Return to “Программирование”

Who is online (over the past 5 minutes)

Users browsing this forum: 1 guest