Очередной "Умный дом", на этот раз модульная система...

gonzales
Offline
Зарегистрирован: 13.07.2015

> Рискну предположить, интерфейс реализован на MAX485, а он позволяет только 32 устройства на шине.

Да, физических устройств на шине не более 32 (Про-мини), но к каждому могут быть подключены до трех сенсоров или актуаторов с субадресацией. 

> Строка 51. Что если пришло не 9 символов, а меньше или больше?

Значит это не мой пакет, а лажа)))) Протоколом определено только 9 байт в пакете.

 

gonzales
Offline
Зарегистрирован: 13.07.2015

Как тут цитирование ставить?)))

gonzales
Offline
Зарегистрирован: 13.07.2015

alex_r61 пишет:

>А что тут может быть кривого? Не сочтите за труд посмотрите скеч

Кривая сама IDE, при такой загрузке нужен прямой доступ к ресурсам МК.

Почему? Вы предлагаете использовать CyberLib? Что это даст?

gonzales
Offline
Зарегистрирован: 13.07.2015

Не могу понять, каким образом CAN противостоит коллизиям, как это реализовано. Есть модуль вот такой http://arduino55.ru/modules/tja1050.html и похожие, и даже библиотека, но в ней ничего про коллизии нет.

gonzales
Offline
Зарегистрирован: 13.07.2015

Нашел 

Арбитраж шины CAN.

Быстродействие CAN сети (до 1 Mbit/s) достигается благодаря механизму недеструктивного арбитража шины посредством сравнения бит конкурирующих сообщений. Т.е. если случится так что одновременно начнут передачу несколько контроллеров, то каждый из них сравнивает бит, который собирается передать на шину с битом, который пытается передать на шину конкурирующий контроллер. Если значения этих битов равны оба контроллера пытаются передать следующий бит. И так происходит до тех пор пока значения передаваемых битов не окажутся различными. Теперь контроллер, который передавал логический ноль (более приоритетный сигнал) будет продолжать передачу, а другой(другие) контроллер прервёт свою передачу до того времени пока шина вновь не освободится. Конечно ,если шина в данный момент занята ,то контроллер не начнет передачу до момента её освобождения.

Эта спецификация CAN исходит из предположения, что все CAN контроллеры принимают сигналы с шины одновременно. Т.е. в одно и то же время один и тот же бит принимается всеми контроллерами в сети. С одной стороны такое положение вещей делает возможным побитовый арбитраж, а с другой стороны ограничивает длину CAN bus. Сигнал распространяется по CAN bus с огромной, но конечной, скоростью и для правильной работы CAN нужно , чтобы все контроллеры "услышали" его почти одновременно. Почти, потому что каждый контроллер принимает бит в течении определённого промежутка времени, отсчитываемого системным часам. Таким образом, чем выше скорость передачи данных, тем меньшая длинна CAN bus возможна.

Получается там аппаратный арбитраж, даже делать ничего не надо. Прям какая-то фантастика

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

gonzales пишет:
Значит это не мой пакет, а лажа)))) Протоколом определено только 9 байт в пакете.
Именно поэтому ты их не вычитываешь из приемника, а оставляешь.... кому? Придут еще 9 байт, будет 17 или 19 байт в приемнике - тоже не твой пакет...!? Будешь ждать пока чисто случайно в приемнике не окажется ровно 9 байт?

gonzales пишет:
Как тут цитирование ставить?)))
Вот так: [ quote=gonzales]Как тут цитирование ставить?)))[ /quote]

только лишний пробел после [ убери.

gonzales пишет:
Получается там аппаратный арбитраж, даже делать ничего не надо. Прям какая-то фантастика
Дело за CAN контроллером, которого в дуине нет. Остается только прикрутить CAN интерфейс к UARTу, потеряв побитовый арбитраж, но взамен получив побайтовый.

gonzales
Offline
Зарегистрирован: 13.07.2015

Andy пишет:
Именно поэтому ты их не вычитываешь из приемника, а оставляешь.... кому? Придут еще 9 байт, будет 17 или 19 байт в приемнике - тоже не твой пакет...!? Будешь ждать пока чисто случайно в приемнике не окажется ровно 9 байт

Спасибо!!!! Понял! То есть считывать в любом случае надо, а уже потом разобраться, мое - не мое.

Andy пишет:
Остается только прикрутить CAN интерфейс к UARTу, потеряв побитовый арбитраж, но взамен получив побайтовый.

Вот сейчас не понял)))) Если можно, поясни более развернуто, для чайников.

Спрошу еще сразу. Есть микросхема приемопередатчика CAN - MCP2551, у нее с одной стороны Tx, Rx, с другой CAN_H, CAN_L. Но его не цеплят напрямую к ардуино, а делают связку через CAN-контроллер MCP2515, который цепляют к ардуино по SPI. Мне не понятно, какие функции у CAN-контроллера и почему нельзя напрямую использовать приемопередатчик CAN, соединив его с ардуино по UART

Заранее спасибо за ответ!!

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

gonzales пишет:
Есть микросхема приемопередатчика CAN - MCP2551, у нее с одной стороны Tx, Rx, с другой CAN_H, CAN_L. Но его не цеплят напрямую к ардуино, а делают связку через CAN-контроллер MCP2515, который цепляют к ардуино по SPI. Мне не понятно, какие функции у CAN-контроллера и почему нельзя напрямую использовать приемопередатчик CAN, соединив его с ардуино по UART

MCP2551 - приемопередатчик, реализует CAN интерфейс, среду передачи. MCP2515 - контроллер, реализует CAN протокол, алгоритм взаимодействия. Ничто не мешает реализовать свой протокол поверх CAN интерфейса. Просто подключи MCP2551 к UARTу дуины. Bluetooth же подключают к UARTу, чем CAN хуже...

Что это даст: можно слушать шину во время передачи и сравнивать, что передаешь, с тем, что принимаешь (побайтово, UART все таки), и тем самым определить наличие колизии. В RS485 ты слышишь только то, что передаешь, а в CANе - то что реально происходит на шине.

gonzales
Offline
Зарегистрирован: 13.07.2015

Andy, спасибо за разъяснения!!! Многое становится понятным!

Andy пишет:

MCP2515 - контроллер, реализует CAN протокол, алгоритм взаимодействия. 

А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.

Andy пишет:
Что это даст: можно слушать шину во время передачи и сравнивать, что передаешь, с тем, что принимаешь (побайтово, UART все таки), и тем самым определить наличие колизии. В RS485 ты слышишь только то, что передаешь, а в CANе - то что реально происходит на шине.

Как раз хотел об этом спросить, прочитал в инете, что какие-то умельцы строят арбитраж RS485 по принципу CAN, то есть слушаешь, что передаешь и сравниваешь с тем, что должен передать - если не совпало, значит коллизия. Но как это реализовать, не понятно, ведь передавая что-то через UART, там же ничего в буфере не остается, что с чем сравнивать-то? Использовав RS485.write(200); а затем x=RS485.read() у меня же не будет x==200, или я не прав?

Заранее извините, если вопросы тупые. ))

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

gonzales пишет:
А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.
Да, так и есть. Я для себя ничего хорошего в этом протоколе не нашел.

gonzales пишет:
умельцы строят арбитраж RS485 по принципу CAN, то есть слушаешь, что передаешь и сравниваешь с тем, что должен передать - если не совпало, значит коллизия. Но как это реализовать, не понятно, ведь передавая что-то через UART, там же ничего в буфере не остается, что с чем сравнивать-то? Использовав RS485.write(200); а затем x=RS485.read() у меня же не будет x==200, или я не прав?
В RS485 сигнал разрешения передачи лог.1, а приема - лог.0. Их обычно объединяют в один сигнал и если передают, то ничего не слушают. В CANе приемник разрешен всегда, следовательно все, что передается будет поступать в приемник и если в это время кто-то еще передает, то коллизию можно обнаружить по несовпадению передаваемого и принимаемого байта.

SportMaster
SportMaster аватар
Offline
Зарегистрирован: 02.03.2016

Всем Доброгого времени суток!

Присоединюсь к обсуждению, а "full duplex rs485 " не рассматривался?
На просторах интернета нашлась такая схема,  имеет ли смысл ее реализовать?

gonzales
Offline
Зарегистрирован: 13.07.2015

Рассматривался, но пока не приенялся. Попробую обойтись полудуплексом.

Схема, которую Вы представили подходит для связи только двух устройств. Если надо больше, то схема будет другая.

http://www.gaw.ru/html.cgi/txt/interface/rs485/app.htm

panas
Offline
Зарегистрирован: 01.02.2017

Всем Привет!

Есть 8 точек которые расположены в радиусе 100 метров,нужен сбор статистики(2-3 датчика на точке) и управление клапанами 6-12в

Подскажите как можно решить такой вопрос.

 

alex_r61
alex_r61 аватар
Offline
Зарегистрирован: 20.06.2012

Какой смысл спрашивать в чужой, заброшенной теме?

gonzales
Offline
Зарегистрирован: 13.07.2015

Тем более, что как раз в этой теме достаточно доходчиво разжевана одна из возможных реализаций. 

Но по существу: я как раз занимаюсь такой системой. Если есть интерес, напишите в личку 

 

panas
Offline
Зарегистрирован: 01.02.2017

gonzales пишет:

Тем более, что как раз в этой теме достаточно доходчиво разжевана одна из возможных реализаций. 

Но по существу: я как раз занимаюсь такой системой. Если есть интерес, напишите в личку 

 


Да,интерес есть,но проблема с личкой,мое мыло taube2002@mail.ru

arDubino
Offline
Зарегистрирован: 12.01.2017

изобретатели велосипедов все прут и прут.

давно уже все изобрели. надо делать тогда отдельный контроллер шины который и будет получать чужие пакеты и передавать по адресу когда приемник будет готов.

а то понаделают щаз всяких сигнализаций которые в этот момент будут данные туда-.сюда гонять а не датчики опрашивать.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Andy пишет:

gonzales пишет:
А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.
Да, так и есть. Я для себя ничего хорошего в этом протоколе не нашел.

А можно узнать  почему в CAN ничего хорошего не нашли? Ведь в нем решены некторые проблемы, обсуждаемые в теме. Например:

- борьба с коллизиями возложена не на программиста, а на микросхему

- Система мультимастерная

- скорость работы высокая ( будет быстрое реагирование между разными МК)

- помехозащищенность на уровне

- стомость не высокая. SPI адаптер CAN для ардуино на MCP2515 стоит немногим более 100 руб. 

- и ведь CAN широко применяется в промышленности и автомобилях, наверное не просто так. 

- нет такого как в rs 485, что если мастер лёг - легла вся шина 

Тут говорят зачем для дома CAN? зачем усложнять? Дак если не дорого и присутствуют плюсы то почему бы и нет. 

тем более в шину можно тупо "серить" пакетами с разной инфой. Кому надо, тот возмет пакет с нужным ID

MaksVV
Offline
Зарегистрирован: 06.08.2015

на досуге заказал такой модуль CAN шины 

 

 

 

Ожидания оправдались. Все плюсы постом выше действительно присутствуют. Модуль работает по SPI. Пробовал подключать два модуля к ондной шине SPI всё работает. Т.е. можно на одной ардуино нано делать несколько CAN шин. Кто собрался делать сеть между контроллерами рекомендую CAN шину. модуль недорогой, в пределах 150 руб. Скорость высокая, т.е. например если выключатели света подключать по кан, будет быстро реагировать, не то что по RS485. Да и вообще новичку проще с кан работать. Там весь арбитраж шины аппаратный, ничё придумывать не надо. Сразу работаешь с сообщениями.  Для меня это главный фактор, так как я ни разу не программист. Тупо использовал пример из библиотеки и вперёд.

Короче RS485 в топку. Удобнее всего наверное делать территориальное разделение по микроконтроллерам умного дома, т.е. в каждой комнате по МК с этим кан модулем. 

PS.  для работы с CAN сразу сделал анализатор шины за 5 мин. Просто залив библиотеку MCP2515 CAN HACKER. Программа хорошая, можно просматривать что происходит в шине, записывать поток сообщений, потом воспроизводить эту запись в шину, короче гуд. Прогу и билиотеку легко найти в инете. 

alex_r61
alex_r61 аватар
Offline
Зарегистрирован: 20.06.2012

Некрофилы никак не уймутся. (((

MaksVV
Offline
Зарегистрирован: 06.08.2015

а чё каждый раз то новую тему создавать, будет куча тем, нафиг это надо. 

AndrF
Offline
Зарегистрирован: 10.04.2016

MaksVV пишет:

модуль недорогой, в пределах 150 руб.

ESP-шка стоит столько же. Преимущество - связь между точками можно сделать по WiFi, то есть беспроводную. Управлять же всем хозяйством можно со смартфона или с помощью Web-интерфейса. И она сама по себе неплохой контроллер, под который можно писать на Arduino или на других средствах разработки...

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

не доверяю я радио каналу, в кане протокол мне понятный, а по вифи как данные гонять - темный лес. Но вообще согласен, неплохой модуль. Экономия на ардуинах, их тогда будет не надо. И если есть знания по ESPшке , то сам бог велел её пользовать.

Artemiy
Offline
Зарегистрирован: 20.10.2014

alex_r61 пишет:

Некрофилы никак не уймутся. (((

сами вы это слово нехорошее. :)

кан как раз сейчас и начинает вытеснять остальные протоколы в области уд и иот. Wi-fi здесь как раз гораздо неэффективнее того же RS485. Смысл гонять на таких частотах мелкие пакеты раз в 5 минут. Кан как раз удобнее за счет скорости и обособленности всей системы. Ничего лишнего не прилетает. Все сигналы от/к устройствам ВНУТРИ системы. Когда по wi-fi летает все подряд, занимают ip пространство даже простой датчик. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

если есть люди, кто будет строить кан сеть, давайте свой стандарт создадим. Т.е. какой ID и дата байты в нём за что отвечают, чтоб не было как у автопроизводителей - у каждого свой ID лист.

Так проще будет. 

Наример ID 001 передает в шину время. 002  - состояние охраны дома. периметра и т.д.

Не забываем, что в отличае от rs-485_модбас и им подобных, в CAN шине  "ID" обозначает не  идент.номер контроллера. а идент.номер  сообщения.

Поэтому нулевым байтом в любом сообщении можно сделать номер контроллера, который это сообщение послал. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Попробовал начать писать протокол. Критикуйте

MaksVV
Offline
Зарегистрирован: 06.08.2015

вот пример кода МК, которому интересно движение в комнате "ванна2". Если там есть движение сообщим, об этом в сериал. 

Т.е. нас интересует опрос сообщения с ID 011 бита №3 байта №1. 

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg;
MCP2515 mcp2515(10);


void setup() {
  Serial.begin(115200);
  SPI.begin();
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_125KBPS);
  mcp2515.setNormalMode();

  
  
  Serial.println("------- CAN Read ID 011   byte 1  bit№3");
   Serial.println("");
  
}

void loop() {
  
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) { // если в кан пришло сообщение
       
    if (canMsg.can_id==0x011) {                           // если ID этого сообщения 011

      if (bitRead(canMsg.data[1],3)) {                    // если бит№3 байта №1 этого сообщения равен 1.
        Serial.println ("Dvizheniе v vannoy!!!"); }       // пожалуемся в сериал об этом    
            }

// здесь делаем проверку на другие ID принятого в кан сообщения, если ID более одного
        
    }

      }

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Предлагаю такую архитектуру умного дома. https://yadi.sk/i/SVtm-9N03P5Bno

В данном случае деление МК идёт по территориальному признаку. Т.е. каждый отдельный МК "обслуживает" свою комнату. 

Для себя посчитал это более оптимальным с точки зрения протяжки количества проводов. В каждую комнату нужно будет кинуть два кабеля - силовой 220В и витую пару желательно в экране (CAN шина и питание МК). Так же в систему проще добавлять новые элементы. 

вышесказанное это по сравнениию с концепцией деления отдельных МК по функциональному признаку (Один МК - отопление, второй - освещение, третий - коммуникация и т.д.) и с концепцией, когда вообще всем рулит только один МК. 

Минусом моего варианта можно посчитать необходимость создания в каждой комнате небольшого распределительного щитка, но если на печатке всё делать можно легко уложиться в стандартные распределительные коробки. 

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

Предлагаю такую архитектуру умного дома. https://yadi.sk/i/SVtm-9N03P5Bno

В данном случае деление МК идёт по территориальному признаку. Т.е. каждый отдельный МК "обслуживает" свою комнату. 

Пришел к аналогичной концепции построения сети. CAN, управляющий контроллер на помещение, если есть сложные задачи то доп. специализированные контроллеры. (У меня 2 распред щита с импульсными реле на каждый из которых ставлю по своей меге, протечки отдельное устройство и т.п.)

Ардуино размещаю в подрозетниках по потолком. Использую Mega  2560 pro от robotdyn при размере 30 на 52 мм спокойно лезет в подрозетник, который закрываю заглушкой (серия LK60)

CAN ID разбил на разряды 

//ID structure   xx.yy.z.a.cc
//      xx               yy                                z             a                        cc
//  my address   remote address    type message  device address     device type 
 
На CAN модуле есть линия  INT ее рекомендую использовать, как прерывание на тему наличия своей передачи.
 
485 испоьзую для удаленной прошивки, от всех модулей вывел пары к себе к рабочему столу.
 
 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:
CAN ID разбил на разряды 

//ID structure   xx.yy.z.a.cc
//      xx               yy                                z             a                        cc
//  my address   remote address    type message  device address     device type 
 
На CAN модуле есть линия  INT ее рекомендую использовать, как прерывание на тему наличия своей передачи.
вот этого не понял, напиши по русски.
xx.yy.z.a.cc   это всё в ID заголовке чтоли зашифровано? т.е. 29 битный ID  используешь? 
 
А INT я так понимаю на внешнее прерывание дуни нужно подключать, чтобы оперативнее реагировать на сообщения, когда они в данный момент прилетели, т.е. всё бросаем, и идём в обработчик прерывания парсить кан сообщение. 
riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

вот этого не понял, напиши по русски.
xx.yy.z.a.cc   это всё в ID заголовке чтоли зашифровано? т.е. 29 битный ID  используешь? 
 
А INT я так понимаю на внешнее прерывание дуни нужно подключать, чтобы оперативнее реагировать на сообщения, когда они в данный момент прилетели, т.е. всё бросаем, и идём в обработчик прерывания парсить кан сообщение. 

Железка MCP_2515. Использую 29 битный ID. Пользователю разницы нет, а внутри ID можно спрятать кучу служебной инфы. Что и делаю.  Использую эту библиотеку (после долгого перебора), смотри примеры. Другие библиотеке так шустро не заработали. Думаю покопать CanOpen и Festival (CANFestivino).

Структуру заголовка придумал сам. 

Первые 2 разряда адрес отправителя например 11, вторые получателя 22, типов сообщения я пока определил 6 их можно расширить (send и ansver command, request, status), device address это для 1-wire и пр. однотипных устройств подключенных к CAN node (пока не использую), device type это тип датчика или исполнительного устройства.

Такое построение заголовка дает мне возможность принимая сообщение видеть от кого и кому оно и прекращать его анализировать если оно не мне или меня не касается. (широковещательный еще ни кто не отменял).

Дальше по типу сообщения я попадаю сразу в нужный обработчик, если пришел запрос состояния, то один обработчик, если команда то другой. Зная адрес и тип устройства я могу не обрабатывать сырые данные внизу а не глядя их запихивать в сеть и обрабатывать сервером и или мощным МК наверху, то же и с устройствами, отправляю прямую команду на конкретное исполнительное устройство. (Что совсем не мешает мне делать виртуальные устройства для верхнего МК, типа климат контроль помещения, задавая температуру, влажность и уровень СО2 чтобы МК внизу сам решал эту задачу и отдавал статус)

По прерыванию INT, оно используется пока как флаг, просто не читаю линию пока передаю, нет смысла читать буфер и его анализировать пока идет моя передача, но мысль "всё бросаем, и идём в обработчик"  нужн тоже продумать.

#define CAN0_INT 2                              // Set INT to pin 2

void RX()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
.............
 
На практике получилось совсем не плохо по сравнению с 485, обмен мгновенный, скорость поставил CAN_500KBPS (длинна до 100м) , все летает.
 
Нахожусь на этапе закладки кабелей под датчики и исполнительные по кваритре и прототипирования сети.
 
Использовать буду наверху Linux server c чем то типа OpenHub, MajorDomo, Domoticz (Пока не определился, расковыряю структуру внутри, пойму на чем комфортнее писать выберу. Под CAN привязок нет, так что все самому придется писать.), ниже наверно пару DUE (мастер-слейв) с AMS, наверх к серверу Eth, вниз CAN, под ними сеть CAN с датчиками и исполнительными устройствами.
Радио буду использовать в крайнем случае, если в друг кабелей не хватит а хотелка появиться.
Думаю снимать во всех помещениях температуру, влажность, давление BME280, температуру у пола, потолка и посередине DS18B20, движение PIR и Microwave, вибрацию, проход, состав воздуха, огонь, шум, концевики в окнах и дверях, контроль наличия напряжения через АОТ166. Исполнительные у-ва. эл. клапаны в радиаторах, кондей (пока IR), увлажнитель, рекуператор, вытяжка, свет (использую меандровские РИО-1М, и кнопочные выключатели LK60 а мк через реле щелкает выключателем), жалюзи, протечки и газ запорные клапана само собой.
MaksVV
Offline
Зарегистрирован: 06.08.2015

Серьезные планы. 500 кБит если на 100 метрах пашет, это гуд. У меня такие же расстояния. А как подключаешь rs485 для удаленной прошивки? Просто поискал инфу прошивки ардуино по RS485, рабочего варианта так и не смог найти. Даже попробовал прошить по 485 через переходник USB->RS485 со стороны компа и китайский модуль RS485 со стороны дуни. Естесственно ничего не получилось. Я так понимаю при заливке прошивки обмен данными между IDE и ардуино идёт туда сюда, а не в одну сторону, поэтому на ардуине нужно дёргать пин прием-передача, а кто его будет дергать то в момент перепрошивки? Bootloader нужен другой, как я понимаю, причем в котором желательно пин , дёргающий приём-передачу, чтоб можно было выбирать.

riv
Offline
Зарегистрирован: 20.07.2017

По поводу 485 его использую как конвертер rs232-rs485-rs485-rs232 точка точка. (По поводу сетевой прошивки через 485 , витали идеи по форуму,  выдавать команду по сети, не принимать команды всем кроме нужного в течении 2-5 минут). Мне это не очень интересно. На магистрали мономастер тупик. Для достижения дальности 100 метров использую сигнальный кабель. (Хотя по честному у меня линии более 30 метров и нет).  Причем питание 12 вольт подаю по 2й паре.  Этот же кабель использую на датчики и слаботочные исполнительные у-ва.

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:
По поводу 485 его использую как конвертер rs232-rs485-rs485-rs232 точка точка.

И все таки мне не понятно. Это так чтоли? Прошиваешь через Arduino IDE?

MaksVV
Offline
Зарегистрирован: 06.08.2015

и можно название кабеля, а то кроме витой пары ниче не могу найти. 

riv
Offline
Зарегистрирован: 20.07.2017

S.D.B. LIYCY-0 2x2x0,34 IEC 332.3 F2 ROHS.  Брал на avito

 

riv
Offline
Зарегистрирован: 20.07.2017

Цепочка сильно короче сразу usb-485 - 485 ардуино.  

USB-485

к ардуино

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

дак я так и подключал. Что нужно чтобы скетч загрузился? На какой пин DE RE подключаешь и через что скетч грузишь -  IDE?

riv
Offline
Зарегистрирован: 20.07.2017

MaksVV пишет:

дак я так и подключал. Что нужно чтобы скетч загрузился? На какой пин DE RE подключаешь и через что скетч грузишь -  IDE?

Все не так просто. Нужно обязательно перепрошивать загрузчик на optiboot   с поддержкой 485, там в опциях сборки указываешь пин DE RE. И уже бутлоадер его дергает. В своем приложении обрабатываешь команду ребут. Можешь использовать DudeLib и примеры из него. Там прямо по шагам указано как собрать optiboot. Шьешь другой ардуиной используя скетч arduinoisp.

У меня сейчас основная проблема перекроить optiboot под 2560, вроде есть решения №1 и №2 но руки не доходят. Честно говоря В плотную займусь этим после НГ. Сейчас как я и говорил занимаюсь прокладкой и прототипированием. Все на столе и иногда выезжает в поле для опытов. Пока скорее выбираю и опробую технологии на предмет использования. Без вылизывания кода.

Есть еще один вариант но не проверял. (И он точно в сети работать не будет из-за колизий). Это использование чипа с автоопределением RX TX - MAX13487/13488

 

Кстати по кабелям, очень много сигнальных - контрольных кабелей у пожарников (ОПС, ВН) и асутпшников (АСКУЭ, АСУТП, etc) . Набери сигнальный кабель для 485 и дальше выбирай под задачу.

MaksVV
Offline
Зарегистрирован: 06.08.2015

MaksVV пишет:
Я так понимаю при заливке прошивки обмен данными между IDE и ардуино идёт туда сюда, а не в одну сторону, поэтому на ардуине нужно дёргать пин прием-передача, а кто его будет дергать то в момент перепрошивки? Bootloader нужен другой, как я понимаю, причем в котором желательно пин , дёргающий приём-передачу, чтоб можно было выбирать.

riv пишет:
Все не так просто. Нужно обязательно перепрошивать загрузчик на optiboot   с поддержкой 485, там в опциях сборки указываешь пин DE RE. И уже бутлоадер его дергает. В своем приложении обрабатываешь команду ребут. Можешь использовать DudeLib и примеры из него. Там прямо по шагам указано как собрать optiboot. Шьешь другой ардуиной используя скетч arduinoisp.

спасибо за инфу (и по rs485 и по кабелю), я так и предполагал. Попробую.  

MaksVV
Offline
Зарегистрирован: 06.08.2015

riv пишет:

CAN ID разбил на разряды 

//ID structure   xx.yy.z.a.cc
//      xx               yy                                z             a                        cc
//  my address   remote address    type message  device address     device type 
 
 
В данной структуре ID есть не точность т.к. XX - имеет не весь диапазон (т.е. не 256 значений), потому как здесь 29 бит, а не 32. Первый Х будет принимать значения только от 0 до 7.
 
И что-то не попёрли у меня 29 битные ID. То анализатор CAN шины не видит 29 бит (видит только последние три разряда - стандартные 11 бит) . То МК также себя ведёт. Может с библиотекой чего то не допонял. 
Короче для себя решил сделать так, в топку эти нестандартные 29 бит. Структура ID будет такая:
 
//11-bit ID structure:  XYY
 
X - тип сообщения (т.к. 11 бит этот разряд может принимать значение от 0 до 7, но мне этого хватит)
 
YY - адрес МК, которому это сообщение предназначено (например FF - широковещательное)
 
а адрес отправителя запихаю в нулевой байт поля данных самого сообщения. 
 
Типов сообщения придумал четыре
 
1. Сообщение команды 
2. Сообщение отчета о выполненной команде
3. Статусы, состояния, данные с датчиков и т.п. Datastream короче
4. Ошибки (коды неисправностей данного модуля). 
 
MaksVV
Offline
Зарегистрирован: 06.08.2015

Анализтор CAN шины можно сделать за 5 мин, используя программу CanHacker, arduino и модуль mcp2515

MaksVV
Offline
Зарегистрирован: 06.08.2015

MaksVV пишет:
Короче для себя решил сделать так, в топку эти нестандартные 29 бит. Структура ID будет такая:

 
//11-bit ID structure:  XYY
 
X - тип сообщения (т.к. 11 бит этот разряд может принимать значение от 0 до 7, но мне этого хватит)
 
YY - адрес МК, которому это сообщение предназначено (например FF - широковещательное)
 
а адрес отправителя запихаю в нулевой байт поля данных самого сообщения.
 
В общем подумал, так тоже не сканает. Потому что при таком подходе сообщения с одним и тем же  ID могут посылать разные МК и временные интервалы фрейма с одним и тем же ID могут быть всегда разные и может так попасть, что задержка между ними будет меньше 10мс, и такие сообщения могут теряться (получающий МК не успеет их прочитать). 
 
решил всё таки в ID зашифровывать только адрес отправителя и получателя. Т.е. структуру ID можно сделать так: 
 
ID XYZ   где Z - адрес получателя,  Y - адрес отправителя . В таком формате адресов всего 16. Кому хватит, можно и так пользоваться. Но я решил сразу на будущее сделать хотябы 32 адреса. X полноценно использовать нельзя, т.к. этот разряд имеет три бита, вместо четырёх. Мы будем использовать два бита этого разряда. Итого у нас получается 5 битный адрес (от 0 до 31). Т.е. мы используем 10 бит CAN ID из 11 доступных. 
 
вот как вытянуть 5 битный адрес получателя и отправителя из ID и также , наоборот, как зашифровывать в CAN ID адреса: 
#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg;
MCP2515 mcp2515(10);

uint8_t Adresat; // адрес получателя
uint8_t AdresaNt; // адрес отправителя

unsigned long IDnew; // переменная нового ID

void setup() {
  Serial.begin(9600);
  SPI.begin();
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_125KBPS);
  mcp2515.setNormalMode();
  
  
}

void loop() {
  
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {// если получили CAN фрейм
      
    Serial.println(canMsg.can_id, HEX); // print ID

Adresat  = (canMsg.can_id & B11111);   // вытягиваем 5-битный адрес получателя из ID
AdresaNt = (canMsg.can_id & 0x3E0)>>5; // вытягиваем 5-битный адрес отправителя из ID   
//распечатаем адреса 
Serial.print("Adresat ");  Serial.println(Adresat);
Serial.print("AdresaNt "); Serial.println(AdresaNt);

// и запихнем эти адреса обратно в CAN ID (ну просто в переменную IDnew)

IDnew = ( ( unsigned int )AdresaNt << 5 ) | Adresat;
    
    Serial.print("IDnew "); Serial.println(IDnew, HEX);
   

    Serial.println();   

       
  }

}

 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

т.к. при 5 битных адресах будет трудно в анализаторе шины визуально мониторить адреса МК, зашифрованные в ID, решил оставить 4 битные адреса. (т.е. в шине может быть 15 адресов МК и один широковещательный).

получился примерно такой протокол.

ID XYZ    где  X тип кадра (от 0 до 7

От 0 до 5 – данные с датчиков, статусы, состояния (от 0 до 5 это страницы кадров, т.е. 6 страниц по 8 байт данных. Итого с одного устройства можно передавать 48 байт за серию из 6 кадров)

6 – команды управления

7 – отчеты о выполненных командах

                   Y - адрес отправителя (от 0 до E, - от любого МК)

                   Z - адрес получателя (от 0 до E, - широковещательный, предназначено всем)

описание протокола CAN - ID лист

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

В протокол CAN шины каждого МК заложил такие правила:

1. Разбираем сообщения из CAN шины, которые адресованы только нам. 

2. Команда на управление чем либо посылается нами с периодичностью 500 мс до тех пор, пока не будет получен отчет о выполнении, но не более 10 раз, по истечение чего, например, можно записывать в еепром код неисправности.

3. Если нами принята команда на управление чем либо, посылаем 3 раза с периодичностью 200 мс отчёт контроллеру, который эту команду нам послал.

Вся CAN шина в программе у меня организована двумя функциями CANread() и CANwrite(), которые крутятся в лупе. 

Помним что ID сообщения кан шины у нас разбит на разряды (читай выше). Работаем с разрядами, вот пример МК_1 всего этого. Проверено, работет хорошо. 

#include <SPI.h>
#include <mcp2515.h>    // библиотека для китайского модуля CAN шины MCP2515

struct can_frame canMsg;              // принимаемое сообщение из кан шины
struct can_frame canMsg_Report;       // сообщение, отсылаемое в шину - отчеты о выполнении команд 
struct can_frame canMsg_WriteData;    // сообщение, отсылаемое в шину - данные, датчики и т.д. 
struct can_frame canMsg_WriteCommand; // сообщение, отсылаемое в шину - команды управления

MCP2515 mcp2515(53);                // пин ардуино к которому подключается CS (SS) модуля MCP 2515


// ниже переменные для организации CAN протокола

unsigned long timer_CANReport = 0;
bool timerenabled_CANReport = 0;

unsigned long prevCANReport = 0;

unsigned long prevCANdata0 = 0;
unsigned long prevCANdata1 = 0;

bool WriteCANReport = 0;
bool WriteCANCommand = 0;

uint8_t CANReport_Number = 0;
uint8_t CANcommand_Number = 0;

void setup() {

  //подготовка сообщения отчетов
  canMsg_Report.can_id  = 0x71F;
  canMsg_Report.can_dlc = 2;
  
  //подготовка сообщения команд  
  canMsg_WriteCommand.can_id  = 0x612;
  canMsg_WriteCommand.can_dlc = 2;
  
  
  SPI.begin();
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_250KBPS); // Скорость CAN шины 
  mcp2515.setNormalMode();

}

void loop() {

 CANread();
 CANwrite();

if (если нужно отправить команду в кан шину) StartCANcommand(0x02, 0x11, 0x2); 
                      // параметры функции (стариший байт команды, мл.байт команды, адрес получателя команды) 
                      // т.е. в этом примере отправляется команда 0211 на МК с адресом "2"
                      // если посмотреть в ID лист, то это включение света в комнате Tanya

}




// адрес данного МК в CAN шине 0x1

void CANread() {
  
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {   // если из CAN пришло сообщение
  if ((canMsg.can_id&0xF)==0xF || (canMsg.can_id&0xF)==0x1){ // если получили широковещательное(0xF) или в наш адрес (0x1)
 
  
  //////////////////////////////////////////ПРИНЯТИЕ СТАТУСОВ, ДАННЫХ С ДАТЧИКОВ, ДАТАСТРИМ КОРОЧЕ
  
  if (((canMsg.can_id&0xF00)>>8)>=0x0 && ((canMsg.can_id&0xF00)>>8) <=0x5){  //если тип полученного сообщения - "статусы, датастрим"

       if (((canMsg.can_id&0xF0)>>4)==0x2){                  // если сообщение от контроллера MK_2 света на втором этаже

          if (((canMsg.can_id&0xF00)>>8)==0x0){             // и если это страница "0" данных
          
 Svet_Tanya =   (canMsg.data[2] & B1);                       //считываем состояние света в битах из байта 2 CAN фрейма 
 Svet_Det =     (canMsg.data[2] & B10)>>1;
 Svet_Katya =   (canMsg.data[2] & B100)>>2;
 Svet_Vanna_2 = (canMsg.data[2] & B1000)>>3;
 Svet_Zal_2 =   (canMsg.data[2] & B10000)>>4;

 Pozhar_Tanya =   (canMsg.data[1] & B1);                     //считываем пож.датчики в битах из байта 1 CAN фрейма
 Pozhar_Det =     (canMsg.data[1] & B10)>>1;
 Pozhar_Katya =   (canMsg.data[1] & B100)>>2;
 Pozhar_Vanna_2 = (canMsg.data[1] & B1000)>>3;
 Pozhar_Zal_2 =   (canMsg.data[1] & B10000)>>4;

 Dvizh_Tanya =   (canMsg.data[0] & B1);                     //считываем датчики движения в битах из байта 0 CAN фрейма
 Dvizh_Det =     (canMsg.data[0] & B10)>>1;
 Dvizh_Katya =   (canMsg.data[0] & B100)>>2;
 Dvizh_Vanna_2 = (canMsg.data[0] & B1000)>>3;
 Dvizh_Zal_2 =   (canMsg.data[0] & B10000)>>4;
                                               }//конец страницы "0" данных
                                         
                                           }//конец данных от МК_2


       if (((canMsg.can_id&0xF0)>>4)==0x3){                  // если сообщение от контроллера MK_3 в беседке 

        if (((canMsg.can_id&0xF00)>>8)==0x0)  {               // и если это страница "0" данных
  
 Dvizh_Stoyanka = (canMsg.data[0] & B1);                    //считываем датчики движения из байта 0 CAN фрейма
 Dvizh_Gazon =    (canMsg.data[0] & B10)>>1;
 Dvizh_Yablonya = (canMsg.data[0] & B100)>>2;
 Dvizh_Teplica =  (canMsg.data[0] & B1000)>>3;
 
 SilaSveta = canMsg.data[1]  ;                                //считываем освещённость улицы из байта 1 CAN фрейма
              
 Svet_Besedka_Shar1 = (canMsg.data[2] & B1);                 //считываем состояние света из байта 2 CAN фрейма 
 Svet_Besedka_Dlin =  (canMsg.data[2] & B10)>>1;
 Svet_Besedka_Shar2 = (canMsg.data[2] & B100)>>2;                                          
                                          
                                               }//конец страницы "0" данных
                                          
                                            }// конец данных от МК_3
  
  
                                                                         }/////////////// конец статусов, датастрима

/////////////////////////////////////////////ПРИНЯТИЕ КОМАНД УПРАВЛЕНИЯ

 if (((canMsg.can_id&0xF00)>>8)==0x6) {                                 //если тип полученного сообщения - "Команды управления"

            if (canMsg.data[0]==0x01) {                                           //если тип команды - "Управление охраной" (старш. байт 0x01)

      if (canMsg.data[1]==0x02) {CAN = 1 ; if (signaliz)signalizOFF(); CAN = 0; StartCANReport();} //отреагируем на команду 0102, пошлём отчет
else  if (canMsg.data[1]==0x12) {CAN = 1; if (!signaliz) signalizON(); CAN = 0; StartCANReport();} //отреагируем на команду 0112, пошлём отчет 
                                       
                                      }

       



                                       
                                                                         }/////////////// конец принятия команд из CAN шины 
 
//////////////////////////////////////////// ПРИНЯТИЕ ОТЧЁТОВ ИЗ CAN О НАЗНАЧЕННЫХ ДО ЭТОГО НАМИ КОМАНДАХ В CAN 

if (WriteCANCommand && ((canMsg.can_id&0xF00)>>8)==0x7){ //если в данный момент ждём отчета о выполнении команды и тип полученного сообщения - "Отчеты о выполнении команд"
                                                       
  
if (canMsg_WriteCommand.data[0]==canMsg.data[0] && canMsg_WriteCommand.data[1]==canMsg.data[1] ){  //если отчет совпадает с командой

CANcommand_Number = 0; timerenabled_CANReport = 0; WriteCANCommand=0;}                             // прекращаем подавать CAN команду
  

                                                                          } /////////////// конец принятия отчётов о выполнении команд из CAN шины 
                                                            
  }}}




  void CANwrite() {

//////////////////////////////////////// ОТПРАВКА ОТЧЕТОВ О ВЫПОЛНЕННЫХ КОМАНДАХ (3 раза через 200мс)

if (WriteCANReport){           
  
  
  if (millis() - prevCANReport>200){
   
    mcp2515.sendMessage(&canMsg_Report);
    
    CANReport_Number++; 
    
    if (CANReport_Number>=3) CANReport_Number = 3;
    
    prevCANReport = millis();}
  
  
  if (CANReport_Number>=3) {WriteCANReport = 0;  CANReport_Number = 0;}
  
  
  }


/////////////////////////////////////////// ПЕРИОДИЧЕСКАЯ ОТПРАВКА ДАННЫХ ДАТЧИКОВ, СТАТУСОВ, ПАРАМЕТРОВ В CAN ШИНУ 

if (millis() - prevCANdata1 > 1000){                       // периодически передаём 1-ю страницу (состояние охраны)

    canMsg_WriteData.can_id  = 0x11F;
    canMsg_WriteData.can_dlc = 1;
    canMsg_WriteData.data[0] = 0;
  if (signaliz) canMsg_WriteData.data[0] |= (1 << 2);      // запишем состояние охраны в бит 2 байта0 
else            canMsg_WriteData.data[0] &= ~(1 << 2);

   
   mcp2515.sendMessage(&canMsg_WriteData);
  
  
  
  prevCANdata1 = millis();
  }// конец отправки данных страницы "1" широковещательно


  else if (millis() - prevCANdata0 > 300){                                 // периодически передаём 0-ю страницу (время)

    canMsg_WriteData.can_id  = 0x01F;
canMsg_WriteData.can_dlc = 8;
    canMsg_WriteData.data[0] = Secunda;
    canMsg_WriteData.data[1] = Minuta;
    canMsg_WriteData.data[2] = Chas;
    canMsg_WriteData.data[3] = Day;
    canMsg_WriteData.data[4] = Weekday;
    canMsg_WriteData.data[5] = Month;
    canMsg_WriteData.data[6] = 18;
if (V220)     canMsg_WriteData.data[7] |= (1 << 0);      // запишем состояние напряжения сети в бит 0 байта 7 
else          canMsg_WriteData.data[7] &= ~(1 << 0);     // значение бита 1 - есть напряжение,  0 - нет напряжения
   
   mcp2515.sendMessage(&canMsg_WriteData);
  
  
  
  prevCANdata0 = millis();
  }// конец отправки данных страницы "0" (это время) широковещательно

///////////////////////////////////////////// ОТПРАВКА КОМАНД УПРАВЛЕНИЯ В CAN ШИНУ 

if (WriteCANCommand){                                                       // если установлена отправка CAN команды
  

if (!timerenabled_CANReport) {   mcp2515.sendMessage(&canMsg_WriteCommand); // отправляем команду в CAN шину, если таймер выключен
                                 timerenabled_CANReport = 1;                // включаем таймер   
                                 timer_CANReport = millis();                // обнуляем таймер
                                 CANcommand_Number++;                       // +1 к количеству отправленных команд

}

if (timerenabled_CANReport && millis()-timer_CANReport>500) {              //если через полсекунды мы всё ещё НЕ получили отчет о выполненной команде, всё по новой
  
                                 mcp2515.sendMessage(&canMsg_WriteCommand); // отправляем команду в CAN шину
                                 CANcommand_Number++;                       // +1 к количеству отправленных команд
if (CANcommand_Number>=10) {CANcommand_Number = 0; timerenabled_CANReport = 0; WriteCANCommand = 0;}// если через 10 раз так и не получили отчет, бросаем это дело
else                             timer_CANReport = millis();                // обнуляем таймер
                                           
  
  
  }






}// конец отправки команд в CAN шину
  }// конец CANwrite()



  void StartCANcommand (byte byte0, byte byte1, byte adr){   // функция пишет номер команды в байты CAN сообщения-команд
                                                             // а также забивает в ID сообщения адрес получателя команды
   
    WriteCANCommand = 1; 
    canMsg_WriteCommand.data[0]=byte0; 
    canMsg_WriteCommand.data[1]=byte1; 
    canMsg_WriteCommand.can_id=canMsg_WriteCommand.can_id & 0xFF0|adr;
    CANcommand_Number = 0;
    timerenabled_CANReport = 0;
        
    }


    void StartCANReport (){  // функция пишет номер команды из принятого из CAN сообщения-команды в отправиляемый в CAN отчет,
                             // о выполненной команде, также направляет отчет тому МК, который нам послал команду 
   
    WriteCANReport = 1; 
    canMsg_Report.data[0]=canMsg.data[0]; 
    canMsg_Report.data[1]=canMsg.data[1]; 
    canMsg_Report.can_id=canMsg_Report.can_id & 0xFF0|(canMsg.can_id&0xF0)>>4;  
    CANReport_Number = 0;
    
        
    }

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

сегодня, наконец, протянул витую пару. Запустил CAN шину. Соединил МК на втором этаже (адрес у него 0х2) и МК на первом этаже (адрес 0х1). Скорость поставил 125кБит/с. Больше мне не нужно. 

По вышеописанному протоколу работает просто отлично! Что не может не радовать. 

riv
Offline
Зарегистрирован: 20.07.2017

Супер!. Осталось MQTT поверх CAN запустить и привязывайся к любому серверу УД.

Вот человек уже сделал https://github.com/c3re/can2mqtt

P.S. Я только заканчиваю ремонт, кабели затянул. Силовые щиты собрал.  Скоро присоединюсь.

MaksVV
Offline
Зарегистрирован: 06.08.2015

кстати спасибо за идею конструкцией заголовка ID! Так намного удобнее. Про MQTT почитаю. Эмм вообще не слышал что это . и да,  Ссылка не работает

riv
Offline
Зарегистрирован: 20.07.2017

Извиняюсь, пробел в ссылке в конце затесался. https://github.com/c3re/can2mqtt

MQTT (Message Queue Telemetry Transport) — упрощённый сетевой протокол, работающий поверх TCP/IP, RS485 Используется для обмена сообщениями между устройствами по принципу издатель-подписчик. Теперь вот через CAN.

Он серверным софтом УД поодерживается для обмена с дачтиками и ИУ.  

Без этого УД не построить. На ардуине скорее ДУ и автоматика, а сценарии управления автоматикой они в софте выше.

Есть смысл посмотреть OpenHub, Majordomo, IoBroker, Domoticz это из бесплатного. Ставить на сервер или на одноплатный комп.

riv
Offline
Зарегистрирован: 20.07.2017

Кстати я не совсем понял причину отказа от расширенного заголовка. Только из-за того, что анализатор шины его не видит?