Библиотека OneWireSlave позволяет использовать ардуину на линии 1-Wire в качестве ведомого устройства. Подробнее о OneWire можно прочитать здесь. Теоретически на линии может быть до 2^48 или 281 триллионов ведомых устройств.
С помощью этой библиотеки на одну линию совместно с датчиками температуры и прочими устройствами, использующими протокол 1-Wire, можно подключить несколько ардуин.
OneWireSlave(uint8_t pin);
— конструктор, параметром указывается пин ардуины для OneWire линии.
void setRom(char rom[8]);
— устанавливает тип и адрес устройства. Если библиотека скомпилирована с поддержкой расчета контрольной суммы crc8, то она подсчитывается и заносится в последний байт rom.
bool waitForRequest(bool ignore_errors);
— функция блокирует выполнение программы и ожидает обращения к текущему устройству. Функция возвращает управление программе, если ведущее устройство отправило команду MATCH ROM с адресом текущего устройства или команду SKIP ROM. Во время ожидания функция принимает участие в поисковых запросах ведущего устройства и отвечает на команду READ ROM. Таким образом обеспечивается поддержка базового протокола. Если параметр ignore_errors установлен, то функция будет игнорировать ошибки чтения/записи, иначе вернет FALSE.
bool waitReset(uint16_t timeout_ms);
— функция ждет RESET импульса на линии, после чего возвращает управление программе. Параметр timeout_ms устанавливает время в миллисекундах, по истечение которого функция принудительно вернет управление программе. Если timeout_ms равен 0, то программа будет вечно ожидать RESET импульс, пока не дождется. Стандартное значение timeout_ms — 1000. Возвращает TRUE, если принят сигнал RESET, в случае слишком короткого или слишком длинного сигнала или по истечение времени ожидания вернет FALSE.
bool presence(uint8_t delta);
— функция посылает сигнал PRESENCE согласно протоколу. Если в конце передачи сигнала на линии по какой-либо причине будет низкий уровень сигнала, функция вернет FALSE.
bool search();
— функция участвует в процедуре поиска устройств, описанной в документации протокола OneWire. Возвращает TRUE, если при поиске было найдено текущее устройство, иначе FALSE.
uint8_t sendData(char buf[], uint8_t len);
— отсылает на линию указанный объем данных. Возвращает количество отосланных байт данных.
uint8_t recvData(char buf[], uint8_t len);
— считывает с линии указанный объем данных и заносит их в указанный буфер. Возвращает количество успешно считанных байт данных.
void send(uint8_t v);
— отсылает на линию один байт данных.
uint8_t recv(void);
— считывает с линии один байт данных.
void sendBit(uint8_t v);
— отсылает на линию один бит данных.
uint8_t recvBit(void);
— считывает с линии один бит данных.
static uint8_t crc8(char addr[], uint8_t len);
— функция подсчитывает контрольную сумму по алгоритму crc8 указанного объема данных.
uint8_t errno;
Если выполнение функции закончилось неудачей, то она занесет номер ошибки в эту переменную.
Ошибки:
ONEWIRE_NO_ERROR при выполнении функции не возникло никаких исключений.
ONEWIRE_READ_TIMESLOT_TIMEOUT истекло время ожидания таймслота от ведомого устройства при чтении с линии. Устанавливается функциями recv*.
ONEWIRE_WRITE_TIMESLOT_TIMEOUT истекло время ожидания таймслота от ведомого устройства при записи на линию. Устанавливается функциями send*.
ONEWIRE_WAIT_RESET_TIMEOUT истекло время ожидания импульса RESET на линии. Устанавливается функцией waitReset.
ONEWIRE_VERY_LONG_RESET импульс RESET принят, но оказался слишком длинным (возможно это не RESET, а что-то другое). Устанавливается функцией waitReset.
ONEWIRE_VERY_SHORT_RESET импульс RESET оказался слишком коротким. Такая ошибка может появиться, если при ожидании RESET сигнала другое устройство начало передачу данных.
ONEWIRE_PRESENCE_LOW_ON_LINE по окончании передачи PRESENCE сигнала на линии оказывается низкий уровень сигнала. Согласно протоколу все устройства в момент считывания сигнала с линии должны были прекратить передачу импульса PRESENCE.
Пример скетча, эмулирующего работу ключа ibutton с микросхемой DS1990A
#include "WProgram.h"
#include "OneWireSlave.h"
char rom[8] = {0x01, 0xAD, 0xDA, 0xCE, 0x0F, 0x00, 0x00, 0x00};
OneWireSlave ds(8);
void setup() {
ds.setRom(rom);
}
void loop() {
ds.waitForRequest(false);
}
В данном случае функция waitForRequest вернет FLASE с ошибкой ONEWIRE_READ_TIMESLOT_TIMEOUT, т.к. домофон (или его эмулятор) не выбирает устройство, а только считывает его адрес.
В случае обрыва линии, на выводе может возникнуть неопределенное состояние, поэтому рекомендуется вывод ардуины подключить к земле через резистор 220к.
Заметка: с реальным домофоном без дополнительной обвязки ардуина работать не будет, т.к. в современные домофоны устанавливаются защиты от копированных ключей. Защита срабатывает на основе некоторых электрических и возможно временных параметров.
Скачать библиотеку: OneWireSlave.zip
OneWireSlave2.zip (с доработкой от Алексея Мочалова(lex512))
Автор статьи: Александр Гордеев — победитель конкурса «Напиши эмулятор iButton-а для Arduino и получи ProtoShield в подарок!»
По теме
Протокол 1-Wire
Практическое программирование Arduino/CraftDuino — протокол 1-Wire и iButton
Arduino/CraftDuino и эмулятор iButton


13 комментариев на «“Arduino и 1-Wire — эмуляция ведомого устройства с помощью библиотеки OneWireSlave”»
Не совсем понял практический смысл как использовать ардуину на линии 1-Wire в качестве ведомого устройства, но чувствуется работа проделана большая. Great work!
Вернее не так. «Для каких целей спользовать ардуину на линии 1-Wire в качестве ведомого устройства» 🙂
А для каких целей используют микроконтроллер?
Вот для этих целей и Ардуино, 1-Wire это просто один из вариантов доступа в дополнение к UART или Ethernet(нужен доп шилд)
Кстати вдогонку, есть интересная реализация взаимодействий 2х и более Ардуино по I2C, один из которых Мастер.
а где ссылка??
proteus на линуксе?
здоровым.
Я не работаю… Я должен Arduino IButton как сканеры, но когда я подключить эмулятор для читателя, я через последовательный монитор Arduino пишет неполную ID — 1 8B C8 FF FF FF FF. и так домофона на эмуляторе не работает.
Я с Ардуинкой новичок, но назрел вопрос. Где взять библиотеку «WProgram.h»?
этот заголовочный файл использовался в старых версиях IDE.
см.
Светлых мыслей.
Благодарность авторам и выложившим сюда описание людям.
А можно написать минимальные требование для библиотеки?
В attiny13 влезет?
Хорошо бы порт нв stm8s003f3p6 по 17р. за проц 🙂
Если залить это на Arduino то можно открыть этим домофон?
Не могу понять что это за ошибка?
CC:\Users\MLG\Documents\Arduino\sketch_jan13b\sketch_jan13b.ino:4:62: warning: narrowing conversion of ‘173’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]
char rom[8] = {0x01, 0xAD, 0xDA, 0xCE, 0x0F, 0x00, 0x00, 0x00};
^
C:\Users\MLG\Documents\Arduino\sketch_jan13b\sketch_jan13b.ino:4:62: warning: narrowing conversion of ‘218’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]
C:\Users\MLG\Documents\Arduino\sketch_jan13b\sketch_jan13b.ino:4:62: warning: narrowing conversion of ‘206’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]
C:\Users\MLG\Documents\Arduino\sketch_jan13b\sketch_jan13b.ino: In function ‘void setup()’:
C:\Users\MLG\Documents\Arduino\sketch_jan13b\sketch_jan13b.ino:8:18: warning: invalid conversion from ‘char*’ to ‘unsigned char*’ [-fpermissive]
ds.setRom(rom);
^
In file included from C:\Users\MLG\Documents\Arduino\sketch_jan13b\sketch_jan13b.ino:2:0:
C:\Users\MLG\Documents\Arduino\libraries\OneWireSlave/OneWireSlave.h:44:10: note: initializing argument 1 of ‘void OneWireSlave::setRom(unsigned char*)’
void setRom(unsigned char rom[8]);
^
Подскажите как реализовать такое на ESP?
народ кто может помочь добавить данную функцию в этот скетч.
#include <OneWire.h> #include "pitches.h" const byte greenLed = 10; //зеленая лампочка const byte redLed = 11; //красная лампочка const byte gerkonPin = 8; //gerkon const byte iButtonPin = 12; //пин для ibutton const byte tonePin = 7; // пин для пищалки const byte waterPin = 9; // пин датчика воды const byte alarmTime = 3; // время, чтобы поднести ключ при разблокировке const byte startTime = 5; // время на закрытие двери при постановке на сигнализацию OneWire ds(iButtonPin); //ibutton byte code1[8] = {0x01, 0x9F, 0xDC, 0x02, 0x00, 0x00, 0x96, 0x1C}; //первый ключ byte code2[8] = {0x01, 0xF0, 0x30, 0xB5, 0x00, 0x00, 0x00, 0xDB}; //второй ключ (он же и для boolean waterAlarmed = 0; //флаг сработавшего оповещения о воде boolean alarmState = 0; //флаг работающей сигнализации boolean gerkonState = 0; //первично закрытая дверь (1 - закрыто, 0 - открыто), пока на кнопке. boolean Hacked = 0; // стандартные коды: 1- включение, 2- выключение, 3- тревога void setup() { Serial.begin(115200); delay(2000); //задержка включения pinMode(greenLed, OUTPUT); //задаем режим работы пинов pinMode(redLed, OUTPUT); pinMode(waterPin, INPUT); pinMode(gerkonPin, INPUT); Notify(98); // оповещение о включении ардуино (напр. после перезагрузки) } void loop() { byte returnedValue = 0; if(alarmState==0) { //Сигнализация выключена, ждем пока поднесут ключ для ВКЛЮЧЕНИЯ returnedValue = findKey(); if (returnedValue == 1) { // нашли известный ключ guardON(); //вкл статус сигнализации } } if(alarmState==1) { // если включена сигнализация, то gerkonState = digitalRead(gerkonPin); //смотрим геркон // Serial.println(gerkonState, HEX); if (gerkonState == 1 && Hacked != 1) { //открылась дверь и квартира не взломана ;) Notify(1); // сообщаем компьютеру об открытии двери alarmON(); //включаем сигналку } returnedValue = findKey(); //нужно выключить изнутри квартиры if (returnedValue == 1) { // нашли известный ключ и alarmState=0; guardOFF(); } } returnedValue = 0; //обнуляем для обработки датчиков воды //returnedValue = checkWater(); //if (returnedValue==1) { // запускаем оповещение о срабатывании датчика воды // Notify(10); //сообщаем о срабатывании датчика воды //} delay (500); } int checkWater() //функция проверки датчика воды { int WsensorState = analogRead(waterPin); Serial.println(WsensorState); if (WsensorState == 1 && waterAlarmed == 0){ waterAlarmed =1; return 1; } return 0; } int findKey() // функция поиска ключа { byte i; byte addr[8]; byte checkOK = 0; //счетчик совпадений массива с эталоном //Serial.println("searching key..."); if (!ds.search(addr)) { // тут надо сделать нормально сделатЬ!!! //Serial.println("No key connected..."); // сообщаем об этом ds.reset_search(); delay(200); return; // и прерываем программу for(int i = 0; i<8; i++) Serial.print(addr[i],HEX); Serial.print(" "); } Serial.println("\n"); for (int i=0; i<8; i++) if (addr[i]==code1[i]) { checkOK++; } if (addr[i]==code2[i]) { //сюда надо добавить начало отправки и через 2 секунды остановить } if (checkOK == 8 ){ return 1; } return 0; } void guardON() // выполнение действие при на сигнализацию { int j; alarmState=1; //включаем статус сигнализации guardSound(1); //бибикаем for (j=0; j < startTime; j++) { guardBlink(1); //моргаем лампочками и ждем время для закрытия двери } Notify(0); } void guardOFF() // выполнение действие при снятии с сигнализации { alarmState=0; // выключаем статус сигнализации Hacked = 0; // отменям статус "взломано" digitalWrite(greenLed, LOW); guardSound(2); //бибикаем guardBlink(2); //моргаем лампочками Notify(3); } int alarmON() // выполнение действий при срабатывании сигнализации { int checkcount=0; while (checkcount < alarmTime) { // даем alarmTime секунд для поднесения ключа int alarmCancel = findKey(); //ищем ключик if (alarmCancel == 1) { // нашли ключ guardOFF(); //отключаем сигналку, break; // выходим из цикла } checkcount++; guardBlink(3); //пищим о том, что ищем ключ guardSound(3); //светим о том, что ищем ключ } if (checkcount==alarmTime) { // если не нашли, то включаем оповещение Notify(2); guardBlink(4); //пищим о том, что УСЁ ПРОПАЛО guardSound(4); //светим о том, что УСЁ ПРОПАЛО Hacked = 1; } } int guardBlink (int x) //функция светового оповещения { if (x==1) { // первое ожидание для закрытия двери. digitalWrite(redLed, HIGH); digitalWrite(greenLed, LOW); delay(500); digitalWrite(redLed, LOW); digitalWrite(greenLed, HIGH); delay(500); } if (x==2) { // выключаем сигнализацию и диоды digitalWrite(redLed, LOW); digitalWrite(greenLed, LOW); } if (x==3) { // во время ожидания ключа при открытой двери digitalWrite(redLed, HIGH); delay (250); digitalWrite(redLed, LOW); delay (250); } if (x==4) { // просрочено, ахтунг digitalWrite(redLed, HIGH); } } int guardSound (int x) //функция звукового оповещения { if (x==1) { int melody[] = { // музыка при включении сигнализацию NOTE_G3, NOTE_G3, NOTE_G3 }; int noteDurations[] = { 4,4,4 }; for (int thisNote = 0; thisNote < 3; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; tone(tonePin, melody[thisNote],noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); noTone(tonePin); } } if (x==2) { // выключаем сигнализацию int melody[] = { NOTE_C2, NOTE_G1,NOTE_G2, NOTE_A1, NOTE_G1,0, NOTE_B2, NOTE_C3 }; int noteDurations[] = { 4, 8, 8, 4,4,4,4,4 }; for (int thisNote = 0; thisNote < 8; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; tone(tonePin, melody[thisNote],noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); noTone(tonePin); } } if (x==3) { //тон ожидания ключа tone(tonePin,NOTE_C4, 100); } if (x==4) { //тон просроченного ключа tone(tonePin, 500); //включаем на 500 Гц delay(100); //ждем 100 Мс tone(tonePin, 1000); //включаем на 1000 Гц delay(100); //ждем 100 Мс } } int Notify(int x) //функция оповещения в последователньый порт { if (x==0) { // оповещение о постановке на сигнализацию Serial.println("Сигнализация включена"); } if (x==1) { // оповещение о открытии двери Serial.println("Дверь открыта"); } if (x==2) { // оповещение о взломе квартиры! Serial.println("Тревога, проникновение"); } if (x==3) { // оповещение о выключении сигнализации Serial.println("Сигнализация отключена"); } if (x==98) { // оповещение о включении ardunio Serial.println("Устройство готово к работе"); } if (x==99) { // оповещение о ОШИБКЕ Serial.println("Ошибка"); } }действия:
1) если приложен ключ 1 {0x01, 0x9F, 0xDC, 0x02, 0x00, 0x00, 0x96, 0x1C}, выполняется первая команда записанная в скетче.
2) если приложен ключ 2 {0x01, 0xF0, 0x30, 0xB5, 0x00, 0x00, 0x00, 0xDB}, начинается инициализация передачи кода {0x01, 0xF0, 0x30, 0xB5, 0x00, 0x00, 0x00, 0xDB} на пин 6