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

Дим M
Topic author, Администратор
Администратор
Avatar
Дим M
Topic author, Администратор
Администратор
Posts: 1464
Joined: 5 Apr 2013
With us: 8 years 1 month

#1by Дим » 29 Nov 2020, 19:33

Сделал себе дубликатор по данной схеме:
Дубликатор домофонных ключей  ibutton и rfid на ардуино.png
Дубликатор домофонных ключей ibutton и rfid на ардуино
Дубликатор домофонных ключей ibutton и rfid на ардуино.png (391.36 KiB) Viewed 621 times

Скетч

Code: Select all

/*
 Скетч к проекту "Копировальщик ключей для домофона RFID с OLED дисплеем и хранением 8 ключей в память EEPROM"
 Аппаратная часть построена на Arduino Nano
 Исходники на GitHub: https://github.com/AlexMalov/EasyKeyDublicatorRFID_OLED/
 Автор: МЕХАТРОН DIY, AlexMalov, 2019
 v 3.2 fix cyfral bug
*/

// Настройки
#include <OneWire.h>
#include <OneWireSlave.h>
#include "pitches.h"
#include <EEPROM.h>
#include <OLED_I2C.h> 
OLED myOLED(SDA, SCL); //создаем экземпляр класса OLED с именем myOLED
extern uint8_t SmallFont[];
extern uint8_t BigNumbers[];
#include "GyverEncoder.h"
#include "TimerOne.h"

//settings
#define rfidUsePWD 0        // ключ использует пароль для изменения
#define rfidPWD 123456      // пароль для ключа
#define rfidBitRate 2       // Скорость обмена с rfid в kbps

//pins
#define iButtonPin A3 // Линия data ibutton
#define iBtnEmulPin A1 // Линия эмулятора ibutton
#define Luse_Led 13        // Светодиод лузы
#define R_Led 2            / / RGB Led
#define G_Led 3
#define B_Led 4
#define ACpin 6            // Вход Ain0 аналогового компаратора 0.1В для EM-Marie 
#define speakerPin 12       // Спикер, он же buzzer, он же beeper
#define FreqGen 11         // генератор 125 кГц
#define CLK 8              // s1 энкодера
#define DT 9               // s2 энкодера
#define BtnPin 10          // Кнопка переключения режима чтение/запись

Encoder enc1(CLK, DT, BtnPin);
OneWire ibutton (iButtonPin);
OneWireSlave iBtnEmul(iBtnEmulPin);       //Эмулятор iButton для BlueMode
byte maxKeyCount;                         // максимальное кол-во ключей, которое влазит в EEPROM, но не > 20
byte EEPROM_key_count;                    // количество ключей 0..maxKeyCount, хранящихся в EEPROM
byte EEPROM_key_index = 0;                // 1..EEPROM_key_count номер последнего записанного в EEPROM ключа  
byte addr[8];                             // временный буфер
byte keyID[8];                            // ID ключа для записи
byte rfidData[5];                         // значащие данные frid em-marine
byte halfT;                               // полупериод для метаком
enum emRWType {rwUnknown, TM01, RW1990_1, RW1990_2, TM2004, T5557, EM4305};               // тип болванки
enum emkeyType {keyUnknown, keyDallas, keyTM2004, keyCyfral, keyMetacom, keyEM_Marine};    // тип оригинального ключа  
emkeyType keyType;
enum emMode {md_empty, md_read, md_write, md_blueMode};               // режим раоты копировальщика
emMode copierMode = md_empty;

void OLED_printKey(byte buf[8], byte msgType = 0){
  String st;
  switch (msgType){
    case 0: st = "The key " + String(EEPROM_key_index) + " of " + String(EEPROM_key_count) + " in ROM"; break;      
    case 1
: st = "Hold the Btn to save";  break; 
    case 3
: st = "The key " + String(indxKeyInROM(buf)) + " exists in ROM";  break;   
  
}
  myOLED.clrScr();
  myOLED.print(st, 0, 0);  
  st 
= "";
  for (byte i = 0; i < 8; i++) st += String(buf[i], HEX) +":";
  myOLED.print(st, 0, 12);
  st = "Type ";
  switch (keyType){
    case keyDallas: st += "Dallas wire"; break;      
    case keyCyfral
: st += "Cyfral wire";  break;  
    case keyMetacom
: st += "Metakom wire"; break;             
    case keyEM_Marine
: st += "EM_Marine rfid"; break;
    case keyUnknown: st += "Unknown"; break;
  }
  myOLED.print(st, 0, 24);
  myOLED.update();
}

void OLED_printError(String st, bool err = true){
  myOLED.clrScr();
  if (err) myOLED.print(F("Error!"), 0, 0);
    else myOLED.print(F("OK"), 0, 0);
  myOLED.print(st, 0, 12);  
  myOLED
.update();
}

void setup() {
  pinMode(Luse_Led, OUTPUT); digitalWrite(Luse_Led, HIGH); //поменять на LOW
  myOLED.begin(SSD1306_128X32); //инициализируем дисплей
  pinMode(BtnPin, INPUT_PULLUP);                            // включаем чтение и подягиваем пин кнопки режима к +5В
  pinMode(speakerPin, OUTPUT);
  pinMode(ACpin, INPUT);                                    // Вход аналогового компаратора 3В для Cyfral 
  pinMode(R_Led, OUTPUT); pinMode(G_Led, OUTPUT); pinMode(B_Led, OUTPUT);  //RGB-led
  clearLed();
  pinMode(FreqGen, OUTPUT);                               
  Serial
.begin(115200);
  myOLED.clrScr();                                          //Очищаем буфер дисплея.
  myOLED.setFont(SmallFont);                                //Перед выводом текста необходимо выбрать шрифт
  myOLED.print(F("Hello, read a key..."), LEFT, 0);
  char st[16] = {98, 121, 32, 77, 69, 88, 65, 84, 80, 79, 72, 32, 68, 73, 89, 0};
  myOLED.print(st, LEFT, 24);
  myOLED.update();
  Sd_StartOK();
  EEPROM_key_count = EEPROM[0];
  maxKeyCount = EEPROM.length() / 8 - 1; if (maxKeyCount > 20) maxKeyCount = 20;
  if (EEPROM_key_count > maxKeyCount) EEPROM_key_count = 0;
  if (EEPROM_key_count != 0 ) {
    EEPROM_key_index = EEPROM[1];
    Serial.print(F("Read key code from EEPROM: "));
    EEPROM_get_key(EEPROM_key_index, keyID);
    for (byte i = 0; i < 8; i++) {
      Serial.print(keyID[i], HEX); Serial.print(F(":"));  
    
}
    Serial.println();
    delay(3000);
    OLED_printKey(keyID);
    copierMode = md_read;
    digitalWrite(G_Led, HIGH);
  } else {
    myOLED.print(F("ROM has no keys yet."), 0, 12);
    myOLED.update();  
  
}
  enc1.setTickMode(AUTO);
  enc1.setType(TYPE2);
  enc1.setDirection(REVERSE);         // NORM / REVERSE
  Timer1.initialize(1000);            // установка таймера на каждые 1000 микросекунд (= 1 мс)
  Timer1.attachInterrupt(timerIsr);   // запуск таймера
  digitalWrite(Luse_Led, !digitalRead(Luse_Led)); 
}

void timerIsr() {   // прерывание таймера для энкодера
  enc1.tick();     
}

void clearLed(){
  digitalWrite(R_Led, LOW);
  digitalWrite(G_Led, LOW);
  digitalWrite(B_Led, LOW);  
}

byte indxKeyInROM(byte buf[]){ //возвращает индекс или ноль если нет в ROM
  byte buf1[8]; bool eq = true;
  for (byte j = 1; j<=EEPROM_key_count; j++){  // ищем ключ в eeprom. 
    EEPROM.get(j*sizeof(buf1), buf1);
    for (byte i = 0; i < 8; i++) 
      if 
(buf1[i] != buf[i]) { eq = false; break;}
    if (eq) return j;
    eq = true;
  }
  return 0;
}

bool EPPROM_AddKey(byte buf[]){
  byte buf1[8]; byte indx;
  indx = indxKeyInROM(buf);                 // ищем ключ в eeprom. Если находим, то не делаем запись, а индекс переводим в него
  if ( indx != 0) { 
    EEPROM_key_index 
= indx;
    EEPROM.update(1, EEPROM_key_index);
    return false; 
  
}
  if (EEPROM_key_count <= maxKeyCount) EEPROM_key_count++;
  if (EEPROM_key_count < maxKeyCount) EEPROM_key_index = EEPROM_key_count;
    else EEPROM_key_index++;
  if (EEPROM_key_index > EEPROM_key_count) EEPROM_key_index = 1;
  Serial.println(F("Adding to EEPROM"));
  for (byte i = 0; i < 8; i++) {
    buf1[i] = buf[i];
    Serial.print(buf[i], HEX); Serial.print(F(":"));  
  
}
  Serial.println();
  EEPROM.put(EEPROM_key_index*sizeof(buf1), buf1);
  EEPROM.update(0, EEPROM_key_count);
  EEPROM.update(1, EEPROM_key_index);
  return true;
}

void EEPROM_get_key(byte EEPROM_key_index1, byte buf[8]){
  byte buf1[8];
  int address = EEPROM_key_index1*sizeof(buf1);
  if (address > EEPROM.length()) return;
  EEPROM.get(address, buf1);
  for (byte i = 0; i < 8; i++) buf[i] = buf1[i];
  keyType = getKeyType(buf1);
}

emkeyType getKeyType(byte* buf){
  if (buf[0] == 0x01) return keyDallas;                       // это ключ формата dallas
  if ((buf[0] >> 4) == 0b0001) return keyCyfral;
  if ((buf[0] >> 4) == 0b0010) return keyMetacom;
  if ((buf[0] == 0xFF) && vertEvenCheck(buf)) return keyEM_Marine;
  return keyUnknown;
}

//*************** 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(F("\n Answer RW-1990.1: ")); Serial.println(answer, HEX);
  if (answer == 0xFE){
    Serial.println(F(" 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();
  if (answer == 0xFE){
    ibutton.reset(); ibutton.write(0x1D); // возвращаем оратно запрет записи для RW-1990.2
    ibutton.write_bit(0);                 // записываем значение флага записи = 0 - выключаем запись
    delay(10); pinMode(iButtonPin, INPUT);
    Serial.println(F(" 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 комманды и адреса
  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(F(" Type: dallas TM2004"));
    ibutton.reset();
    return TM2004; // это Type: TM2004
  }
  ibutton.reset();
  Serial.println(F(" 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(F(" The key copy faild"));
    OLED_printError(F("The key copy faild"));
    Sd_ErrorBeep();
    digitalWrite(R_Led, HIGH);
    return false;    
  
}
  ibutton.reset();
  Serial.println(F(" The key has copied successesfully"));
  OLED_printError(F("The key has copied"), false);
  Sd_ReadOK();
  delay(2000);
  digitalWrite(R_Led, HIGH);
  return true;
}

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

void BurnByteMC(byte buf[8]){
  byte j = 0;
  for(byte n_bit = 0; n_bit < 36; n_bit++){ 
    ibutton
.write_bit(((~buf[n_bit>>3]) >> (7-j) ) & 1);  
    delay
(5);                        // даем время на прошивку каждого бита 5 мс
    j++;
    if (> 7) j = 0;
  }
  pinMode(iButtonPin, INPUT);
}

void convetr2MC(byte buff[8]){
  byte data;
  for (byte i = 0; i < 5; i++){
    data = ~buff[i];
    buff[i] = 0;
    for (byte j = 0; j < 8; j++) 
      if 
( (data>>j)&1) bitSet(buff[i], 7-j);
  }
  buff[4] &= 0xf0;  buff[5] = 0; buff[6] = 0; buff[7] = 0;
}

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

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

bool searchIbutton(){
  if (!ibutton.search(addr)) { 
    ibutton
.reset_search(); 
    return false
;
  }  
  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) keyType = keyTM2004;
    if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println(F("CRC is not valid!"));
      OLED_printError(F("CRC is not valid!"));
      Sd_ErrorBeep();
      digitalWrite(B_Led, HIGH);
      return false;
    }
    return true;
  }
  switch (addr[0]>>4){
    case 1: Serial.println(F(" Type: May be cyfral in dallas key")); break;      
    case 2
: Serial.println(F(" Type: May be metacom in dallas key"));  break;  
    case 3
: Serial.println(F(" Type: unknown family dallas")); break;             
  
}
  keyType = keyUnknown;
  return true;
}

//************ Cyfral ***********************
unsigned long pulseACompA(bool pulse, byte Average = 80, unsigned long timeOut = 1500){  // pulse HIGH or LOW
  bool AcompState;
  unsigned long tEnd = micros() + timeOut;
  do {
    ADCSRA |= (1<<ADSC);
    while(ADCSRA & (<< ADSC)); // Wait until the ADSC bit has been cleared
    if (ADCH > 200) return 0;
    if (ADCH > Average) AcompState = HIGH;  // читаем флаг компаратора
      else AcompState = LOW;
    if (AcompState == pulse) {
      tEnd = micros() + timeOut;
      do {
          ADCSRA |= (1<<ADSC);
          while(ADCSRA & (<< ADSC)); // Wait until the ADSC bit has been cleared
        if (ADCH > Average) AcompState = HIGH;  // читаем флаг компаратора
          else AcompState = LOW;
        if (AcompState != pulse) return (unsigned long)(micros() + timeOut - tEnd);  
      
} while (micros() < tEnd);
      return 0;                                                 //таймаут, импульс не вернуся оратно
    }             // end if
  } while (micros() < tEnd);
  return 0;
}

void ADCsetOn(){
  ADMUX = (ADMUX&0b11110000) | 0b0011 | (1<<ADLAR);// (1 << REFS0);          // подключаем к AC Линию A3 ,  левое выравние, измерение до Vcc
  ADCSRB = (ADCSRB & 0b11111000) | (1<<ACME);                // источник перезапуска ADC FreeRun, включаем мультиплексор AC
  ADCSRA = (ADCSRA & 0b11111000) |0b011 | (1<<ADEN) | (1<<ADSC);// | (1<<ADATE);      // 0b011 делитель скорости ADC, // включаем ADC и запускаем ADC и autotriger ADC 
}

void ACsetOn(){
  ACSR |= 1<<ACBG;                            // Подключаем ко входу Ain0 1.1V для Cyfral/Metacom
  ADCSRA &= ~(1<<ADEN);                       // выключаем ADC
  ADMUX = (ADMUX&0b11110000) | 0b0011;        // подключаем к AC Линию A3
  ADCSRB |= 1<<ACME;                          // включаем мультиплексор AC
}

bool read_cyfral(byte* buf, byte CyfralPin){
  unsigned long ti; byte i=0, j = 0, k = 0;
  analogRead(iButtonPin);
  ADCsetOn(); 
  byte aver 
= calcAverage();
  unsigned long tEnd = millis() + 30;
  do{
    ti = pulseACompA(HIGH, aver);
    if ((ti == 0) || (ti > 260) || (ti < 10)) {= 0; j=0; k = 0; continue;}
    if ((< 3) && (ti > halfT)) {= 0; j = 0; k = 0; continue;}      //контроль стартовой последовательности 0b0001
    if ((== 3) && (ti < halfT)) continue;      
    if 
(ti > halfT) bitSet(buf[>> 3], 7-j);
      else if (> 3) k++; 
    if 
((> 3) && ((i-3)%== 0) ){        //начиная с 4-го бита проверяем количество нулей каждой строки из 4-и бит
      if (!= 1) {for (byte n = 0; n < (>> 3)+2; n++) buf[n] = 0; i = 0; j = 0; k = 0; continue;}        //если нулей больше одной - начинаем сначала 
      k = 0; 
    
}
    j++; if (j>7) j=0;
    i++;
  } while ((millis() < tEnd) && (< 36));
  if (< 36) return false;
  return true;
}

bool searchCyfral(){
  byte buf[8];
  for (byte i = 0; i < 8; i++) {addr[i] =0; buf[i] = 0;}
  if (!read_cyfral(addr, iButtonPin)) return false;
  if (!read_cyfral(buf, iButtonPin)) return false;
  for (byte i = 0; i < 8; i++) 
    if 
(addr[i] != buf[i]) 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(F(" Type: Cyfral "));
  return true;  
}

byte calcAverage(){
  unsigned int sum = 127; byte preADCH = 0, j = 0; 
  for 
(byte i = 0; i<255; i++) {
    ADCSRA |= (1<<ADSC);
    delayMicroseconds(10);
    while(ADCSRA & (<< ADSC)); // Wait until the ADSC bit has been cleared
    sum += ADCH;
  }
  sum = sum >> 8;
  unsigned long tSt = micros();
  for (byte i = 0; i<255; i++) {
    delayMicroseconds(4);
    ADCSRA |= (1<<ADSC);
    while(ADCSRA & (<< ADSC)); // Wait until the ADSC bit has been cleared
    if (((ADCH > sum)&&(preADCH < sum)) | ((ADCH < sum)&&(preADCH > sum))) {
      j++;
      preADCH = ADCH;
    }   
  
}
  halfT = (byte)((micros() - tSt) / j);
  return (byte)sum;
}

bool read_metacom(byte* buf, byte MetacomPin){
  unsigned long ti; byte i = 0, j = 0, k = 0;
  analogRead(iButtonPin);
  ADCsetOn();
  byte aver = calcAverage();
  unsigned long tEnd = millis() + 30;
  do{
    ti = pulseACompA(LOW, aver);
    if ((ti == 0) || (ti > 500)) {= 0; j=0; k = 0; continue;}
    if ((== 0) && (ti+30 < (halfT<<1))) continue;      //вычисляем период;
    if ((== 2) && (ti > halfT)) {= 0; j = 0;  continue;}      //вычисляем период;
    if (((== 1) || (== 3)) && (ti < halfT)) {= 0; j = 0; continue;}      //вычисляем период;
    if (ti < halfT) {   
      bitSet
(buf[>> 3], 7-j);
      if (> 3) k++;                             // считаем кол-во единиц
    }
    if ((> 3) && ((i-3)%== 0) ){        //начиная с 4-го бита проверяем контроль четности каждой строки из 8-и бит
      if (& 1) { for (byte n = 0; n < (>> 3)+1; n++) buf[n] = 0; i = 0; j = 0;  k = 0; continue;}              //если нечетно - начинаем сначала
      k = 0;
    }   
    j
++; if (j>7) j=0;
    i++;
  }  while ((millis() < tEnd) && (< 36));
  if (< 36) return false;
  return true;
}

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

//**********EM-Marine***************************
bool vertEvenCheck(byte* buf){        // проверка четности столбцов с данными
  byte k;
  k = 1&buf[1]>>+ 1&buf[1]>>+ 1&buf[2]>>+ 1&buf[3]>>+ 1&buf[3]>>+ 1&buf[4]>>+ 1&buf[4] + 1&buf[5]>>+ 1&buf[6]>>+ 1&buf[6]>>+ 1&buf[7]>>4;
  if (k&1) return false;
  k = 1&buf[1]>>+ 1&buf[1] + 1&buf[2]>>+ 1&buf[3]>>+ 1&buf[3]>>+ 1&buf[4]>>+ 1&buf[5]>>+ 1&buf[5]>>+ 1&buf[6]>>+ 1&buf[6] + 1&buf[7]>>3;
  if (k&1) return false;
  k = 1&buf[1]>>+ 1&buf[2]>>+ 1&buf[2]>>+ 1&buf[3]>>+ 1&buf[3] + 1&buf[4]>>+ 1&buf[5]>>+ 1&buf[5]>>+ 1&buf[6]>>+ 1&buf[7]>>+ 1&buf[7]>>2;
  if (k&1) return false;
  k = 1&buf[1]>>+ 1&buf[2]>>+ 1&buf[2]>>+ 1&buf[3]>>+ 1&buf[4]>>+ 1&buf[4]>>+ 1&buf[5]>>+ 1&buf[5] + 1&buf[6]>>+ 1&buf[7]>>+ 1&buf[7]>>1;
  if (k&1) return false;
  if (1&buf[7]) return false;
  //номер ключа, который написан на корпусе
  rfidData[0] = (0b01111000&buf[1])<<| (0b11&buf[1])<<| buf[2]>>6;
  rfidData[1] = (0b00011110&buf[2])<<| buf[3]>>4;
  rfidData[2] = buf[3]<<| (0b10000000&buf[4])>>| (0b00111100&buf[4])>>2;
  rfidData[3] = buf[4]<<| (0b11100000&buf[5])>>| 0b1111&buf[5];
  rfidData[4] = (0b01111000&buf[6])<<| (0b11&buf[6])<<| buf[7]>>6;
  return true;
}

byte ttAComp(unsigned long timeOut = 7000){  // pulse 0 or 1 or -1 if timeout
  byte AcompState, AcompInitState;
  unsigned long tEnd = micros() + timeOut;
  AcompInitState = (ACSR >> ACO)&1;               // читаем флаг компаратора
  do {
    AcompState = (ACSR >> ACO)&1;                 // читаем флаг компаратора
    if (AcompState != AcompInitState) {
      delayMicroseconds(1000/(rfidBitRate*4));    // 1/4 Period on 2 kBps = 125 mks 
      AcompState = (ACSR >> ACO)&1;               // читаем флаг компаратора      
      delayMicroseconds(1000/(rfidBitRate*2));    // 1/2 Period on 2 kBps = 250 mks 
      return AcompState;  
    
}
  } while (micros() < tEnd);
  return 2;                                             //таймаут, компаратор не сменил состояние
}

bool readEM_Marie(byte* buf){
  unsigned long tEnd = millis() + 50;
  byte ti; byte j = 0, k=0;
  for (int i = 0; i<64; i++){    // читаем 64 bit
    ti = ttAComp();
    if (ti == 2)  break;         //timeout
    if ( ( ti == 0 ) && ( i < 9)) {  // если не находим 9 стартовых единиц - начинаем сначала
      if (millis() > tEnd) { ti=2; break;}  //timeout
      i = -1; j=0; continue;
    }
    if ((> 8) && (< 59)){     //начиная с 9-го бита проверяем контроль четности каждой строки
      if (ti) k++;                // считаем кол-во единиц
      if ( (i-9)%== 4 ){        // конец строки с данными из 5-и бит, 
        if (& 1) {              //если нечетно - начинаем сначала
          i = -1; j = 0; k = 0; continue; 
        
}
        k = 0;
      }
    }
    if (ti) bitSet(buf[>> 3], 7-j);
      else bitClear(buf[>> 3], 7-j);
    j++; if (j>7) j=0; 
  
}
  if (ti == 2) return false;         //timeout
  return vertEvenCheck(buf);
}

void rfidACsetOn(){
  //включаем генератор 125кГц
  pinMode(FreqGen, OUTPUT);
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);  //Вкючаем режим Toggle on Compare Match на COM2A (pin 11) и счет таймера2 до OCR2A
  TCCR2B = _BV(WGM22) | _BV(CS20);                                // Задаем делитель для таймера2 = 1 (16 мГц)
  OCR2A = 63;                                                    // 63 тактов на период. Частота на COM2A (pin 11) 16000/64/2 = 125 кГц, Скважнось COM2A в этом режиме всегда 50% 
  OCR2B = 31;                                                     // Скважность COM2B 32/64 = 50%  Частота на COM2A (pin 3) 16000/64 = 250 кГц
  // включаем компаратор
  ADCSRB &= ~(1<<ACME);           // отключаем мультиплексор AC
  ACSR &= ~(1<<ACBG);             // отключаем от входа Ain0 1.1V
}

bool searchEM_Marine( bool copyKey = true){
  byte gr = digitalRead(G_Led);
  bool rez = false;
  rfidACsetOn();            // включаем генератор 125кГц и компаратор
  delay(6);                //13 мс длятся переходные прцессы детектора 
  if (!readEM_Marie(addr)) {
    if (!copyKey) TCCR2A &=0b00111111;              //Оключить ШИМ COM2A (pin 11)
    digitalWrite(G_Led, gr);
    return rez;
  }
  rez = true;
  keyType = keyEM_Marine;
  for (byte i = 0; i<8; i++){
    if (copyKey) keyID[i] = addr [i];
    Serial.print(addr[i], HEX); Serial.print(":");
  }
  Serial.print(F(" ( id "));
  Serial.print(rfidData[0]); Serial.print(" key ");
  unsigned long keyNum = (unsigned long)rfidData[1]<<24 | (unsigned long)rfidData[2]<<16 | (unsigned long)rfidData[3]<<| (unsigned long)rfidData[4];
  Serial.print(keyNum);
  Serial.println(F(") Type: EM-Marie "));
  if (!copyKey) TCCR2A &=0b00111111;              //Оключить ШИМ COM2A (pin 11)
  digitalWrite(G_Led, gr);
  return rez;
}

void TxBitRfid(byte data){
  if (data & 1) delayMicroseconds(54*8); 
    else delayMicroseconds
(24*8);
  rfidGap(19*8);                       //write gap
}

void TxByteRfid(byte data){
  for(byte n_bit=0; n_bit<8; n_bit++){
    TxBitRfid(data & 1);
    data = data >> 1;                   // переходим к следующему bit
  }
}

void rfidGap(unsigned int tm){
  TCCR2A &=0b00111111;                //Оключить ШИМ COM2A 
  delayMicroseconds(tm);
  TCCR2A |= _BV(COM2A0);              // Включить ШИМ COM2A (pin 11)      
}

bool T5557_blockRead(byte* buf){
  byte ti; byte j = 0, k=0;
  for (int i = 0; i<33; i++){                           // читаем стартовый 0 и 32 значащих bit
    ti = ttAComp(2000);
    if (ti == 2)  break;                                //timeout
    if ( ( ti == 1 ) && ( i == 0)) { ti=2; break; }     // если не находим стартовый 0 - это ошибка
    if (> 0){                                         //начиная с 1-го бита пишем в буфер
      if (ti) bitSet(buf[(i-1) >> 3], 7-j);
        else bitClear(buf[(i-1) >> 3], 7-j);
      j++; if (j>7) j=0;
    }
  }
  if (ti == 2) return false;                           //timeout
  return true;
}

bool sendOpT5557(byte opCode, unsigned long password = 0, byte lockBit = 0, unsigned long data = 0, byte blokAddr = 1){
  TxBitRfid(opCode >> 1); TxBitRfid(opCode & 1); // передаем код операции 10
  if (opCode == 0b00) return true;
  // password
  TxBitRfid(lockBit & 1);               // lockbit 0
  if (data != 0){
    for (byte i = 0; i<32; i++) {
      TxBitRfid((data>>(31-i)) & 1);
    }
  }
  TxBitRfid(blokAddr>>2); TxBitRfid(blokAddr>>1); TxBitRfid(blokAddr & 1);      // адрес блока для записи
  delay(4);                                                                     // ждем пока пишутся данные
  return true;
}

bool write2rfidT5557(byte* buf){
  bool result; unsigned long data32;
  delay(6);
  for (byte k = 0; k<2; k++){                                       // send key data
    data32 = (unsigned long)buf[+ (k<<2)]<<24 | (unsigned long)buf[+ (k<<2)]<<16 | (unsigned long)buf[+ (k<<2)]<<| (unsigned long)buf[+ (k<<2)];
    rfidGap(30 * 8);                                                 //start gap
    sendOpT5557(0b10, 0, 0, data32, k+1);                            //передаем 32 бита ключа в blok k
    Serial.print('*'); delay(6);
  }
  delay(6);
  rfidGap(30 * 8);                  //start gap
  sendOpT5557(0b00);
  delay(4);
  result = readEM_Marie(addr);
  TCCR2A &=0b00111111;              //Оключить ШИМ COM2A (pin 11)
  for (byte i = 0; i < 8; i++)
    if (addr[i] != keyID[i]) { result = false; break; }
  if (!result){
    Serial.println(F(" The key copy faild"));
    OLED_printError(F("The key copy faild"));
    Sd_ErrorBeep();
  } else {
    Serial.println(F(" The key has copied successesfully"));
    OLED_printError(F("The key has copied"), false);
    Sd_ReadOK();
    delay(2000);
  }
  digitalWrite(R_Led, HIGH);
  return result;  
}

emRWType getRfidRWtype(){
  unsigned long data32, data33; byte buf[4] = {0, 0, 0, 0}; 
  rfidACsetOn
();                // включаем генератор 125кГц и компаратор
  delay(13);                    //13 мс длятся переходные процессы детектора
  rfidGap(30 * 8);              //start gap
  sendOpT5557(0b11, 0, 0, 0, 1); //переходим в режим чтения Vendor ID 
  if (!T5557_blockRead(buf)) return rwUnknown; 
  data32 
= (unsigned long)buf[0]<<24 | (unsigned long)buf[1]<<16 | (unsigned long)buf[2]<<| (unsigned long)buf[3];
  delay(4);
  rfidGap(20 * 8);          //gap  
  data33 = 0b00000000000101001000000001000000 | (rfidUsePWD << 4);   //конфиг регистр 0b00000000000101001000000001000000
  sendOpT5557(0b10, 0, 0, data33, 0);   //передаем конфиг регистр
  delay(4);
  rfidGap(30 * 8);          //start gap
  sendOpT5557(0b11, 0, 0, 0, 1); //переходим в режим чтения Vendor ID 
  if (!T5557_blockRead(buf)) return rwUnknown; 
  data33 
= (unsigned long)buf[0]<<24 | (unsigned long)buf[1]<<16 | (unsigned long)buf[2]<<| (unsigned long)buf[3];
  sendOpT5557(0b00, 0, 0, 0, 0);  // send Reset
  delay(6);
  if (data32 != data33) return rwUnknown;    
  Serial
.print(F(" The rfid RW-key is T5557. Vendor ID is "));
  Serial.println(data32, HEX);
  return T5557;
}

bool write2rfid(){
  bool Check = true;
  if (searchEM_Marine(false)) {
    for (byte i = 0; i < 8; i++)
      if (addr[i] != keyID[i]) { Check = false; break; }  // сравниваем код для записи с тем, что уже записано в ключе.
    if (Check) {                                          // если коды совпадают, ничего писать не нужно
      digitalWrite(R_Led, LOW); 
      Serial
.println(F(" it is the same key. Writing in not needed."));
      OLED_printError(F("It is the same key"));
      Sd_ErrorBeep();
      digitalWrite(R_Led, HIGH);
      delay(1000);
      return false;
    }
  }
  emRWType rwType = getRfidRWtype(); // определяем тип T5557 (T5577) или EM4305
  if (rwType != rwUnknown) Serial.print(F("\n Burning rfid ID: "));
  switch (rwType){
    case T5557: return write2rfidT5557(keyID); break;                    //пишем T5557
    //case EM4305: return write2rfidEM4305(keyID); break;                  //пишем EM4305
    case rwUnknown: break;
  }
  return false;
}


void SendEM_Marine(byte* buf){ 
  TCCR2A 
&=0b00111111; // отключаем шим 
  digitalWrite(FreqGen, LOW);
  //FF:A9:8A:A4:87:78:98:6A
  delay(20);
  for (byte k = 0; k<10; k++){
    for (byte i = 0; i<8; i++){
      for (byte j = 0; j<8; j++){
        if (& (buf[i]>>(7-j))) {
          pinMode(FreqGen, INPUT);
          delayMicroseconds(250);
          pinMode(FreqGen, OUTPUT); 
          delayMicroseconds
(250);
        } else {
          pinMode(FreqGen, OUTPUT);
          delayMicroseconds(250);
          pinMode(FreqGen, INPUT);
          delayMicroseconds(250);
        }
      }
    }
   // delay(1);
  }  
}

void SendDallas(byte* buf){
/*  iBtnEmul.init(buf);
  //iBtnEmul.waitForRequest(false);
  unsigned long tStart = millis();
  do {
    if (!iBtnEmul.waitReset(10) ) continue;
    if (!iBtnEmul.presence() ) continue;
    if (iBtnEmul.recvAndProcessCmd() ) break;
  } while (millis() < 200 + tStart);  */
}

void BM_SendKey(byte* buf){
  switch (keyType){
    case keyEM_Marine: SendEM_Marine(buf); break;
    default: SendDallas(buf); break;
  }
}

unsigned long stTimer = millis();
void loop() {
  char echo = Serial.read();
  if (echo == 'e'){
    myOLED.print(F("EEPROM cleared success!"), 0, 0);
    Serial.println(F("EEPROM cleared"));
    EEPROM.update(0, 0); EEPROM.update(1, 0);
    EEPROM_key_count = 0; EEPROM_key_index = 0;
    Sd_ReadOK();
    myOLED.update();
  }
  if ((echo == 't') || enc1.isClick()) {  // переключаель режима чтение/запись
    switch (copierMode){
      case md_empty: Sd_ErrorBeep(); break;
      case md_read: copierMode = md_write; clearLed(); digitalWrite(R_Led, HIGH);  break;
      case md_write: copierMode = md_blueMode; clearLed(); digitalWrite(B_Led, HIGH); 
        digitalWrite
(Luse_Led, !digitalRead(Luse_Led)); break;
      case md_blueMode: copierMode = md_read; clearLed(); digitalWrite(G_Led, HIGH); 
        digitalWrite
(Luse_Led, !digitalRead(Luse_Led)); break;
    }
    OLED_printKey(keyID);
    Serial.print(F("Mode: ")); Serial.println(copierMode);
    Sd_WriteStep();
  }
  if (enc1.isLeft() && (EEPROM_key_count > 0)){       //при повороте энкодера листаем ключи из eeprom
    EEPROM_key_index--;
    if (EEPROM_key_index < 1) EEPROM_key_index = EEPROM_key_count;
    EEPROM_get_key(EEPROM_key_index, keyID);
    OLED_printKey(keyID);
    Sd_WriteStep();
  }
  if (enc1.isRight() && (EEPROM_key_count > 0)){
    EEPROM_key_index++;
    if (EEPROM_key_index > EEPROM_key_count) EEPROM_key_index = 1;
    EEPROM_get_key(EEPROM_key_index, keyID);
    OLED_printKey(keyID);
    Sd_WriteStep();            
  
}
  if ((copierMode != md_empty) && enc1.isHolded()){     // Если зажать кнопкку - ключ сохранися в EEPROM
    if (EPPROM_AddKey(keyID)) {
      OLED_printError(F("The key saved"), false);
      Sd_ReadOK();
      delay(1000); 
    
}
      else Sd_ErrorBeep();
    OLED_printKey(keyID);  
  
}   
  if 
(millis() - stTimer < 100) return; //задержка в 100 мс
  stTimer = millis();
  switch (copierMode){
      case md_empty: case md_read: 
        if 
(searchCyfral() || searchMetacom() || searchEM_Marine() || searchIbutton() ){     // запускаем поиск cyfral, затем поиск EM_Marine, затем поиск dallas
          //keyID[0] = 0xFF; keyID[1] = 0xA9; keyID[2] =  0x8A; keyID[3] = 0xA4; keyID[4] = 0x87; keyID[5] = 0x78; keyID[6] = 0x98; keyID[7] = 0x6A;
          Sd_ReadOK();
          copierMode = md_read;
          digitalWrite(G_Led, HIGH);
          if (indxKeyInROM(keyID) == 0) OLED_printKey(keyID, 1);
            else OLED_printKey(keyID, 3);
          } 
        break
;
      case md_write:
        if (keyType == keyEM_Marine) write2rfid();
          else write2iBtn(); 
        break
;
      case md_blueMode: 
        BM_SendKey
(keyID);
        break;
    } //end switch
}

//***************** звуки****************
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); 
Всё работает нормально, только катушка из Китая не захотела работать. Хотя в какой-то момент и начала считывать но потом опять тишина. Встретился в интернете ещё один проект, там автор катушку сделал из дросселя. Я тоже сделал так же. Купил дроссель (уже не помню точно на сколько) примерно на 500 uH отмотал некоторое количество витков и всё ок. Только плохо срабатывает в корпусе (стенки толстоватые). В месте соприкосновения катушки - дросселя и крышки корпуса паяльником сделал не большую выямку. Тем самым как бы утончил корпус. Более мене работает. Но потом попался дроссель с номиналом 957 uH, не точно конечно так как измерения делал самодельным измерителем индуктивности на Arduino. На нем опытным путем (постоянно делая замеры вольтажа) отмотал примерно метр проволоки и получил 395 uH. Для этого была собрана схема на макетке на которой и производил свои опыты.
i love you mxIni Mysql

! ! !


sogs
Avatar
sogs
Posts: 1
Joined: 6 Feb 2021
With us: 3 months 3 days

Вопрос про возможности устройства

#2by sogs » 6 Feb 2021, 18:37

Заинтересовало для повторения .У вас в теме за 11 июня 2019 в скетче есть восстановление нечитаемых ключей, случайно испорченных при неудачной записи.А у этого устройства имеется такая возможность? :smile:

Дим M
Topic author, Администратор
Администратор
Avatar
Дим M
Topic author, Администратор
Администратор
Posts: 1464
Joined: 5 Apr 2013
With us: 8 years 1 month

#3by Дим » 6 Feb 2021, 19:39

sogs wrote:имеется такая возможность?
Тут нет.
i love you mxIni Mysql

Deniskyn M
Рядовой
Рядовой
Avatar
Deniskyn M
Рядовой
Рядовой
Posts: 11
Joined: 11 Feb 2021
With us: 2 months 26 days

#4by Deniskyn » 27 Apr 2021, 11:22

Знающие, подскажите что поменять в скетче что бы на дисплейчике ключ отображался в виде 7167268, а не в 255:129:128:3:54:173:149:38: ???


  • Similar Topics
    Replies
    Views
    Last post

Return to “Прочая электроника”

Who is online (over the past 5 minutes)

Users browsing this forum: 7 guests