Нашёл на одном форуме данный скетч. Но проблема в том что отображается всё на английском ( Помогите сделать отображение на русском. И ещё там база ключей не вся активирована не смог сам активировать (
Спойлер
/*
Скетч для копирования ключей DS1990 на базе Arduino NANO. Специально для https://4pda.ru/forum/index.php?showtopic=953401
Схема версии 3 очень простая, привела меня в восторг. Но лично мне не хватало в программной реализации пары мелочей.
Свою доработанную версию я назвал 3.1, т.к. она является просто небольшой доработкой версии 3. Скетч версии 3.1
отличается от версии 3 только наличием монитора порта, добавлением более понятного вывода номера ключа на экран и
удалёнными “лишними” блоками кода. А именно, я прибил вычисление CRC для вывода на экран (всё равно нигде его отдельно
не выводим), закомментированную часть кода, которая была написана автором явно не для экрана 1602. Кроме того, я добавил
комментарии, мне так приятнее смотреть на код. Ещё я заменил в схеме резистор 1 кОм на 2.2 кОм, так у меня лучше пишет ключи.
Английскую версию скетча я не делал по той простой причине, что этот скетч прекрасно работает с экранчиками 1602, в которых
отсутствуют кириллические символы. Всё благодаря прекрасной библиотеке LCD_1602_RUS_ALL.
Подключение LCD дисплея по IIC:
GND-GND
+5V-VCC
A4-SDA
A5-SCL
Если во время компиляции ругается на то, что невозможно найти arduino.h, то в файле
/Arduino/libraries/liquidcrystalrus_i2c/LiquidCrystalRus_I2C.cpp
Нужно заменить строку:
#include <arduino.h>
на
#include <Arduino.h>
*/
#define _LCD_TYPE 1
#include <OneWire.h> // Библиотека
#include <LCD_1602_RUS_ALL.h> // Библиотека
LCD_1602_RUS <LiquidCrystal_I2C> lcd(0x27, 16, 2); // Адрес Lcd дисплея 16х2
#define pin 10 // D10: пин данных (центральный) для подлючения лузы iButton (зелёный провод у лузы DS9092)
OneWire ibutton (pin);
byte OldID[8];
byte addr[8];
byte ReadID[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
byte bOut;
byte iSelN = 0xFF;
int iSize = 22;
int iDef = 30;
//массив универсальных ключей из темы
byte UniKey[22][8] =
{
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0x00}, // - Univer 1F
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F, 0xFF, 0x00}, // - Univer 2F
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x9B}, // - UK-1 Metakom 2003
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, // - UK-2 Vizit – код универсального ключа, для Vizit
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D}, // - UK-3 Cyfral
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F}, // - Стандартный универсальный ключ
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}, // - Обычный
{0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x19, 0xFF}, // - Отлично работает на старых домофонах
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x7E, 0x88}, // - Cyfral, Metakom
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x7E, 0x00}, // - Cyfral,Metakom
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, // - Открываает 98% Metakom и некоторые Cyfral
{0x01, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00}, // - домофоны Cyfral + фильтр и защита
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}, // - Metakom
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xA0}, // - Metakom 95%
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, // - домофоны KeyMan
{0x01, 0xBE, 0x40, 0x11, 0x0A, 0x00, 0x00, 0x1D}, // - проверен работает Vizit иногда KeyMan
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x00, 0x6F}, // - домофоны Vizit - до 99%
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0x00}, // - Vizit 99%
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, // - домофоны Форвард
{0x01, 0xA9, 0xE4, 0x3C, 0x09, 0x00, 0x00, 0x00}, // - домофоны Eltis - до 90%
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, // - проверен работает
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, // - проверен работает
//{0x01, 0x2C, 0x7A, 0x0F, 0xA0, 0x00, 0x00, 0x4A}, // - ???
//{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // - домофоны Cyfral 70%
//{0x01, 0x6F, 0x2E, 0x88, 0x8A, 0x00, 0x00, 0x4D}, // - Открывать что-то должен
//{0x01, 0x71, 0xA8, 0x75, 0x0F, 0x00, 0x00, 0xE9}, // - Vizit 55%
//{0x11, 0xBE, 0x40, 0x11, 0x5B, 0x00, 0x00, 0xCD}, // - Vizit 50%
//{0x0F, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0x9E}, // - Vizit 50%
};
//идентификаторы унив ключей для отображения
String NameKey[22] = {“Uni_1F”, “Uni_2F”, “UK1 Met”, “UK2 Viz”, “UK3 Cyf”, “Std”, “Std2”, “Std_Old”, “CyfMet1”, “CyfMet2”, “CyfMet3”,“Cyf_Flt”, “Met_1”, “Met_2”, “KeyMan”, “KeyMViz”, “Vizit1”, “Vizit2”, “Forward”, “Eltis”, “Wrk_1”, “Wrk_2”};
#define TIME_STEP 10 //шаг измерения времени нажатия кнопки
#define TIME_WAIT 1000 //шаг измерения времени нажатия кнопки
#define BUTTON_LONG_PRESS_TIME 7000 //время длинного нажатия кнопки
#define BUTTON_MIDDLE_PRESS_TIME 3000 //время длинного нажатия кнопки
#define BUTTON_LSHORT_PRESS_TIME 500 //время короткого нажатия кнопки
#define BUTTON_SHORT_PRESS_TIME 100 //время короткого нажатия кнопки
//физическое состояние кнопки
enum ButtonResult {
buttonNotPress, //код если кнопка не нажата
buttonShortPress, //код короткого нажатия
buttonLShortPress, //код короткого нажатия
buttonMiddlePress, //код среднего нажатия
buttonLongPress //код длинного нажатия
};
const int buttonPin = 2; // Назначаем пин D2 на кнопку
const int ledPin = 13; // Пин светодиода (Плюс) D13. Если используется светодиод в лузе DS9092, то белый провод. Дублирует светодиод на Ардуинке.
int buttonState = 0; // Переменная, в которой хранится состояние кнопки
bool bWriteFlag = false; // Не пишем содержимое массива readID в таблетку, когда флаг равен 0
bool bReadFlag = true; // Вытаскиваем из таблетки номер в массив readID, если этот флаг равен 0
bool bFlagErr = false;
bool bCopy = false;
int iButtonPress;
void setup() { // Функция инициализации, выполняется однократно при запуске Ардуинки
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
lcd.init(); // Инициализируем дисплей 16x2
lcd.backlight(); // Включаем подсветку дисплея 16х2
lcd.setCursor(1,0); // Устанавливаем курсор в 4 символ 1 строки
LCD_Start();
Serial.begin(9600); // Инициализируем монитор порта на скорости 9600
Serial.println(); // новая строка в порт для красоты
Serial.println(F(“Инициализация успешно завершена”)); // Отправляем тестовую строку в монитор порта
Serial.println(F(“Читаем униерсальный ключ”));
if (iDef>= 0 && iDef < iSize - 1){
fMoveArray (ReadID, UniKey[iDef]);
NameKey[iDef] += “*”;
iSelN = iDef;
}
PrnByte(ReadID,0);
Serial.println();
delay(500);
}
//---------------------------
//сброс ардуино
void(* resetFunc) (void) = 0;
void loop() {
//обработка нажатия кнопки
switch(get_button()){
case buttonLShortPress:{
if (!bCopy){break;}
}
case buttonMiddlePress:{
Serial.println(F(“Button middle pressed”));
Serial.println ();
Serial.println (F("Нажата кнопка, готов к записи "));
if (!fCompareArray(ReadID, ReadID, true)){
bReadFlag = false; // Ставим флаг, чтобы не читать из таблетки в массив ReadID перед записью
bWriteFlag = true; // Ставим флаг, чтобы писать в таблетку содержимое масива readID
}
else{
Serial.println(F("К записи подан пустой код "));
PrnByte(ReadID,0);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F(" Blank code"));
lcd.setCursor(0,1);
lcd.print(F("Nothing to write"));
delay(1500);
LCD_Start();
}
break;
}
case buttonShortPress:{
Serial.println(F("Button short pressed"));
SelectUni ();
break;
}
case buttonLongPress:{
Serial.println(F("Button long pressed"));
lcd.clear(); // Очищаем экран и начинаем отображение информации о номере ключа
lcd.setCursor(0,0);
lcd.print(F("Restart!!!"));
delay(1000);
resetFunc();
break;
}
case buttonNotPress:break;
}
if (!bWriteFlag && (Serial.read() != ‘w’)) { // Если НЕ установлен флаг на запись в таблетку
if (!ibutton.search (addr)) { // Проверка: а может таблетка не обнаружена?
ibutton.reset_search();
delay(50);
return; // если нет таблетки, то выходим из loop
}
if (bReadFlag){// Пишем считанный ключ в массив ReadID, если не стоит флаг запрета раньше был прочитан дугой
if (!fCompareArray(ReadID, addr, false)){
digitalWrite(ledPin, HIGH); // Ну а если нашли таблетку, то зажигаем светодиод на время считывания ключа
delay(100);
bCopy = true;
lcd.clear(); // Очищаем экран и начинаем отображение информации о номере ключа
lcd.setCursor(0,0);
lcd.print(F("Read: "));
Serial.print(F("Считан: "));
fMoveArray (ReadID, (addr));
PrnByte(ReadID,2);
digitalWrite(ledPin, LOW); // Гасим светодиод
}
else{Serial.println(F("Повторное чтение"));}
}
else{Serial.print(".");}
}
else{ //Запись в таблетку
lcd.clear(); // очищаем LCD и предлагаем приложить болванку
lcd.setCursor(0,0);
lcd.print(F(“Attach blank key”));
lcd.setCursor(4,1);
if (!bCopy){
lcd.print(NameKey[iSelN]);
}
else{
lcd.print(F(“Copy → New”));
}
Serial.println(); // отчитываемся в монитор порта о том, какой номер будем записывать в ключ
Serial.println(F("Будем писать ID: "));
PrnByte(ReadID,0);
delay(500);
digitalWrite(ledPin, HIGH); // Зажигаем светодиод, показывая готовность к записи
bFlagErr = true;
while (bFlagErr){
bReadFlag = true;
while (bReadFlag){
if(!ibutton.search (addr)) { // Проверка: а может таблетка не обнаружена?
switch(get_button()){
case buttonLongPress:{;}
case buttonMiddlePress:{;}
case buttonLShortPress:{
delay(50);
bReadFlag = true;
bWriteFlag = false;
Serial.print(F(“выход по кнопке”));
digitalWrite(ledPin, LOW);
LCD_Start();
return;
}
}
}
else{bReadFlag = false;}
}
ibutton.skip(); ibutton.reset(); ibutton.write(0x33);
Serial.println(); // Новая строка в порт
Serial.print(F(" ID ключа до записи: ")); // пишем в порт что на ключе было до записи
for (byte x = 0; x < 8; x++) {
OldID[x] = ibutton.read();
}
PrnByte(OldID,0);
lcd.clear(); // Очищаем экран перед записью ключа
lcd.setCursor(0,0);
lcd.print(F("Key writing")); // Начало записи, интригуем пользователя и не даём оторвать таблетку
// send reset
ibutton.skip();
ibutton.reset();
// send 0xD1
ibutton.write(0xD1);
// send logical 0
digitalWrite(pin, LOW); pinMode(pin, OUTPUT); delayMicroseconds(60);
pinMode(pin, INPUT); digitalWrite(pin, HIGH); delay(10);
byte newID[8] = { (ReadID[0]), (ReadID[1]), (ReadID[2]), (ReadID[3]), (ReadID[4]), (ReadID[5]), (ReadID[6]), (ReadID[7]) };
ibutton.skip();
ibutton.reset();
ibutton.write(0xD5);
Serial.println();
Serial.print(F(" Запись ключа")); // Отчитываемся в порт о начале записи ключа
if (bCopy){Serial.print(F(" (копия):"));}
else{Serial.print(F(" (универсальный):"));}
for (byte x = 0; x < 8; x++) {
writeByte(newID[x]); // В цикле вызываем функцию побайтовой записи ключа
lcd.setCursor(x,1);
lcd.print(".");
}
PrnByte(newID,0);
Serial.println();
Serial.println(F("Запись завершена")); // Пишем в порт о завершении процесса записи
Serial.println(F("Проверяем записанное")); // Пишем в порт о завершении процесса записи
//проверяем запись
ibutton.skip();
ibutton.reset();
// ibutton.search (addr);
ibutton.write(0x33);
bFlagErr = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F(“Checking”));
for (byte x = 0; x < 8; x++) {
lcd.setCursor(x,1);
lcd.print(“.”);
addr = ibutton.read();
delay(100);
}
bFlagErr = !fCompareArray (newID, addr, false);
Serial.print(F(“К записи в ключ “));
PrnByte(newID,0);
Serial.println();
Serial.print(F(” прочитано после записи “));
PrnByte(addr,0);
if (bFlagErr){
Serial.println(F(“Ошибка! Записанный ключ не прошел последующую верификацию. Возможно он только для чтения”));
}
ibutton.reset();
digitalWrite(ledPin, LOW); // Гасим светодиод
// lcd.setCursor(4,1);
lcd.clear();
lcd.setCursor(1,0);
if (bFlagErr){
lcd.print(F(“Write ERROR!”));
lcd.setCursor(0,1);
lcd.print(F(“Key is ReadOnly”));
delay(4000);
lcd.clear();
lcd.setCursor(1,0);
lcd.print(F(“Try write again”));
lcd.setCursor(0,1);
lcd.print(F(“or press button”));
}
else{
lcd.setCursor(4,0);
lcd.print(F(” Write OK”)); // дописываем фразу для пользователя, намекая, что таблетку можно забирать
lcd.setCursor(0,1);
lcd.print(F(" Key is ready"));
}
}
delay(4000);
LCD_Start();
bWriteFlag = false;
bReadFlag = true;
bCopy = false;
iSelN = 0xFF;
for (byte x = 0; x < 8; x++) ReadID = 0xFF;
}
}
//--------------------------------------------------
// собственно, функция записи байта в таблетку
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;
}
//--------------------------------------------------
// Начальное сообщение на дисплее
void LCD_Start(){
lcd.clear();
lcd.setCursor(1,0); // Устанавливаем курсор в 4 символ 1 строки
lcd.print(F("Ready to copy ")); // Первая строка при включении
lcd.setCursor(1,1); // Устанавливаем курсор в 7 символ 2 строки
lcd.print(F(“Attach the key”)); // Вторая строка при включении
}
//--------------------------------------------------
// вывод 8 байт с лидирующим 0
void PrnByte(byte hByte[8], int i){
bool bStart = true;
for (byte x = 0; x < 8; x++) {
if (bStart && (i == 1 || i == 2)){lcd.setCursor(8,0);}
if (hByte [x] <= 0x0F){
if (i == 0 || i == 2){Serial.print("0");}
if (i == 1 || i == 2){lcd.print("0");}
}
if (i == 0 || i == 2){
Serial.print(hByte[x], HEX);
if (x < 7){Serial.print(':');}
else{Serial.println();}
}
if (i == 1 || i == 2){
lcd.print(hByte[x], HEX);
if (x==3){lcd.setCursor (0,1);}
if (x < 7){lcd.print(":");}
bStart = false;
}
}
}
//--------------------------------------------------
//обработка кнопки
enum ButtonResult get_button(void){
//для измерения времени нажатия
uint16_t buttonPressTime = 0;
//--------------------------------------------------
//проверка нажатия кнопки
while(digitalRead(buttonPin) == LOW){
//шаг по шкале времени
delay(TIME_STEP);
//считаем время
buttonPressTime += TIME_STEP;
//это нужно, чтоб счетчик не переполнился, если кто-то уснет на кнопке
if(buttonPressTime > BUTTON_LONG_PRESS_TIME)
buttonPressTime = BUTTON_LONG_PRESS_TIME;
}
//проверяем длинное нажатие кнопки
if(buttonPressTime >= BUTTON_LONG_PRESS_TIME)
return buttonLongPress;
//проверяем среднее нажатие кнопки
if(buttonPressTime >= BUTTON_MIDDLE_PRESS_TIME)
return buttonMiddlePress;
//проверяем короткое нажатие кнопки
if(buttonPressTime >= BUTTON_LSHORT_PRESS_TIME)
return buttonLShortPress;
//проверяем короткое нажатие кнопки
if(buttonPressTime >= BUTTON_SHORT_PRESS_TIME)
return buttonShortPress;
//сообщаем, что кнопку не нажимали
return buttonNotPress;
}
//--------------------------------------------------
// копирование массива ключа
void fMoveArray (byte To[8], byte From[8]){
for (byte x = 0; x < 8; x ++) To = From;
}
//--------------------------------------------------
// копирование массива ключа
bool fCompareArray (byte Arr1[8], byte Arr2[8], bool bBlank){
bool bOk = true;
byte BlankByte = 0xFF;
for (byte x = 0; x < 8; x ++){
if (!bBlank){BlankByte = Arr2;}
if (Arr1 != BlankByte && bOk){
bOk = false;
}
}
return bOk;
}
//--------------------------------------------------
//выбор универсального клча из базы
void SelectUni (){
bool bLoop = true, bSel = false;
uint16_t WaitTime = 0;
byte i = 5, iSel = 0;
byte selID[8];
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F(“Select univ key”));
Serial.println (F(“Выбираем унив. ключ из базы”));
while (bLoop){
switch(get_button()){
case buttonShortPress:{
fMoveArray (selID, UniKey[iSel]);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(NameKey[iSel]);
Serial.print(NameKey[iSel]);
Serial.print(" ");
PrnByte(selID,2);
iSelN = iSel;
if (iSel == iSize){iSel = 0;}else{iSel += 1;}
bSel = true;
break;
}
case buttonLShortPress:{;}
case buttonMiddlePress:{
if (!bSel){break;}
fMoveArray (ReadID, selID);
bReadFlag = false; // Ставим флаг, чтобы не читать из таблетки в массив ReadID перед записью
bWriteFlag = true; // Ставим флаг, чтобы писать в таблетку содержимое масива readID
bCopy = false;
return;
}
case buttonLongPress:{
LCD_Start();
return;
}
case buttonNotPress:{
if (!bSel){
delay(TIME_STEP);
WaitTime += TIME_STEP;
if ((WaitTime%1000) == 0){
lcd.setCursor(9,1);
lcd.print(i, DEC);
i -= 1;
}
}
break;
}
}
if (WaitTime > 5000){
LCD_Start();
return;
}
}
}