Не могу понять, каким образом CAN противостоит коллизиям, как это реализовано. Есть модуль вот такой http://arduino55.ru/modules/tja1050.html и похожие, и даже библиотека, но в ней ничего про коллизии нет.
Быстродействие CAN сети (до 1 Mbit/s) достигается благодаря механизму недеструктивного арбитража шины посредством сравнения бит конкурирующих сообщений. Т.е. если случится так что одновременно начнут передачу несколько контроллеров, то каждый из них сравнивает бит, который собирается передать на шину с битом, который пытается передать на шину конкурирующий контроллер. Если значения этих битов равны оба контроллера пытаются передать следующий бит. И так происходит до тех пор пока значения передаваемых битов не окажутся различными. Теперь контроллер, который передавал логический ноль (более приоритетный сигнал) будет продолжать передачу, а другой(другие) контроллер прервёт свою передачу до того времени пока шина вновь не освободится. Конечно ,если шина в данный момент занята ,то контроллер не начнет передачу до момента её освобождения.
Эта спецификация CAN исходит из предположения, что все CAN контроллеры принимают сигналы с шины одновременно. Т.е. в одно и то же время один и тот же бит принимается всеми контроллерами в сети. С одной стороны такое положение вещей делает возможным побитовый арбитраж, а с другой стороны ограничивает длину CAN bus. Сигнал распространяется по CAN bus с огромной, но конечной, скоростью и для правильной работы CAN нужно , чтобы все контроллеры "услышали" его почти одновременно. Почти, потому что каждый контроллер принимает бит в течении определённого промежутка времени, отсчитываемого системным часам. Таким образом, чем выше скорость передачи данных, тем меньшая длинна CAN bus возможна.
Получается там аппаратный арбитраж, даже делать ничего не надо. Прям какая-то фантастика
Значит это не мой пакет, а лажа)))) Протоколом определено только 9 байт в пакете.
Именно поэтому ты их не вычитываешь из приемника, а оставляешь.... кому? Придут еще 9 байт, будет 17 или 19 байт в приемнике - тоже не твой пакет...!? Будешь ждать пока чисто случайно в приемнике не окажется ровно 9 байт?
gonzales пишет:
Как тут цитирование ставить?)))
Вот так: [ quote=gonzales]Как тут цитирование ставить?)))[ /quote]
только лишний пробел после [ убери.
gonzales пишет:
Получается там аппаратный арбитраж, даже делать ничего не надо. Прям какая-то фантастика
Дело за CAN контроллером, которого в дуине нет. Остается только прикрутить CAN интерфейс к UARTу, потеряв побитовый арбитраж, но взамен получив побайтовый.
Именно поэтому ты их не вычитываешь из приемника, а оставляешь.... кому? Придут еще 9 байт, будет 17 или 19 байт в приемнике - тоже не твой пакет...!? Будешь ждать пока чисто случайно в приемнике не окажется ровно 9 байт
Спасибо!!!! Понял! То есть считывать в любом случае надо, а уже потом разобраться, мое - не мое.
Andy пишет:
Остается только прикрутить CAN интерфейс к UARTу, потеряв побитовый арбитраж, но взамен получив побайтовый.
Вот сейчас не понял)))) Если можно, поясни более развернуто, для чайников.
Спрошу еще сразу. Есть микросхема приемопередатчика CAN - MCP2551, у нее с одной стороны Tx, Rx, с другой CAN_H, CAN_L. Но его не цеплят напрямую к ардуино, а делают связку через CAN-контроллер MCP2515, который цепляют к ардуино по SPI. Мне не понятно, какие функции у CAN-контроллера и почему нельзя напрямую использовать приемопередатчик CAN, соединив его с ардуино по UART
Есть микросхема приемопередатчика 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е - то что реально происходит на шине.
Andy, спасибо за разъяснения!!! Многое становится понятным!
Andy пишет:
MCP2515 - контроллер, реализует CAN протокол, алгоритм взаимодействия.
А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.
Andy пишет:
Что это даст: можно слушать шину во время передачи и сравнивать, что передаешь, с тем, что принимаешь (побайтово, UART все таки), и тем самым определить наличие колизии. В RS485 ты слышишь только то, что передаешь, а в CANе - то что реально происходит на шине.
Как раз хотел об этом спросить, прочитал в инете, что какие-то умельцы строят арбитраж RS485 по принципу CAN, то есть слушаешь, что передаешь и сравниваешь с тем, что должен передать - если не совпало, значит коллизия. Но как это реализовать, не понятно, ведь передавая что-то через UART, там же ничего в буфере не остается, что с чем сравнивать-то? Использовав RS485.write(200); а затем x=RS485.read() у меня же не будет x==200, или я не прав?
А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.
Да, так и есть. Я для себя ничего хорошего в этом протоколе не нашел.
gonzales пишет:
умельцы строят арбитраж RS485 по принципу CAN, то есть слушаешь, что передаешь и сравниваешь с тем, что должен передать - если не совпало, значит коллизия. Но как это реализовать, не понятно, ведь передавая что-то через UART, там же ничего в буфере не остается, что с чем сравнивать-то? Использовав RS485.write(200); а затем x=RS485.read() у меня же не будет x==200, или я не прав?
В RS485 сигнал разрешения передачи лог.1, а приема - лог.0. Их обычно объединяют в один сигнал и если передают, то ничего не слушают. В CANе приемник разрешен всегда, следовательно все, что передается будет поступать в приемник и если в это время кто-то еще передает, то коллизию можно обнаружить по несовпадению передаваемого и принимаемого байта.
давно уже все изобрели. надо делать тогда отдельный контроллер шины который и будет получать чужие пакеты и передавать по адресу когда приемник будет готов.
а то понаделают щаз всяких сигнализаций которые в этот момент будут данные туда-.сюда гонять а не датчики опрашивать.
А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.
Да, так и есть. Я для себя ничего хорошего в этом протоколе не нашел.
А можно узнать почему в CAN ничего хорошего не нашли? Ведь в нем решены некторые проблемы, обсуждаемые в теме. Например:
- борьба с коллизиями возложена не на программиста, а на микросхему
- Система мультимастерная
- скорость работы высокая ( будет быстрое реагирование между разными МК)
- помехозащищенность на уровне
- стомость не высокая. SPI адаптер CAN для ардуино на MCP2515 стоит немногим более 100 руб.
- и ведь CAN широко применяется в промышленности и автомобилях, наверное не просто так.
- нет такого как в rs 485, что если мастер лёг - легла вся шина
Тут говорят зачем для дома CAN? зачем усложнять? Дак если не дорого и присутствуют плюсы то почему бы и нет.
тем более в шину можно тупо "серить" пакетами с разной инфой. Кому надо, тот возмет пакет с нужным ID
Ожидания оправдались. Все плюсы постом выше действительно присутствуют. Модуль работает по SPI. Пробовал подключать два модуля к ондной шине SPI всё работает. Т.е. можно на одной ардуино нано делать несколько CAN шин. Кто собрался делать сеть между контроллерами рекомендую CAN шину. модуль недорогой, в пределах 150 руб. Скорость высокая, т.е. например если выключатели света подключать по кан, будет быстро реагировать, не то что по RS485. Да и вообще новичку проще с кан работать. Там весь арбитраж шины аппаратный, ничё придумывать не надо. Сразу работаешь с сообщениями. Для меня это главный фактор, так как я ни разу не программист. Тупо использовал пример из библиотеки и вперёд.
Короче RS485 в топку. Удобнее всего наверное делать территориальное разделение по микроконтроллерам умного дома, т.е. в каждой комнате по МК с этим кан модулем.
PS. для работы с CAN сразу сделал анализатор шины за 5 мин. Просто залив библиотеку MCP2515 CAN HACKER. Программа хорошая, можно просматривать что происходит в шине, записывать поток сообщений, потом воспроизводить эту запись в шину, короче гуд. Прогу и билиотеку легко найти в инете.
ESP-шка стоит столько же. Преимущество - связь между точками можно сделать по WiFi, то есть беспроводную. Управлять же всем хозяйством можно со смартфона или с помощью Web-интерфейса. И она сама по себе неплохой контроллер, под который можно писать на Arduino или на других средствах разработки...
не доверяю я радио каналу, в кане протокол мне понятный, а по вифи как данные гонять - темный лес. Но вообще согласен, неплохой модуль. Экономия на ардуинах, их тогда будет не надо. И если есть знания по ESPшке , то сам бог велел её пользовать.
кан как раз сейчас и начинает вытеснять остальные протоколы в области уд и иот. Wi-fi здесь как раз гораздо неэффективнее того же RS485. Смысл гонять на таких частотах мелкие пакеты раз в 5 минут. Кан как раз удобнее за счет скорости и обособленности всей системы. Ничего лишнего не прилетает. Все сигналы от/к устройствам ВНУТРИ системы. Когда по wi-fi летает все подряд, занимают ip пространство даже простой датчик.
если есть люди, кто будет строить кан сеть, давайте свой стандарт создадим. Т.е. какой ID и дата байты в нём за что отвечают, чтоб не было как у автопроизводителей - у каждого свой ID лист.
Так проще будет.
Наример ID 001 передает в шину время. 002 - состояние охраны дома. периметра и т.д.
Не забываем, что в отличае от rs-485_модбас и им подобных, в CAN шине "ID" обозначает не идент.номер контроллера. а идент.номер сообщения.
Поэтому нулевым байтом в любом сообщении можно сделать номер контроллера, который это сообщение послал.
В данном случае деление МК идёт по территориальному признаку. Т.е. каждый отдельный МК "обслуживает" свою комнату.
Для себя посчитал это более оптимальным с точки зрения протяжки количества проводов. В каждую комнату нужно будет кинуть два кабеля - силовой 220В и витую пару желательно в экране (CAN шина и питание МК). Так же в систему проще добавлять новые элементы.
вышесказанное это по сравнениию с концепцией деления отдельных МК по функциональному признаку (Один МК - отопление, второй - освещение, третий - коммуникация и т.д.) и с концепцией, когда вообще всем рулит только один МК.
Минусом моего варианта можно посчитать необходимость создания в каждой комнате небольшого распределительного щитка, но если на печатке всё делать можно легко уложиться в стандартные распределительные коробки.
В данном случае деление МК идёт по территориальному признаку. Т.е. каждый отдельный МК "обслуживает" свою комнату.
Пришел к аналогичной концепции построения сети. 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 испоьзую для удаленной прошивки, от всех модулей вывел пары к себе к рабочему столу.
// my address remote address type message device address device type
На CAN модуле есть линия INT ее рекомендую использовать, как прерывание на тему наличия своей передачи.
вот этого не понял, напиши по русски.
xx.yy.z.a.cc это всё в ID заголовке чтоли зашифровано? т.е. 29 битный ID используешь?
А INT я так понимаю на внешнее прерывание дуни нужно подключать, чтобы оперативнее реагировать на сообщения, когда они в данный момент прилетели, т.е. всё бросаем, и идём в обработчик прерывания парсить кан сообщение.
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 а мк через реле щелкает выключателем), жалюзи, протечки и газ запорные клапана само собой.
Серьезные планы. 500 кБит если на 100 метрах пашет, это гуд. У меня такие же расстояния. А как подключаешь rs485 для удаленной прошивки? Просто поискал инфу прошивки ардуино по RS485, рабочего варианта так и не смог найти. Даже попробовал прошить по 485 через переходник USB->RS485 со стороны компа и китайский модуль RS485 со стороны дуни. Естесственно ничего не получилось. Я так понимаю при заливке прошивки обмен данными между IDE и ардуино идёт туда сюда, а не в одну сторону, поэтому на ардуине нужно дёргать пин прием-передача, а кто его будет дергать то в момент перепрошивки? Bootloader нужен другой, как я понимаю, причем в котором желательно пин , дёргающий приём-передачу, чтоб можно было выбирать.
По поводу 485 его использую как конвертер rs232-rs485-rs485-rs232 точка точка. (По поводу сетевой прошивки через 485 , витали идеи по форуму, выдавать команду по сети, не принимать команды всем кроме нужного в течении 2-5 минут). Мне это не очень интересно. На магистрали мономастер тупик. Для достижения дальности 100 метров использую сигнальный кабель. (Хотя по честному у меня линии более 30 метров и нет). Причем питание 12 вольт подаю по 2й паре. Этот же кабель использую на датчики и слаботочные исполнительные у-ва.
дак я так и подключал. Что нужно чтобы скетч загрузился? На какой пин DE RE подключаешь и через что скетч грузишь - IDE?
Все не так просто. Нужно обязательно перепрошивать загрузчик на optiboot с поддержкой 485, там в опциях сборки указываешь пин DE RE. И уже бутлоадер его дергает. В своем приложении обрабатываешь команду ребут. Можешь использовать DudeLib и примеры из него. Там прямо по шагам указано как собрать optiboot. Шьешь другой ардуиной используя скетч arduinoisp.
У меня сейчас основная проблема перекроить optiboot под 2560, вроде есть решения №1 и №2 но руки не доходят. Честно говоря В плотную займусь этим после НГ. Сейчас как я и говорил занимаюсь прокладкой и прототипированием. Все на столе и иногда выезжает в поле для опытов. Пока скорее выбираю и опробую технологии на предмет использования. Без вылизывания кода.
Есть еще один вариант но не проверял. (И он точно в сети работать не будет из-за колизий). Это использование чипа с автоопределением RX TX - MAX13487/13488
Кстати по кабелям, очень много сигнальных - контрольных кабелей у пожарников (ОПС, ВН) и асутпшников (АСКУЭ, АСУТП, etc) . Набери сигнальный кабель для 485 и дальше выбирай под задачу.
Я так понимаю при заливке прошивки обмен данными между IDE и ардуино идёт туда сюда, а не в одну сторону, поэтому на ардуине нужно дёргать пин прием-передача, а кто его будет дергать то в момент перепрошивки? Bootloader нужен другой, как я понимаю, причем в котором желательно пин , дёргающий приём-передачу, чтоб можно было выбирать.
riv пишет:
Все не так просто. Нужно обязательно перепрошивать загрузчик на optiboot с поддержкой 485, там в опциях сборки указываешь пин DE RE. И уже бутлоадер его дергает. В своем приложении обрабатываешь команду ребут. Можешь использовать DudeLib и примеры из него. Там прямо по шагам указано как собрать optiboot. Шьешь другой ардуиной используя скетч arduinoisp.
спасибо за инфу (и по rs485 и по кабелю), я так и предполагал. Попробую.
// 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 короче
Короче для себя решил сделать так, в топку эти нестандартные 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 адреса:
т.к. при 5 битных адресах будет трудно в анализаторе шины визуально мониторить адреса МК, зашифрованные в ID, решил оставить 4 битные адреса. (т.е. в шине может быть 15 адресов МК и один широковещательный).
получился примерно такой протокол.
ID XYZ гдеX тип кадра (от 0 до 7 )
От 0 до 5 – данные с датчиков, статусы, состояния (от 0 до 5 это страницы кадров, т.е. 6 страниц по 8 байт данных. Итого с одного устройства можно передавать 48 байт за серию из 6 кадров)
6 – команды управления
7 – отчеты о выполненных командах
Y - адрес отправителя (от 0 до E, F - от любого МК)
Z - адрес получателя (от 0 до E, F - широковещательный, предназначено всем)
В протокол CAN шины каждого МК заложил такие правила:
1. Разбираем сообщения из CAN шины, которые адресованы только нам.
2. Команда на управление чем либо посылается нами с периодичностью 500 мс до тех пор, пока не будет получен отчет о выполнении, но не более 10 раз, по истечение чего, например, можно записывать в еепром код неисправности.
3. Если нами принята команда на управление чем либо, посылаем 3 раза с периодичностью 200 мс отчёт контроллеру, который эту команду нам послал.
Вся CAN шина в программе у меня организована двумя функциями CANread() и CANwrite(), которые крутятся в лупе.
Помним что ID сообщения кан шины у нас разбит на разряды (читай выше). Работаем с разрядами, вот пример МК_1 всего этого. Проверено, работет хорошо.
#include <mcp2515.h> // библиотека для китайского модуля CAN шины MCP2515
003
004
structcan_frame canMsg; // принимаемое сообщение из кан шины
005
structcan_frame canMsg_Report; // сообщение, отсылаемое в шину - отчеты о выполнении команд
006
structcan_frame canMsg_WriteData; // сообщение, отсылаемое в шину - данные, датчики и т.д.
007
structcan_frame canMsg_WriteCommand; // сообщение, отсылаемое в шину - команды управления
008
009
MCP2515 mcp2515(53); // пин ардуино к которому подключается CS (SS) модуля MCP 2515
010
011
012
// ниже переменные для организации CAN протокола
013
014
unsigned longtimer_CANReport = 0;
015
booltimerenabled_CANReport = 0;
016
017
unsigned longprevCANReport = 0;
018
019
unsigned longprevCANdata0 = 0;
020
unsigned longprevCANdata1 = 0;
021
022
boolWriteCANReport = 0;
023
boolWriteCANCommand = 0;
024
025
uint8_t CANReport_Number = 0;
026
uint8_t CANcommand_Number = 0;
027
028
voidsetup() {
029
030
//подготовка сообщения отчетов
031
canMsg_Report.can_id = 0x71F;
032
canMsg_Report.can_dlc = 2;
033
034
//подготовка сообщения команд
035
canMsg_WriteCommand.can_id = 0x612;
036
canMsg_WriteCommand.can_dlc = 2;
037
038
039
SPI.begin();
040
041
mcp2515.reset();
042
mcp2515.setBitrate(CAN_250KBPS); // Скорость CAN шины
043
mcp2515.setNormalMode();
044
045
}
046
047
voidloop() {
048
049
CANread();
050
CANwrite();
051
052
if(если нужно отправить команду в кан шину) StartCANcommand(0x02, 0x11, 0x2);
053
// параметры функции (стариший байт команды, мл.байт команды, адрес получателя команды)
054
// т.е. в этом примере отправляется команда 0211 на МК с адресом "2"
055
// если посмотреть в ID лист, то это включение света в комнате Tanya
056
057
}
058
059
060
061
062
// адрес данного МК в CAN шине 0x1
063
064
voidCANread() {
065
066
if(mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) { // если из CAN пришло сообщение
067
if((canMsg.can_id&0xF)==0xF || (canMsg.can_id&0xF)==0x1){ // если получили широковещательное(0xF) или в наш адрес (0x1)
068
069
070
//////////////////////////////////////////ПРИНЯТИЕ СТАТУСОВ, ДАННЫХ С ДАТЧИКОВ, ДАТАСТРИМ КОРОЧЕ
071
072
if(((canMsg.can_id&0xF00)>>8)>=0x0 && ((canMsg.can_id&0xF00)>>8) <=0x5){ //если тип полученного сообщения - "статусы, датастрим"
073
074
if(((canMsg.can_id&0xF0)>>4)==0x2){ // если сообщение от контроллера MK_2 света на втором этаже
075
076
if(((canMsg.can_id&0xF00)>>8)==0x0){ // и если это страница "0" данных
077
078
Svet_Tanya = (canMsg.data[2] & B1); //считываем состояние света в битах из байта 2 CAN фрейма
079
Svet_Det = (canMsg.data[2] & B10)>>1;
080
Svet_Katya = (canMsg.data[2] & B100)>>2;
081
Svet_Vanna_2 = (canMsg.data[2] & B1000)>>3;
082
Svet_Zal_2 = (canMsg.data[2] & B10000)>>4;
083
084
Pozhar_Tanya = (canMsg.data[1] & B1); //считываем пож.датчики в битах из байта 1 CAN фрейма
085
Pozhar_Det = (canMsg.data[1] & B10)>>1;
086
Pozhar_Katya = (canMsg.data[1] & B100)>>2;
087
Pozhar_Vanna_2 = (canMsg.data[1] & B1000)>>3;
088
Pozhar_Zal_2 = (canMsg.data[1] & B10000)>>4;
089
090
Dvizh_Tanya = (canMsg.data[0] & B1); //считываем датчики движения в битах из байта 0 CAN фрейма
091
Dvizh_Det = (canMsg.data[0] & B10)>>1;
092
Dvizh_Katya = (canMsg.data[0] & B100)>>2;
093
Dvizh_Vanna_2 = (canMsg.data[0] & B1000)>>3;
094
Dvizh_Zal_2 = (canMsg.data[0] & B10000)>>4;
095
}//конец страницы "0" данных
096
097
}//конец данных от МК_2
098
099
100
if(((canMsg.can_id&0xF0)>>4)==0x3){ // если сообщение от контроллера MK_3 в беседке
101
102
if(((canMsg.can_id&0xF00)>>8)==0x0) { // и если это страница "0" данных
103
104
Dvizh_Stoyanka = (canMsg.data[0] & B1); //считываем датчики движения из байта 0 CAN фрейма
105
Dvizh_Gazon = (canMsg.data[0] & B10)>>1;
106
Dvizh_Yablonya = (canMsg.data[0] & B100)>>2;
107
Dvizh_Teplica = (canMsg.data[0] & B1000)>>3;
108
109
SilaSveta = canMsg.data[1] ; //считываем освещённость улицы из байта 1 CAN фрейма
110
111
Svet_Besedka_Shar1 = (canMsg.data[2] & B1); //считываем состояние света из байта 2 CAN фрейма
112
Svet_Besedka_Dlin = (canMsg.data[2] & B10)>>1;
113
Svet_Besedka_Shar2 = (canMsg.data[2] & B100)>>2;
114
115
}//конец страницы "0" данных
116
117
}// конец данных от МК_3
118
119
120
}/////////////// конец статусов, датастрима
121
122
/////////////////////////////////////////////ПРИНЯТИЕ КОМАНД УПРАВЛЕНИЯ
123
124
if(((canMsg.can_id&0xF00)>>8)==0x6) { //если тип полученного сообщения - "Команды управления"
125
126
if(canMsg.data[0]==0x01) { //если тип команды - "Управление охраной" (старш. байт 0x01)
127
128
if(canMsg.data[1]==0x02) {CAN = 1 ; if(signaliz)signalizOFF(); CAN = 0; StartCANReport();} //отреагируем на команду 0102, пошлём отчет
129
elseif(canMsg.data[1]==0x12) {CAN = 1; if(!signaliz) signalizON(); CAN = 0; StartCANReport();} //отреагируем на команду 0112, пошлём отчет
130
131
}
132
133
134
135
136
137
138
}/////////////// конец принятия команд из CAN шины
139
140
//////////////////////////////////////////// ПРИНЯТИЕ ОТЧЁТОВ ИЗ CAN О НАЗНАЧЕННЫХ ДО ЭТОГО НАМИ КОМАНДАХ В CAN
141
142
if(WriteCANCommand && ((canMsg.can_id&0xF00)>>8)==0x7){ //если в данный момент ждём отчета о выполнении команды и тип полученного сообщения - "Отчеты о выполнении команд"
143
144
145
if(canMsg_WriteCommand.data[0]==canMsg.data[0] && canMsg_WriteCommand.data[1]==canMsg.data[1] ){ //если отчет совпадает с командой
146
147
CANcommand_Number = 0; timerenabled_CANReport = 0; WriteCANCommand=0;} // прекращаем подавать CAN команду
148
149
150
} /////////////// конец принятия отчётов о выполнении команд из CAN шины
151
152
}}}
153
154
155
156
157
voidCANwrite() {
158
159
//////////////////////////////////////// ОТПРАВКА ОТЧЕТОВ О ВЫПОЛНЕННЫХ КОМАНДАХ (3 раза через 200мс)
if(V220) canMsg_WriteData.data[7] |= (1 << 0); // запишем состояние напряжения сети в бит 0 байта 7
212
elsecanMsg_WriteData.data[7] &= ~(1 << 0); // значение бита 1 - есть напряжение, 0 - нет напряжения
213
214
mcp2515.sendMessage(&canMsg_WriteData);
215
216
217
218
prevCANdata0 = millis();
219
}// конец отправки данных страницы "0" (это время) широковещательно
220
221
///////////////////////////////////////////// ОТПРАВКА КОМАНД УПРАВЛЕНИЯ В CAN ШИНУ
222
223
if(WriteCANCommand){ // если установлена отправка CAN команды
224
225
226
if(!timerenabled_CANReport) { mcp2515.sendMessage(&canMsg_WriteCommand); // отправляем команду в CAN шину, если таймер выключен
227
timerenabled_CANReport = 1; // включаем таймер
228
timer_CANReport = millis(); // обнуляем таймер
229
CANcommand_Number++; // +1 к количеству отправленных команд
230
231
}
232
233
if(timerenabled_CANReport && millis()-timer_CANReport>500) { //если через полсекунды мы всё ещё НЕ получили отчет о выполненной команде, всё по новой
234
235
mcp2515.sendMessage(&canMsg_WriteCommand); // отправляем команду в CAN шину
236
CANcommand_Number++; // +1 к количеству отправленных команд
237
if(CANcommand_Number>=10) {CANcommand_Number = 0; timerenabled_CANReport = 0; WriteCANCommand = 0;}// если через 10 раз так и не получили отчет, бросаем это дело
сегодня, наконец, протянул витую пару. Запустил CAN шину. Соединил МК на втором этаже (адрес у него 0х2) и МК на первом этаже (адрес 0х1). Скорость поставил 125кБит/с. Больше мне не нужно.
По вышеописанному протоколу работает просто отлично! Что не может не радовать.
MQTT (Message Queue Telemetry Transport) — упрощённый сетевой протокол, работающий поверх TCP/IP, RS485 Используется для обмена сообщениями между устройствами по принципу издатель-подписчик. Теперь вот через CAN.
Он серверным софтом УД поодерживается для обмена с дачтиками и ИУ.
Без этого УД не построить. На ардуине скорее ДУ и автоматика, а сценарии управления автоматикой они в софте выше.
Есть смысл посмотреть OpenHub, Majordomo, IoBroker, Domoticz это из бесплатного. Ставить на сервер или на одноплатный комп.
> Рискну предположить, интерфейс реализован на MAX485, а он позволяет только 32 устройства на шине.
Да, физических устройств на шине не более 32 (Про-мини), но к каждому могут быть подключены до трех сенсоров или актуаторов с субадресацией.
> Строка 51. Что если пришло не 9 символов, а меньше или больше?
Значит это не мой пакет, а лажа)))) Протоколом определено только 9 байт в пакете.
Как тут цитирование ставить?)))
>А что тут может быть кривого? Не сочтите за труд посмотрите скеч
Кривая сама IDE, при такой загрузке нужен прямой доступ к ресурсам МК.
Почему? Вы предлагаете использовать CyberLib? Что это даст?
Не могу понять, каким образом CAN противостоит коллизиям, как это реализовано. Есть модуль вот такой http://arduino55.ru/modules/tja1050.html и похожие, и даже библиотека, но в ней ничего про коллизии нет.
Нашел
Арбитраж шины CAN.
Быстродействие CAN сети (до 1 Mbit/s) достигается благодаря механизму недеструктивного арбитража шины посредством сравнения бит конкурирующих сообщений. Т.е. если случится так что одновременно начнут передачу несколько контроллеров, то каждый из них сравнивает бит, который собирается передать на шину с битом, который пытается передать на шину конкурирующий контроллер. Если значения этих битов равны оба контроллера пытаются передать следующий бит. И так происходит до тех пор пока значения передаваемых битов не окажутся различными. Теперь контроллер, который передавал логический ноль (более приоритетный сигнал) будет продолжать передачу, а другой(другие) контроллер прервёт свою передачу до того времени пока шина вновь не освободится. Конечно ,если шина в данный момент занята ,то контроллер не начнет передачу до момента её освобождения.
Эта спецификация CAN исходит из предположения, что все CAN контроллеры принимают сигналы с шины одновременно. Т.е. в одно и то же время один и тот же бит принимается всеми контроллерами в сети. С одной стороны такое положение вещей делает возможным побитовый арбитраж, а с другой стороны ограничивает длину CAN bus. Сигнал распространяется по CAN bus с огромной, но конечной, скоростью и для правильной работы CAN нужно , чтобы все контроллеры "услышали" его почти одновременно. Почти, потому что каждый контроллер принимает бит в течении определённого промежутка времени, отсчитываемого системным часам. Таким образом, чем выше скорость передачи данных, тем меньшая длинна CAN bus возможна.
Получается там аппаратный арбитраж, даже делать ничего не надо. Прям какая-то фантастика
только лишний пробел после [ убери.
Спасибо!!!! Понял! То есть считывать в любом случае надо, а уже потом разобраться, мое - не мое.
Вот сейчас не понял)))) Если можно, поясни более развернуто, для чайников.
Спрошу еще сразу. Есть микросхема приемопередатчика 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е - то что реально происходит на шине.
Andy, спасибо за разъяснения!!! Многое становится понятным!
MCP2515 - контроллер, реализует CAN протокол, алгоритм взаимодействия.
А что именно хорошего в самом протоколе? Он сам следит за арбитражем, коллизиями, очередью посылок и т.д, так? Мне остается только подать ему на вход пакет через UART, правильно я понимаю? Так в случае использования только интерфейса передачи, это все придется писать руками на ардуино. Поправьте, если не прав.
Как раз хотел об этом спросить, прочитал в инете, что какие-то умельцы строят арбитраж RS485 по принципу CAN, то есть слушаешь, что передаешь и сравниваешь с тем, что должен передать - если не совпало, значит коллизия. Но как это реализовать, не понятно, ведь передавая что-то через UART, там же ничего в буфере не остается, что с чем сравнивать-то? Использовав RS485.write(200); а затем x=RS485.read() у меня же не будет x==200, или я не прав?
Заранее извините, если вопросы тупые. ))
Всем Доброгого времени суток!
Присоединюсь к обсуждению, а "full duplex rs485 " не рассматривался?
На просторах интернета нашлась такая схема, имеет ли смысл ее реализовать?
Рассматривался, но пока не приенялся. Попробую обойтись полудуплексом.
Схема, которую Вы представили подходит для связи только двух устройств. Если надо больше, то схема будет другая.
http://www.gaw.ru/html.cgi/txt/interface/rs485/app.htm
Всем Привет!
Есть 8 точек которые расположены в радиусе 100 метров,нужен сбор статистики(2-3 датчика на точке) и управление клапанами 6-12в
Подскажите как можно решить такой вопрос.
Какой смысл спрашивать в чужой, заброшенной теме?
Тем более, что как раз в этой теме достаточно доходчиво разжевана одна из возможных реализаций.
Но по существу: я как раз занимаюсь такой системой. Если есть интерес, напишите в личку
Тем более, что как раз в этой теме достаточно доходчиво разжевана одна из возможных реализаций.
Но по существу: я как раз занимаюсь такой системой. Если есть интерес, напишите в личку
Да,интерес есть,но проблема с личкой,мое мыло taube2002@mail.ru
изобретатели велосипедов все прут и прут.
давно уже все изобрели. надо делать тогда отдельный контроллер шины который и будет получать чужие пакеты и передавать по адресу когда приемник будет готов.
а то понаделают щаз всяких сигнализаций которые в этот момент будут данные туда-.сюда гонять а не датчики опрашивать.
А можно узнать почему в CAN ничего хорошего не нашли? Ведь в нем решены некторые проблемы, обсуждаемые в теме. Например:
- борьба с коллизиями возложена не на программиста, а на микросхему
- Система мультимастерная
- скорость работы высокая ( будет быстрое реагирование между разными МК)
- помехозащищенность на уровне
- стомость не высокая. SPI адаптер CAN для ардуино на MCP2515 стоит немногим более 100 руб.
- и ведь CAN широко применяется в промышленности и автомобилях, наверное не просто так.
- нет такого как в rs 485, что если мастер лёг - легла вся шина
Тут говорят зачем для дома CAN? зачем усложнять? Дак если не дорого и присутствуют плюсы то почему бы и нет.
тем более в шину можно тупо "серить" пакетами с разной инфой. Кому надо, тот возмет пакет с нужным ID
на досуге заказал такой модуль CAN шины
Ожидания оправдались. Все плюсы постом выше действительно присутствуют. Модуль работает по SPI. Пробовал подключать два модуля к ондной шине SPI всё работает. Т.е. можно на одной ардуино нано делать несколько CAN шин. Кто собрался делать сеть между контроллерами рекомендую CAN шину. модуль недорогой, в пределах 150 руб. Скорость высокая, т.е. например если выключатели света подключать по кан, будет быстро реагировать, не то что по RS485. Да и вообще новичку проще с кан работать. Там весь арбитраж шины аппаратный, ничё придумывать не надо. Сразу работаешь с сообщениями. Для меня это главный фактор, так как я ни разу не программист. Тупо использовал пример из библиотеки и вперёд.
Короче RS485 в топку. Удобнее всего наверное делать территориальное разделение по микроконтроллерам умного дома, т.е. в каждой комнате по МК с этим кан модулем.
PS. для работы с CAN сразу сделал анализатор шины за 5 мин. Просто залив библиотеку MCP2515 CAN HACKER. Программа хорошая, можно просматривать что происходит в шине, записывать поток сообщений, потом воспроизводить эту запись в шину, короче гуд. Прогу и билиотеку легко найти в инете.
Некрофилы никак не уймутся. (((
а чё каждый раз то новую тему создавать, будет куча тем, нафиг это надо.
модуль недорогой, в пределах 150 руб.
ESP-шка стоит столько же. Преимущество - связь между точками можно сделать по WiFi, то есть беспроводную. Управлять же всем хозяйством можно со смартфона или с помощью Web-интерфейса. И она сама по себе неплохой контроллер, под который можно писать на Arduino или на других средствах разработки...
не доверяю я радио каналу, в кане протокол мне понятный, а по вифи как данные гонять - темный лес. Но вообще согласен, неплохой модуль. Экономия на ардуинах, их тогда будет не надо. И если есть знания по ESPшке , то сам бог велел её пользовать.
Некрофилы никак не уймутся. (((
кан как раз сейчас и начинает вытеснять остальные протоколы в области уд и иот. Wi-fi здесь как раз гораздо неэффективнее того же RS485. Смысл гонять на таких частотах мелкие пакеты раз в 5 минут. Кан как раз удобнее за счет скорости и обособленности всей системы. Ничего лишнего не прилетает. Все сигналы от/к устройствам ВНУТРИ системы. Когда по wi-fi летает все подряд, занимают ip пространство даже простой датчик.
если есть люди, кто будет строить кан сеть, давайте свой стандарт создадим. Т.е. какой ID и дата байты в нём за что отвечают, чтоб не было как у автопроизводителей - у каждого свой ID лист.
Так проще будет.
Наример ID 001 передает в шину время. 002 - состояние охраны дома. периметра и т.д.
Не забываем, что в отличае от rs-485_модбас и им подобных, в CAN шине "ID" обозначает не идент.номер контроллера. а идент.номер сообщения.
Поэтому нулевым байтом в любом сообщении можно сделать номер контроллера, который это сообщение послал.
Попробовал начать писать протокол. Критикуйте
вот пример кода МК, которому интересно движение в комнате "ванна2". Если там есть движение сообщим, об этом в сериал.
Т.е. нас интересует опрос сообщения с ID 011 бита №3 байта №1.
01
#include <SPI.h>
02
#include <mcp2515.h>
03
04
struct
can_frame canMsg;
05
MCP2515 mcp2515(10);
06
07
08
void
setup
() {
09
Serial
.begin(115200);
10
SPI.begin();
11
12
mcp2515.reset();
13
mcp2515.setBitrate(CAN_125KBPS);
14
mcp2515.setNormalMode();
15
16
17
18
Serial
.println(
"------- CAN Read ID 011 byte 1 bit№3"
);
19
Serial
.println(
""
);
20
21
}
22
23
void
loop
() {
24
25
if
(mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
// если в кан пришло сообщение
26
27
if
(canMsg.can_id==0x011) {
// если ID этого сообщения 011
28
29
if
(bitRead(canMsg.data[1],3)) {
// если бит№3 байта №1 этого сообщения равен 1.
30
Serial
.println (
"Dvizheniе v vannoy!!!"
); }
// пожалуемся в сериал об этом
31
}
32
33
// здесь делаем проверку на другие ID принятого в кан сообщения, если ID более одного
34
35
}
36
37
}
Предлагаю такую архитектуру умного дома. https://yadi.sk/i/SVtm-9N03P5Bno
В данном случае деление МК идёт по территориальному признаку. Т.е. каждый отдельный МК "обслуживает" свою комнату.
Для себя посчитал это более оптимальным с точки зрения протяжки количества проводов. В каждую комнату нужно будет кинуть два кабеля - силовой 220В и витую пару желательно в экране (CAN шина и питание МК). Так же в систему проще добавлять новые элементы.
вышесказанное это по сравнениию с концепцией деления отдельных МК по функциональному признаку (Один МК - отопление, второй - освещение, третий - коммуникация и т.д.) и с концепцией, когда вообще всем рулит только один МК.
Минусом моего варианта можно посчитать необходимость создания в каждой комнате небольшого распределительного щитка, но если на печатке всё делать можно легко уложиться в стандартные распределительные коробки.
Предлагаю такую архитектуру умного дома. https://yadi.sk/i/SVtm-9N03P5Bno
В данном случае деление МК идёт по территориальному признаку. Т.е. каждый отдельный МК "обслуживает" свою комнату.
Пришел к аналогичной концепции построения сети. CAN, управляющий контроллер на помещение, если есть сложные задачи то доп. специализированные контроллеры. (У меня 2 распред щита с импульсными реле на каждый из которых ставлю по своей меге, протечки отдельное устройство и т.п.)
Ардуино размещаю в подрозетниках по потолком. Использую Mega 2560 pro от robotdyn при размере 30 на 52 мм спокойно лезет в подрозетник, который закрываю заглушкой (серия LK60)
CAN ID разбил на разряды
Железка 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
Серьезные планы. 500 кБит если на 100 метрах пашет, это гуд. У меня такие же расстояния. А как подключаешь rs485 для удаленной прошивки? Просто поискал инфу прошивки ардуино по RS485, рабочего варианта так и не смог найти. Даже попробовал прошить по 485 через переходник USB->RS485 со стороны компа и китайский модуль RS485 со стороны дуни. Естесственно ничего не получилось. Я так понимаю при заливке прошивки обмен данными между IDE и ардуино идёт туда сюда, а не в одну сторону, поэтому на ардуине нужно дёргать пин прием-передача, а кто его будет дергать то в момент перепрошивки? Bootloader нужен другой, как я понимаю, причем в котором желательно пин , дёргающий приём-передачу, чтоб можно было выбирать.
По поводу 485 его использую как конвертер rs232-rs485-rs485-rs232 точка точка. (По поводу сетевой прошивки через 485 , витали идеи по форуму, выдавать команду по сети, не принимать команды всем кроме нужного в течении 2-5 минут). Мне это не очень интересно. На магистрали мономастер тупик. Для достижения дальности 100 метров использую сигнальный кабель. (Хотя по честному у меня линии более 30 метров и нет). Причем питание 12 вольт подаю по 2й паре. Этот же кабель использую на датчики и слаботочные исполнительные у-ва.
И все таки мне не понятно. Это так чтоли? Прошиваешь через Arduino IDE?
и можно название кабеля, а то кроме витой пары ниче не могу найти.
S.D.B. LIYCY-0 2x2x0,34 IEC 332.3 F2 ROHS. Брал на avito
Цепочка сильно короче сразу usb-485 - 485 ардуино.
USB-485
к ардуино
дак я так и подключал. Что нужно чтобы скетч загрузился? На какой пин DE RE подключаешь и через что скетч грузишь - IDE?
дак я так и подключал. Что нужно чтобы скетч загрузился? На какой пин DE RE подключаешь и через что скетч грузишь - IDE?
Все не так просто. Нужно обязательно перепрошивать загрузчик на optiboot с поддержкой 485, там в опциях сборки указываешь пин DE RE. И уже бутлоадер его дергает. В своем приложении обрабатываешь команду ребут. Можешь использовать DudeLib и примеры из него. Там прямо по шагам указано как собрать optiboot. Шьешь другой ардуиной используя скетч arduinoisp.
У меня сейчас основная проблема перекроить optiboot под 2560, вроде есть решения №1 и №2 но руки не доходят. Честно говоря В плотную займусь этим после НГ. Сейчас как я и говорил занимаюсь прокладкой и прототипированием. Все на столе и иногда выезжает в поле для опытов. Пока скорее выбираю и опробую технологии на предмет использования. Без вылизывания кода.
Есть еще один вариант но не проверял. (И он точно в сети работать не будет из-за колизий). Это использование чипа с автоопределением RX TX - MAX13487/13488
Кстати по кабелям, очень много сигнальных - контрольных кабелей у пожарников (ОПС, ВН) и асутпшников (АСКУЭ, АСУТП, etc) . Набери сигнальный кабель для 485 и дальше выбирай под задачу.
спасибо за инфу (и по rs485 и по кабелю), я так и предполагал. Попробую.
CAN ID разбил на разряды
Анализтор CAN шины можно сделать за 5 мин, используя программу CanHacker, arduino и модуль mcp2515
01
#include <SPI.h>
02
#include <mcp2515.h>
03
04
struct
can_frame canMsg;
05
MCP2515 mcp2515(10);
06
07
uint8_t Adresat;
// адрес получателя
08
uint8_t AdresaNt;
// адрес отправителя
09
10
unsigned
long
IDnew;
// переменная нового ID
11
12
void
setup
() {
13
Serial
.begin(9600);
14
SPI.begin();
15
16
mcp2515.reset();
17
mcp2515.setBitrate(CAN_125KBPS);
18
mcp2515.setNormalMode();
19
20
21
}
22
23
void
loop
() {
24
25
if
(mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
// если получили CAN фрейм
26
27
Serial
.println(canMsg.can_id, HEX);
// print ID
28
29
Adresat = (canMsg.can_id & B11111);
// вытягиваем 5-битный адрес получателя из ID
30
AdresaNt = (canMsg.can_id & 0x3E0)>>5;
// вытягиваем 5-битный адрес отправителя из ID
31
//распечатаем адреса
32
Serial
.print(
"Adresat "
);
Serial
.println(Adresat);
33
Serial
.print(
"AdresaNt "
);
Serial
.println(AdresaNt);
34
35
// и запихнем эти адреса обратно в CAN ID (ну просто в переменную IDnew)
36
37
IDnew = ( ( unsigned
int
)AdresaNt << 5 ) | Adresat;
38
39
Serial
.print(
"IDnew "
);
Serial
.println(IDnew, HEX);
40
41
42
Serial
.println();
43
44
45
}
46
47
}
т.к. при 5 битных адресах будет трудно в анализаторе шины визуально мониторить адреса МК, зашифрованные в ID, решил оставить 4 битные адреса. (т.е. в шине может быть 15 адресов МК и один широковещательный).
получился примерно такой протокол.
ID XYZ где X тип кадра (от 0 до 7 )
От 0 до 5 – данные с датчиков, статусы, состояния (от 0 до 5 это страницы кадров, т.е. 6 страниц по 8 байт данных. Итого с одного устройства можно передавать 48 байт за серию из 6 кадров)
6 – команды управления
7 – отчеты о выполненных командах
Y - адрес отправителя (от 0 до E, F - от любого МК)
Z - адрес получателя (от 0 до E, F - широковещательный, предназначено всем)
описание протокола CAN - ID лист
В протокол CAN шины каждого МК заложил такие правила:
1. Разбираем сообщения из CAN шины, которые адресованы только нам.
2. Команда на управление чем либо посылается нами с периодичностью 500 мс до тех пор, пока не будет получен отчет о выполнении, но не более 10 раз, по истечение чего, например, можно записывать в еепром код неисправности.
3. Если нами принята команда на управление чем либо, посылаем 3 раза с периодичностью 200 мс отчёт контроллеру, который эту команду нам послал.
Вся CAN шина в программе у меня организована двумя функциями CANread() и CANwrite(), которые крутятся в лупе.
Помним что ID сообщения кан шины у нас разбит на разряды (читай выше). Работаем с разрядами, вот пример МК_1 всего этого. Проверено, работет хорошо.
001
#include <SPI.h>
002
#include <mcp2515.h> // библиотека для китайского модуля CAN шины MCP2515
003
004
struct
can_frame canMsg;
// принимаемое сообщение из кан шины
005
struct
can_frame canMsg_Report;
// сообщение, отсылаемое в шину - отчеты о выполнении команд
006
struct
can_frame canMsg_WriteData;
// сообщение, отсылаемое в шину - данные, датчики и т.д.
007
struct
can_frame canMsg_WriteCommand;
// сообщение, отсылаемое в шину - команды управления
008
009
MCP2515 mcp2515(53);
// пин ардуино к которому подключается CS (SS) модуля MCP 2515
010
011
012
// ниже переменные для организации CAN протокола
013
014
unsigned
long
timer_CANReport = 0;
015
bool
timerenabled_CANReport = 0;
016
017
unsigned
long
prevCANReport = 0;
018
019
unsigned
long
prevCANdata0 = 0;
020
unsigned
long
prevCANdata1 = 0;
021
022
bool
WriteCANReport = 0;
023
bool
WriteCANCommand = 0;
024
025
uint8_t CANReport_Number = 0;
026
uint8_t CANcommand_Number = 0;
027
028
void
setup
() {
029
030
//подготовка сообщения отчетов
031
canMsg_Report.can_id = 0x71F;
032
canMsg_Report.can_dlc = 2;
033
034
//подготовка сообщения команд
035
canMsg_WriteCommand.can_id = 0x612;
036
canMsg_WriteCommand.can_dlc = 2;
037
038
039
SPI.begin();
040
041
mcp2515.reset();
042
mcp2515.setBitrate(CAN_250KBPS);
// Скорость CAN шины
043
mcp2515.setNormalMode();
044
045
}
046
047
void
loop
() {
048
049
CANread();
050
CANwrite();
051
052
if
(если нужно отправить команду в кан шину) StartCANcommand(0x02, 0x11, 0x2);
053
// параметры функции (стариший байт команды, мл.байт команды, адрес получателя команды)
054
// т.е. в этом примере отправляется команда 0211 на МК с адресом "2"
055
// если посмотреть в ID лист, то это включение света в комнате Tanya
056
057
}
058
059
060
061
062
// адрес данного МК в CAN шине 0x1
063
064
void
CANread() {
065
066
if
(mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
// если из CAN пришло сообщение
067
if
((canMsg.can_id&0xF)==0xF || (canMsg.can_id&0xF)==0x1){
// если получили широковещательное(0xF) или в наш адрес (0x1)
068
069
070
//////////////////////////////////////////ПРИНЯТИЕ СТАТУСОВ, ДАННЫХ С ДАТЧИКОВ, ДАТАСТРИМ КОРОЧЕ
071
072
if
(((canMsg.can_id&0xF00)>>8)>=0x0 && ((canMsg.can_id&0xF00)>>8) <=0x5){
//если тип полученного сообщения - "статусы, датастрим"
073
074
if
(((canMsg.can_id&0xF0)>>4)==0x2){
// если сообщение от контроллера MK_2 света на втором этаже
075
076
if
(((canMsg.can_id&0xF00)>>8)==0x0){
// и если это страница "0" данных
077
078
Svet_Tanya = (canMsg.data[2] & B1);
//считываем состояние света в битах из байта 2 CAN фрейма
079
Svet_Det = (canMsg.data[2] & B10)>>1;
080
Svet_Katya = (canMsg.data[2] & B100)>>2;
081
Svet_Vanna_2 = (canMsg.data[2] & B1000)>>3;
082
Svet_Zal_2 = (canMsg.data[2] & B10000)>>4;
083
084
Pozhar_Tanya = (canMsg.data[1] & B1);
//считываем пож.датчики в битах из байта 1 CAN фрейма
085
Pozhar_Det = (canMsg.data[1] & B10)>>1;
086
Pozhar_Katya = (canMsg.data[1] & B100)>>2;
087
Pozhar_Vanna_2 = (canMsg.data[1] & B1000)>>3;
088
Pozhar_Zal_2 = (canMsg.data[1] & B10000)>>4;
089
090
Dvizh_Tanya = (canMsg.data[0] & B1);
//считываем датчики движения в битах из байта 0 CAN фрейма
091
Dvizh_Det = (canMsg.data[0] & B10)>>1;
092
Dvizh_Katya = (canMsg.data[0] & B100)>>2;
093
Dvizh_Vanna_2 = (canMsg.data[0] & B1000)>>3;
094
Dvizh_Zal_2 = (canMsg.data[0] & B10000)>>4;
095
}
//конец страницы "0" данных
096
097
}
//конец данных от МК_2
098
099
100
if
(((canMsg.can_id&0xF0)>>4)==0x3){
// если сообщение от контроллера MK_3 в беседке
101
102
if
(((canMsg.can_id&0xF00)>>8)==0x0) {
// и если это страница "0" данных
103
104
Dvizh_Stoyanka = (canMsg.data[0] & B1);
//считываем датчики движения из байта 0 CAN фрейма
105
Dvizh_Gazon = (canMsg.data[0] & B10)>>1;
106
Dvizh_Yablonya = (canMsg.data[0] & B100)>>2;
107
Dvizh_Teplica = (canMsg.data[0] & B1000)>>3;
108
109
SilaSveta = canMsg.data[1] ;
//считываем освещённость улицы из байта 1 CAN фрейма
110
111
Svet_Besedka_Shar1 = (canMsg.data[2] & B1);
//считываем состояние света из байта 2 CAN фрейма
112
Svet_Besedka_Dlin = (canMsg.data[2] & B10)>>1;
113
Svet_Besedka_Shar2 = (canMsg.data[2] & B100)>>2;
114
115
}
//конец страницы "0" данных
116
117
}
// конец данных от МК_3
118
119
120
}
/////////////// конец статусов, датастрима
121
122
/////////////////////////////////////////////ПРИНЯТИЕ КОМАНД УПРАВЛЕНИЯ
123
124
if
(((canMsg.can_id&0xF00)>>8)==0x6) {
//если тип полученного сообщения - "Команды управления"
125
126
if
(canMsg.data[0]==0x01) {
//если тип команды - "Управление охраной" (старш. байт 0x01)
127
128
if
(canMsg.data[1]==0x02) {CAN = 1 ;
if
(signaliz)signalizOFF(); CAN = 0; StartCANReport();}
//отреагируем на команду 0102, пошлём отчет
129
else
if
(canMsg.data[1]==0x12) {CAN = 1;
if
(!signaliz) signalizON(); CAN = 0; StartCANReport();}
//отреагируем на команду 0112, пошлём отчет
130
131
}
132
133
134
135
136
137
138
}
/////////////// конец принятия команд из CAN шины
139
140
//////////////////////////////////////////// ПРИНЯТИЕ ОТЧЁТОВ ИЗ CAN О НАЗНАЧЕННЫХ ДО ЭТОГО НАМИ КОМАНДАХ В CAN
141
142
if
(WriteCANCommand && ((canMsg.can_id&0xF00)>>8)==0x7){
//если в данный момент ждём отчета о выполнении команды и тип полученного сообщения - "Отчеты о выполнении команд"
143
144
145
if
(canMsg_WriteCommand.data[0]==canMsg.data[0] && canMsg_WriteCommand.data[1]==canMsg.data[1] ){
//если отчет совпадает с командой
146
147
CANcommand_Number = 0; timerenabled_CANReport = 0; WriteCANCommand=0;}
// прекращаем подавать CAN команду
148
149
150
}
/////////////// конец принятия отчётов о выполнении команд из CAN шины
151
152
}}}
153
154
155
156
157
void
CANwrite() {
158
159
//////////////////////////////////////// ОТПРАВКА ОТЧЕТОВ О ВЫПОЛНЕННЫХ КОМАНДАХ (3 раза через 200мс)
160
161
if
(WriteCANReport){
162
163
164
if
(millis() - prevCANReport>200){
165
166
mcp2515.sendMessage(&canMsg_Report);
167
168
CANReport_Number++;
169
170
if
(CANReport_Number>=3) CANReport_Number = 3;
171
172
prevCANReport = millis();}
173
174
175
if
(CANReport_Number>=3) {WriteCANReport = 0; CANReport_Number = 0;}
176
177
178
}
179
180
181
/////////////////////////////////////////// ПЕРИОДИЧЕСКАЯ ОТПРАВКА ДАННЫХ ДАТЧИКОВ, СТАТУСОВ, ПАРАМЕТРОВ В CAN ШИНУ
182
183
if
(millis() - prevCANdata1 > 1000){
// периодически передаём 1-ю страницу (состояние охраны)
184
185
canMsg_WriteData.can_id = 0x11F;
186
canMsg_WriteData.can_dlc = 1;
187
canMsg_WriteData.data[0] = 0;
188
if
(signaliz) canMsg_WriteData.data[0] |= (1 << 2);
// запишем состояние охраны в бит 2 байта0
189
else
canMsg_WriteData.data[0] &= ~(1 << 2);
190
191
192
mcp2515.sendMessage(&canMsg_WriteData);
193
194
195
196
prevCANdata1 = millis();
197
}
// конец отправки данных страницы "1" широковещательно
198
199
200
else
if
(millis() - prevCANdata0 > 300){
// периодически передаём 0-ю страницу (время)
201
202
canMsg_WriteData.can_id = 0x01F;
203
canMsg_WriteData.can_dlc = 8;
204
canMsg_WriteData.data[0] = Secunda;
205
canMsg_WriteData.data[1] = Minuta;
206
canMsg_WriteData.data[2] = Chas;
207
canMsg_WriteData.data[3] = Day;
208
canMsg_WriteData.data[4] = Weekday;
209
canMsg_WriteData.data[5] = Month;
210
canMsg_WriteData.data[6] = 18;
211
if
(V220) canMsg_WriteData.data[7] |= (1 << 0);
// запишем состояние напряжения сети в бит 0 байта 7
212
else
canMsg_WriteData.data[7] &= ~(1 << 0);
// значение бита 1 - есть напряжение, 0 - нет напряжения
213
214
mcp2515.sendMessage(&canMsg_WriteData);
215
216
217
218
prevCANdata0 = millis();
219
}
// конец отправки данных страницы "0" (это время) широковещательно
220
221
///////////////////////////////////////////// ОТПРАВКА КОМАНД УПРАВЛЕНИЯ В CAN ШИНУ
222
223
if
(WriteCANCommand){
// если установлена отправка CAN команды
224
225
226
if
(!timerenabled_CANReport) { mcp2515.sendMessage(&canMsg_WriteCommand);
// отправляем команду в CAN шину, если таймер выключен
227
timerenabled_CANReport = 1;
// включаем таймер
228
timer_CANReport = millis();
// обнуляем таймер
229
CANcommand_Number++;
// +1 к количеству отправленных команд
230
231
}
232
233
if
(timerenabled_CANReport && millis()-timer_CANReport>500) {
//если через полсекунды мы всё ещё НЕ получили отчет о выполненной команде, всё по новой
234
235
mcp2515.sendMessage(&canMsg_WriteCommand);
// отправляем команду в CAN шину
236
CANcommand_Number++;
// +1 к количеству отправленных команд
237
if
(CANcommand_Number>=10) {CANcommand_Number = 0; timerenabled_CANReport = 0; WriteCANCommand = 0;}
// если через 10 раз так и не получили отчет, бросаем это дело
238
else
timer_CANReport = millis();
// обнуляем таймер
239
240
241
242
}
243
244
245
246
247
248
249
}
// конец отправки команд в CAN шину
250
}
// конец CANwrite()
251
252
253
254
void
StartCANcommand (
byte
byte0,
byte
byte1,
byte
adr){
// функция пишет номер команды в байты CAN сообщения-команд
255
// а также забивает в ID сообщения адрес получателя команды
256
257
WriteCANCommand = 1;
258
canMsg_WriteCommand.data[0]=byte0;
259
canMsg_WriteCommand.data[1]=byte1;
260
canMsg_WriteCommand.can_id=canMsg_WriteCommand.can_id & 0xFF0|adr;
261
CANcommand_Number = 0;
262
timerenabled_CANReport = 0;
263
264
}
265
266
267
void
StartCANReport (){
// функция пишет номер команды из принятого из CAN сообщения-команды в отправиляемый в CAN отчет,
268
// о выполненной команде, также направляет отчет тому МК, который нам послал команду
269
270
WriteCANReport = 1;
271
canMsg_Report.data[0]=canMsg.data[0];
272
canMsg_Report.data[1]=canMsg.data[1];
273
canMsg_Report.can_id=canMsg_Report.can_id & 0xFF0|(canMsg.can_id&0xF0)>>4;
274
CANReport_Number = 0;
275
276
277
}
сегодня, наконец, протянул витую пару. Запустил CAN шину. Соединил МК на втором этаже (адрес у него 0х2) и МК на первом этаже (адрес 0х1). Скорость поставил 125кБит/с. Больше мне не нужно.
По вышеописанному протоколу работает просто отлично! Что не может не радовать.
Супер!. Осталось MQTT поверх CAN запустить и привязывайся к любому серверу УД.
Вот человек уже сделал https://github.com/c3re/can2mqtt
P.S. Я только заканчиваю ремонт, кабели затянул. Силовые щиты собрал. Скоро присоединюсь.
кстати спасибо за идею конструкцией заголовка ID! Так намного удобнее. Про MQTT почитаю. Эмм вообще не слышал что это . и да, Ссылка не работает
Извиняюсь, пробел в ссылке в конце затесался. https://github.com/c3re/can2mqtt
MQTT (Message Queue Telemetry Transport) — упрощённый сетевой протокол, работающий поверх TCP/IP, RS485 Используется для обмена сообщениями между устройствами по принципу издатель-подписчик. Теперь вот через CAN.
Он серверным софтом УД поодерживается для обмена с дачтиками и ИУ.
Без этого УД не построить. На ардуине скорее ДУ и автоматика, а сценарии управления автоматикой они в софте выше.
Есть смысл посмотреть OpenHub, Majordomo, IoBroker, Domoticz это из бесплатного. Ставить на сервер или на одноплатный комп.
Кстати я не совсем понял причину отказа от расширенного заголовка. Только из-за того, что анализатор шины его не видит?