Как сделать копию ключа для домофона в домашних условиях
С помощью Ардуино можно сделать дома копию ключа для домофона за 15 минут, если, к примеру, мастерская закрыта, а ключ нужен срочно.
Инструкция по чтению и записи ключа iButton (1-wire) с помощью Arduino
Нам понадобится:
- Ардуино (или совместимая плата);
- персональный компьютер с Arduino IDE или иной средой разработки;
- ключ для домофона типа iButton или 1-wire, копию которого нужно сделать;
- ключ-болванка для создания «клона» оригинального ключа (покупаем здесь);
- 1 резистор сопротивлением 2,2 кОм (вот отличный набор резисторов самых популярных номиналов);
- макетная плата (breadboard);
- соединительные провода.
1Схема подключения ключа к Arduinoпо однопроводному интерфейсу
Каждый ключ для домофона имеет свой номер – именно этот номер и служит идентификатором ключа. Именно по номеру ключа домофон решает – свой или чужой. Поэтому алгоритм копирования такой: сначала нужно узнать номер разрешённого ключа, а затем присвоить этот номер другому ключу – клону. Для домофона нет разницы, был приложен оригинальный ключ или его копия. Сверив номер со своей базой данных разрешённых номеров, он откроет дверь.
Ключи для домофона, которые мы будем подключать к Arduino (их иногда называют iButton или Touch Memory), считываются и записываются по однопроводному интерфейсу 1-wire. Поэтому схема подключения очень проста. Нам нужны лишь пара проводов и подтягивающий резистор номиналом 2,2 кОм. Схема соединений показана на рисунке.

Собранная схема может выглядеть примерно так:

2Считывание идентификатора ключа iButton с помощью Arduino
Для работы с интерфейсом 1-wire существуют готовые библиотеки для Ардуино. Можно воспользоваться, например, этой. Скачиваем архив и распаковываем в папку /libraries/, расположенную в каталоге Arduino IDE. Теперь мы можем очень просто работать с данным протоколом.
Загрузим в Ардуино стандартным способом этот скетч:
Скетч чтения ключа iButton с помощью Arduino (разворачивается)
#include <OneWire.h>
OneWire iButton(10); // создаём объект 1-wire на 10 выводе
void setup (void) {
Serial.begin(9600);
}
void loop(void) {
delay(1000); // задержка 1 сек
byte addr[8]; // массив для хранения данных ключа
if ( !iButton.search(addr) ) { // если ключ не приложен
Serial.println("No key connected..."); // сообщаем об этом
return; // и прерываем программу
}
Serial.print("Key : ");
for(int i=0; i<8; i++) {
Serial.print(addr[i], HEX); // выводим побайтно данные ключа
Serial.print(" ");
}
Serial.println();
iButton.reset(); // сброс ключа
}
Данный скетч показывает номер ключа для домофона, который подключён к схеме. Это то, что нам и нужно сейчас: мы должны узнать номер ключа, копию которого хотим сделать. Подключим Ардуино к компьютеру. Запустим монитор последовательного порта: Инструменты Монитор последовательного порта (или сочетание клавиш Ctrl+Shift+M).
Теперь подключим ключ к схеме. Монитор порта покажет номер ключа. Запомним этот номер.

А вот какой обмен происходит на однопроводной линии при чтении идентификатора ключа (подробнее – далее):

На рисунке, конечно, не видны все детали реализации. Поэтому в конце статьи я прикладываю временную диаграмму в формате *.logicdata , снятую с помощью логического анализатора и программы Saleae Logic Analyzer и открываемую ей же. Программа бесплатная и скачивается с официального сайта Saleae. Чтобы открыть файл *.logicdata нужно запустить программу, нажать сочетание Ctrl+O или в меню Options (расположено вверху справа) выбрать пункт Open capture / setup.
3Запись идентификатора ключа Dallasс помощью Arduino
Теперь напишем скетч для записи данных в память ключа iButton.
Скетч записи ключа iButton с помощью Arduino (разворачивается)
#include <OneWire.h> // подключаем библиотеку
const int pin = 10; // объявляем номер пина
OneWire iButton(pin); // объявляем объект OneWire на 10-ом пине
// номер ключа, который мы хотим записать в iButton:
byte key_to_write[] = { 0x01, 0xF6, 0x75, 0xD7, 0x0F, 0x00, 0x00, 0x9A };
void setup(void) {
Serial.begin(9600);
pinMode(pin, OUTPUT);
}
void loop(void) {
delay(1000); // задержка на 1 сек
iButton.reset(); // сброс устройства 1-wire
delay(50);
iButton.write(0x33); // отправляем команду "чтение"
byte data[8]; // массив для хранения данных ключа
iButton.read_bytes(data, 8); // считываем данные приложенного ключа, 8х8=64 бита
if ( OneWire::crc8(data, 7) != data[7] ) { // проверяем контрольную сумму приложенного ключа
Serial.println("CRC error!"); // если CRC не верна, сообщаем об этом
return; // и прерываем программу
}
if (data[0] & data[1] & data[2] & data[3] & data[4] & data[5] & data[6] & data[7] == 0xFF) {
return; // если ключ не приложен к считывателю, прерываем программу и ждём, пока будет приложен
}
Serial.print("Start programming..."); // начало процесса записи данных в ключ
for (int i = 0; i < 8; i++) {
// формирование 4-х байт для записи в ключ - см. рис.4 из datasheet для подробностей
iButton.reset(); // сброс ключа
data[0] = 0x3C; // отправляем команду "копировать из буфера в ПЗУ"
data[1] = i; // указываем байт для записи
data[2] = 0;
data[3] = key_to_write[i];
iButton.write_bytes(data, 4); // записываем i-ый байт в ключ
uint8_t b = iButton.read(); // считываем байт из ключа
if (OneWire::crc8(data, 4) != b) { // при ошибке контрольной суммы
Serial.println("Error while programming!"); // сообщаем об этом
return; // и отменяем запись ключа
}
send_programming_impulse(); // если всё хорошо, посылаем импульс для записи i-го байта в ключ
}
Serial.println("Success!"); // сообщение об успешной записи данных в ключ
}
// Инициализация записи данных в ключ-таблетку iButton:
void send_programming_impulse() {
digitalWrite(pin, HIGH);
delay(60);
digitalWrite(pin, LOW);
delay(5);
digitalWrite(pin, HIGH);
delay(50);
}
Не забудьте задать номер своего оригинального ключа в массиве key_to_write, который мы узнали ранее.
Загрузим этот скетч в Arduino. Откроем монитор последовательного порта (Ctrl+Shift+M). Подключим к схеме ключ, который будет клоном оригинального ключа. О результате программирования монитор последовательного порта выведет соответствующее сообщение.
Если данный скетч не сработал, попробуйте заменить код после Serial.print("Start programming...") и до конца функции loop() на следующий:
Дополнительный скетч записи ключа iButton с помощью Arduino (разворачивается)
delay (200);
iButton.skip();
iButton.reset();
iButton.write(0x33); // чтение текущего номера ключа
Serial.print("ID before write:");
for (byte i=0; i<8; i++){
Serial.print(' ');
Serial.print(iButton.read(), HEX);
}
Serial.print("\n");
iButton.skip();
iButton.reset();
iButton.write(0xD1); // команда разрешения записи
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
delayMicroseconds(60);
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
delay(10);
// выведем ключ, который собираемся записать:
Serial.print("Writing iButton ID: ");
for (byte i=0; i<8; i++) {
Serial.print(key_to_write[i], HEX);
Serial.print(" ");
}
Serial.print("\n");
iButton.skip();
iButton.reset();
iButton.write(0xD5); // команда записи
for (byte i=0; i<8; i++) {
writeByte(key_to_write[i]);
Serial.print("*");
}
Serial.print("\n");
iButton.reset();
iButton.write(0xD1); // команда выхода из режима записи
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
delayMicroseconds(10);
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
delay(10);
Serial.println("Success!");
delay(10000);
Здесь функция writeByte() будет следующей:
int writeByte(byte data) {
int data_bit;
for(data_bit=0; data_bit<8; data_bit++) {
if (data & 1) {
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
delayMicroseconds(60);
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
delay(10);
} else {
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
delay(10);
}
data = data >> 1;
}
return 0;
}
Временную диаграмму работы скетча записи идентификатора ключа показывать бессмысленно, т.к. она длинная и не поместится на рисунке. Однако файл *.logicdata для программы логического анализатора прикладываю в конце статьи.
Ключи для домофона бывают разных типов. Данный код подойдёт не для всех ключей, а только для RW1990 или RW1990.2. Программирование ключей других типов может привести к выходу ключей из строя!
При желании можно переписать программу для ключа другого типа. Для этого воспользуйтесь техническим описанием Вашего типа ключа (datasheet) и изменить скетч в соответствии с описанием. Скачать datasheet для ключей iButton можно в приложении к статье.
Кстати, некоторые современные домофоны читают не только идентификатор ключа, но и другую информацию, записанную на оригинальном ключе. Поэтому сделать клон, скопировав только номер, не получится. Нужно полностью копировать данные ключа.
4Описание однопроводного интерфейса 1-Wire
Давайте чуть глубже познакомимся с интерфейсом One-wire. По организации он похож на интерфейс I2C: в нём также должно присутствовать ведущее устройство (master), которое инициирует обмен, а также одно или несколько ведомых устройств (slave). Все устройства подключены к одной общей шине. Устройства iButton – всегда ведомые. В качестве мастера чаще всего выступает микроконтроллер или ПК. Скорость передачи данных составляет 16,3 кбит/сек. Шина в состоянии ожидания находится в логической "1" (HIGH). В данном протоколе предусмотрены всего 5 типов сигналов:
- импульс сброса (master)
- импульс присутствия (slave)
- запись бита "0" (master)
- запись бита "1" (master)
- чтение бита (master)
1) Инициализация
Инициализация заключается в том, что ведущий выставляет условие сброса RESET (на время от 480 мкс или более опускает линию в "0", а затем отпускает её, и за счёт подтягивающего резистора линия поднимается в состояние "1"), а ведомый не позднее чем через 60 мкс после этого должен подтвердить присутствие, также опустив линию в "0" на 60…240 мкс и затем освободив её:

2) Команды работы с ПЗУ
Если после импульса инициализации не пришёл сигнал подтверждения, мастер повторяет опрос шины. Если сигнал подтверждения пришёл, то мастер понимает, что на шине есть устройство, которое готово к обмену, и посылает ему одну из четырёх 8-битных команд работы с ПЗУ:
| Название | Команда | Назначение |
|---|---|---|
| Чтение (Read ROM) | 0x33 | Мастер считывает 64 первых битов iButton, в которых содержатся: 8 бит кода семейства (*), 48 бит серийного номера и 8 бит контрольной суммы. |
| Совпадение (Match ROM) | 0x55 | Обращение к определённому устройству с известным 64-битным номером. |
| Поиск (Search ROM) | 0xF0 | Позволяет определить все 64-битные номера ведомых устройств, подключённых к шине. |
| Пропуск (Skip ROM) | 0xCC | Позволяет сэкономить время обмена данными с ключом благодаря тому, что мастер пропускает проверку серийного номера. Не рекомендуется к использованию в ситуации, когда на линии присутствуют несколько ведомых. |
(*) Кстати, семейств устройств iButton существует довольно много, некоторые из них перечислены в таблице ниже.
Коды семейств устройств типа iButton (разворачивается)
| Код семейства | Устройства iButton | Описание |
|---|---|---|
| 0x01 | DS1990A, DS1990R, DS2401, DS2411 | Уникальный серийный номер-ключ |
| 0x02 | DS1991 | Мультиключ, 1152-битная защищённая EEPROM |
| 0x04 | DS1994, DS2404 | 4 кб NV RAM + часы, таймер и будильник |
| 0x05 | DS2405 | Одиночный адресуемый ключ |
| 0x06 | DS1993 | 4 кб NV RAM |
| 0x08 | DS1992 | 1 кб NV RAM |
| 0x09 | DS1982, DS2502 | 1 кб PROM |
| 0x0A | DS1995 | 16 кб NV RAM |
| 0x0B | DS1985, DS2505 | 16 кб EEPROM |
| 0x0C | DS1996 | 64 кб NV RAM |
| 0x0F | DS1986, DS2506 | 64 кб EEPROM |
| 0x10 | DS1920, DS1820, DS18S20, DS18B20 | Датчик температуры |
| 0x12 | DS2406, DS2407 | 1 кб EEPROM + двухканальный адресуемый ключ |
| 0x14 | DS1971, DS2430A | 256 бит EEPROM и 64 бита PROM |
| 0x1A | DS1963L | 4 кб NV RAM + счётчик циклов записи |
| 0x1C | DS28E04-100 | 4 кб EEPROM + двухканальный адресуемый ключ |
| 0x1D | DS2423 | 4 кб NV RAM + внешний счётчик |
| 0x1F | DS2409 | Двухканальный адресуемый ключ с возможностью коммутации на возвратную шину |
| 0x20 | DS2450 | Четырёхканальный АЦП |
| 0x21 | DS1921G, DS1921H, DS1921Z | Термохронный датчик с функцией сбора данных |
| 0x23 | DS1973, DS2433 | 4 кб EEPROM |
| 0x24 | DS1904, DS2415 | Часы реального времени |
| 0x26 | DS2438 | Датчик температуры, АЦП |
| 0x27 | DS2417 | Часы реального времени с прерыванием |
| 0x29 | DS2408 | Двунаправленный 8-разрядный порт ввода/вывода |
| 0x2C | DS2890 | Одноканальный цифровой потенциометр |
| 0x2D | DS1972, DS2431 | 1 кб EEPROM |
| 0x30 | DS2760 | Датчик температуры, датчик тока, АЦП |
| 0x37 | DS1977 | 32 кб защищённой паролем EEPROM |
| 0x3A | DS2413 | Двухканальный адресуемый коммутатор |
| 0x41 | DS1922L, DS1922T, DS1923, DS2422 | Термохронные и гигрохронные датчики высокого разрешения с функцией сбора данных |
| 0x42 | DS28EA00 | Цифровой термометр с программируемым разрешением, возможностью работать в режиме подключения к последовательному каналу и программируемыми портами ввода/вывода |
| 0x43 | DS28EC20 | 20 кб EEPROM |
Данные передаются последовательно, бит за битом. Передачу каждого бита инициирует ведущее устройство. При записи ведущий опускает линию к нулю и удерживает её. Если время удерживания линии равно 1…15 мкс, значит записывается бит "1". Если время удерживания от 60 мкс и выше – записывается бит "0".
Чтение битов также инициируется мастером. В начале чтения каждого бита мастер устанавливает низкий уровень на шине. Если ведомое устройство хочет передать "0", оно удерживает шину в состоянии LOW на время от 60 до 120 мкс, а если хочет передать "1", то на время примерно 15 мкс. После этого ведомый отпускает линию, и за счёт подтягивающего резистора она возвращается в состояние HIGH.
Вот так, например, выглядит временная диаграмма команды поиска Search ROM (0xF0). Красным цветом на диаграмме отмечены команды записи битов. Обратите внимание на порядок следования битов при передаче по 1-Wire: старший бит справа, младший – слева.

Далее, если предшествующей командой подразумевается работа с ППЗУ (чтение и запись из перезаписываемой памяти ключа Dallas), то мастер передаёт команду работы с ППЗУ.
3) Команды работы с ППЗУ
Прежде чем рассматривать команды для работы с ППЗУ iButton, необходимо пару слов сказать о структуре памяти ключа. Память разделена на 4 равных участка: три из них предназначены для хранения трёх уникальных ключей, а четвёртый – для временного хранения данных. Этот временный буфер служит своеобразным черновиком, где данные готовятся для записи ключей.

Для работы с ППЗУ существуют 6 команд:
| Название | Команда | Назначение |
|---|---|---|
| Записать во временный буфер (Write Scratchpad) | 0x96 | Используется для записи данных во временный буфер (scratchpad). |
| Прочитать из временного буфера (Read Scratchpad) | 0x69 | Используется для чтения данных из временного буфера. |
| Копировать из временного буфера (Copy Scratchpad) | 0x3C | Используется для передачи данных, подготовленных во временном буфере, в выбранный ключ. |
| Записать пароль ключа (Write Password) | 0x5A | Используется для записи пароля и уникального идентификатора выбранного ключа (одного из трёх). |
| Записать ключ (Write SubKey) | 0x99 | Используется для непосредственной записи данных в выбранный ключ (минуя временный буфер). |
| Прочитать ключ (Read SubKey) | 0x66 | Используется для чтения данных выбранного ключа. |
4) Передача данных
Более подробно и с примерами низкоуровневая работа с протоколом 1-Wire описана в этой статье.
5Возможные ошибки при компиляции скетча
1) Если при компиляции скетча возникнет ошибка WConstants.h: No such file or directory #include "WConstants.h", то, как вариант, следует в файле OneWire.cpp заменить первый блок после комментариев на следующий:
#include <OneWire.h>
#include <Arduino.h>
extern "C" {
#include <avr/io.h>
#include <pins_arduino.h>
}
2) Если при компиляции появляется ошибка class OneWire has no member named read_bytes,то найдите и попробуйте использовать другую библиотеку для работы с интерфейсом OneWire.
Скачать вложения:
- Временная диаграмма чтения ключа iButton (2053 Скачиваний)
- Временная диаграмма записи ключа iButton (1826 Скачиваний)
- Техническое описание (datasheet) DS1996 (1591 Скачиваний)
- Техническое описание (datasheet) DS1991 (1664 Скачиваний)
- Техническое описание (datasheet) DS1992/DS1993 (1836 Скачиваний)
- Техническое описание (datasheet) DS1990A (1765 Скачиваний)
Поблагодарить автора:
Поделиться
Похожие материалы (по тегу)
2 комментарии
-
Slava 11.10.2018 17:43 КомментироватьОшибка в скетче
byte key_to_write[] = { 0x01, 0xF6, 0x75, 0xD7, 0x0F, 0x00 0x00, 0x9A }; - запятая
byte key_to_write[] = { 0x01, 0xF6, 0x75, 0xD7, 0x0F, 0x00, 0x00, 0x9A }; -


