CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

Arduino и 1-Wire - эмуляция ведомого устройства с помощью библиотеки OneWireSlave

Arduino и 1-Wire - эмуляция ведомого устройства

Библиотека 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
  • +2
  • 4 сентября 2010, 09:55
  • admin

Комментарии (11)

RSS свернуть / развернуть
+
0
Не совсем понял практический смысл как использовать ардуину на линии 1-Wire в качестве ведомого устройства, но чувствуется работа проделана большая. Great work!
avatar

saaremaa

  • 4 сентября 2010, 11:07
+
0
Вернее не так. «Для каких целей спользовать ардуину на линии 1-Wire в качестве ведомого устройства» :)
avatar

saaremaa

  • 4 сентября 2010, 11:08
+
0
А для каких целей используют микроконтроллер?
Вот для этих целей и Ардуино, 1-Wire это просто один из вариантов доступа в дополнение к UART или Ethernet(нужен доп шилд)
avatar

skystorm

  • 4 сентября 2010, 11:30
+
0
Кстати вдогонку, есть интересная реализация взаимодействий 2х и более Ардуино по I2C, один из которых Мастер.
avatar

skystorm

  • 6 сентября 2010, 16:37
+
0
а где ссылка??
avatar

pepper

  • 28 сентября 2010, 11:41
+
0
proteus на линуксе?
avatar

MAFia

  • 26 сентября 2011, 14:41
+
0
здоровым.
Я не работаю… Я должен Arduino IButton как сканеры, но когда я подключить эмулятор для читателя, я через последовательный монитор Arduino пишет неполную ID — 1 8B C8 FF FF FF FF. и так домофона на эмуляторе не работает.
avatar

vasia789

  • 1 мая 2014, 00:58
+
0
Я с Ардуинкой новичок, но назрел вопрос. Где взять библиотеку «WProgram.h»?
avatar

Grishin

  • 22 января 2015, 14:39
+
0
этот заголовочный файл использовался в старых версиях IDE.
см. Как адаптировать библиотеки для Arduino 1.0
avatar

admin

  • 22 января 2015, 14:41
+
0
Светлых мыслей.
Благодарность авторам и выложившим сюда описание людям.
А можно написать минимальные требование для библиотеки?
В attiny13 влезет?
Хорошо бы порт нв stm8s003f3p6 по 17р. за проц :)
avatar

izhadapter

  • 16 декабря 2015, 07:53
+
0
народ кто может помочь добавить данную функцию в этот скетч.

#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
avatar

sir999

  • 2 декабря 2016, 02:52

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.