РЕШЕНО Преобразователь can ethernet и обратно

Тема в разделе "Arduino & Shields", создана пользователем PE4ENbKA, 23 фев 2022.

  1. PE4ENbKA

    PE4ENbKA Нуб

    Тема - программирование конструирование.
    Мне нужна помощь с -
    Вопросы:
    1) Конверсия числа из байтов в UINT32?
    2) CAN id, почему используется операция И 0х1FFFFFF? И из за этого ли конечные устройства не понимают когда идет обращение к ним?

    Источники внизу. Так же приложил свои скетчи, очень надеюсь на вашу помощь. Поскольку уже достиг предела своих знаний в этой теме.

    С характеристиками следующее:
    2 платы Uno и 2 МСР2515, 2 Интернет шилда на базе W5100.
    Соединены по схеме
    Соединение MCP2515 с Uno следующее:
    upload_2022-2-23_15-27-54.png
    Контакты INT и CS могут быть переназначены в скетче.
    upload_2022-2-23_15-28-45.png
    Установка шилда на ардуино в описании не нуждается, собрать как лего.
    На плате MCP2515 устанавливается перемычка J1 - терминирующий резистор.

    Первая плата - та у которой порт 2000, вторая - порт 2001.
    Эта связка включена в разрыв шины, передача двунаправленная, проверено - работает.
    Конечные устройства теряют связь друг с другом из за проблем с пакетами.


    1)
    Проблема - конвертация числа UINT32 из 4х Uchar
    если использовать метод
    [​IMG]

    о в результате любое число будет FFFFxxxx где x это нормальная часть числа без потерь.
    если использовать вариант:
    unsigned long number3 = pow(256, 0) * bytes[0] + pow(256, 1) * bytes[1] + pow(256, 2) * bytes[2] + pow(256, 3) * bytes[3];
    то число будет иметь вид хххххх00 где х это нормально восстановленная часть числа а 00 всегда в конце

    Почему так происходит? В VS19 тестовый пример с обеими данными функциями не приводит к потере фрагментов числа.

    2)
    Теперь вторая часть, касаемо формата CAN rxID он имеет расширение UINT32 зачем в тестовом примере сделано вот так? (См выделенную желтым область)
    [​IMG]
    Прилагаю разъяснение работы устройств.
    Для работы с UDP используется библиотека <EthernetUdp.h>
    Подготовка параметров выглядит так:
    [​IMG]
    [​IMG]
    Указываем желаемый MAC и IP. IP dest это целевой адрес устройства с которым будем связывать первую ардуину, а REMOTE_PORT соответственно куда мы будем посылать данные.
    SERV_PORT будет ожидать данные от второго устройства.

    Передача данных начинается с того, что нужно прочитать посылку CAN - ее читать с помощью следующей функции:
    с начала проверяем какой уровень сигнала на контакте CAN0_UNT и если он высокий значит есть посылка.
    в функцию readMsgBuf должно быть передано три параметра - 1 идентификатор пакета, длина (DLC) и массив данных, в случае чтения эти параметры будут перезаписаны да же если в них есть данные.
    далее создаем пакет на 13 элементов где 0-3 будет хранить 4 байта числа UINT32, 4 - количество данных (DLC), и оставшиеся 5-12 блок данных.
    После окончания формирования массива передадим его в функцию отправки UDP для этого вызвав метод write() в него необходимо передать массив и размер в байтах, в данном случае с типом char размер будет 13 байт.
    функция НЕ умеет работать с UINT32 и больше.
    А что бы отправить данные конкретному устройству - в функции beginPacket() нужно передать IP адрес и порт того устройства которому это все адресовано.
    [​IMG]
    Не забываем endPacket(), иначе данные не отправятся.
    Работа с CAN:
    Инициализировать объект класса следующими параметрами.
    begin()
    MCP_ANY - не знаю что такое.
    KBPS - скорость CAN шины, в текущем устройстве будет 50.
    MHZ - частота работы кварца модуля МСР2515 (есть версии на 16 МГц).
    setMode()
    режимы работы (информации об этом нет) мне известно что режим Normal обеспечивает прием/передачу в нормальном режиме.
    На рисунке показаны все доступные режимы работы.
    [​IMG]
    pinMode()
    выбрать контакт назначенный на прерывания при получении посылки.
    [​IMG]
    Теперь для работы с отправкой сообщений нужно создать буфер с подготовленными данными.
    Поскольку они получены по UDP в том же виде как мы их передали то их необходимо собрать.
    Первые 4 байта это будущее число UINT32 хранящее rxID.
    Восстановим число с помощью метода pow(), но на конце будет всегда 00, поэтому по завершению преобразования прибавим еще раз 0 элемент полученного пакета.

    [​IMG]

    В примере используется дополнительно объявленный буфер, на самом деле он не нужен и лишь лишний. Работать можно сразу с полученными данными.

    Теперь после формирования rxID нужно сформировать блок данных пакета CAN, теперь уже нужно создать отдельный массив на 8 элементов и перенести в него 5-12 элементы принятого массива.

    [​IMG]

    Теперь можно отправлять посылку вызовом метода sendMsgBuf() в нее нужно передать наше число UINT32 - rxIDб.
    Второе число 1 - *ext, это переменная отвечающая за выбор типа посылки (Если 0 то STANDART а если 1 то EXTENDED) если будет выбор стандартного пакета то половина rxID будет потеряна и посылка отправится с коротким ID пакета.
    [​IMG]
    И обязательно не забываем про включение режима однократной отправки enOneShotTX().
    Если не использовать эту команду то модуль МСР2515 имеющий 3 буфера сообщений будет бесконечно, на максимальной скорости слать последние 3 сообщения.
    Об этом нет информации нигде просто, я догадался сам анализируя голую библиотеку CAN рассматривая в блокноте.
    что бы выключить этот режим вызовите функцию disOneShotTX().
    Так же прилагаю полный список функций класса CAN
    [​IMG][​IMG]
    Большинству этих функций описание не известно, я бы сказал его вообще нет. Применение функций можно увидеть только в тестовых скетчах идущих с библиотекой.
    Далее в функцию передаем 4 элемент - который хранит длину поля данных (DLC) и передаем блок данных.
    Не стоит волноваться о том что при DLC = 4 блок будет на 8 элементов, функция отправки обрежет сообщение до 4х ячеек и отправит.
    На этом отправка сообщения завершена и МСР2515 готов к получению данных.

    Моя система работает в обе стороны одновременно.
    В текущий момент есть проблемы - не корректно собирается rxID, конечные устройства теряют связь друг с другом поскольку что то не так с rxID.

    Полезные источники:
    1) Библиотека которая поддерживает сразу CAN EXTEND+STANDART frames, CAN2.0B https://github.com/coryjfowler/MCP_CAN_lib
    2) Datasheet для МСР2515 https://ww1.microchip.com/downloads...d-Alone-CAN-Controller-with-SPI-20001801J.pdf
    3) Описание команд для UDP с примерами http://mypractic.ru/urok-64-tcp-server-i-klient-na-arduino-biblioteka-uipethernet.html
    4) Если нет второй ардуины то можно достучаться к ней с ПК http://mypractic.ru/urok-69-protoko...hyu-biblioteki-uipethernet.html#comment-72076
     
  2. DetSimen

    DetSimen Гик

    Тут не любят студентов-халявщиков. Достиг потолка и нихрена не понимаешь, - отчисляйся и иди в армию.
     
    Igor68 и parovoZZ нравится это.
  3. parovoZZ

    parovoZZ Гуру

    так вызвал эту функцию или нет?
     
  4. parovoZZ

    parovoZZ Гуру

    халявщик настолько, что скопировал всё, кроме вопроса.
     
  5. b707

    b707 Гуру

    где-то я это уже читал...
    Печенька. это не вы пару месяцев назад приходили ныть на ардуино.ру, что, мол, дайте подробное РУССКОЕ описание всех функций библиотеки CAN?
    Наверняка вы... Какого вам описания нет, вы исходник библиотеки читать не умете?
     
  6. SergeiL

    SergeiL Оракул Модератор

    @PE4ENbKA, после вашего хамства, помогать вам пропадает всякое желание.

    Но дам зацепку:
    upload_2022-2-23_22-9-26.png
    Не наводит ни на какие мысли???
     
  7. b707

    b707 Гуру

    так он еще и нахамил? :)
    Вообще товарищ очень мутный - постоянно регистрирует новые ники и ходит клянчит по форумам
     
  8. SergeiL

    SergeiL Оракул Модератор

    Пока потер, предупредил, может одумается.
    Ваших сктчей то не видно.
     
  9. b707

    b707 Гуру

    я с ним у гайвера переписываюсь.... дерево деревом...
    Какой ему "кан через эзернет". когда он байтами пользоваться не умеет...
     
  10. PE4ENbKA

    PE4ENbKA Нуб

    Короче я разобрался. Вот полностью рабочий вариант, начал с начала писать и убрал хлам.
    Код (C++):
    //константы конфигурирования-------------------------------------------------------------------------------------------------
    #define SERV_PORT 2000       // порт сервера для прослушивания (откуда принять)
    #define REMOTE_PORT 2001     // порт устройства адрсата (куда отправить)
    #define CAN0_INT 2           // пин для прерываний (если МСР2515 получает посылку то генерирует низкий уровень)
    // определяем конфигурацию сети----------------------------------------------------------------------------------------------
      byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02}; // МАС адрес устройства (Должен быть уникален)
      IPAddress ip(10, 1, 1, 86);                        // IP текущего устройства
      IPAddress dest(10, 1, 1, 166);                     // IP цели
    // Создание экземпляров объектов для работы с ними---------------------------------------------------------------------------
      EthernetUDP Udpin;          // объект для приема/отправки UDP пакетов
      long unsigned int rxId;     // переменная для записи ID пакета
      unsigned char len = 0;      // длина пакета DLC
      unsigned char rxBuf[8];     // буфер данных пакета Data
      MCP_CAN CAN0(10);           // Set CS to pin 10 (число в скобках указывает пин)
    void setup() {
    //Ethernet setup-------------------------------------------------------------------------------------------------------------
      Ethernet.begin(mac, ip);    // инициализируем контроллер сетевого соединения
      Udpin.begin(SERV_PORT);     // включаем прослушивание порта
      delay(10);
    //Serial setup---------------------------------------------------------------------------------------------------------------
      Serial.begin(115200);       // устанавливаем частоту передачи
      delay(10);
      Serial.print(F("Server address: "));
      delay(10);
      Serial.println(Ethernet.localIP()); // выводим IP-адрес контроллера
      Serial.print(F("\n"));
      Serial.print(F("CAN - Ethernet bridje Version 1.0.0\n"));
      delay(10);
    //CAN setup------------------------------------------------------------------------------------------------------------------
      CAN0.begin(MCP_ANY, CAN_50KBPS, MCP_8MHZ);       // init CAN Bus with 50kb/s baudrate at 8MHz with Mask & Filters Disabled
      CAN0.setMode(MCP_NORMAL);                        // Set operation mode to normal so the MCP2515 sends acks to received data.
      pinMode(CAN0_INT, INPUT);                        // Setting pin 2, MCP2515 /INT, to input mode
      delay(10);
    } //setup end
    void loop() {
    // UDP begin-----------------------------------------------------------------------------------------------------------------
    int packetSize = Udpin.parsePacket();              // проверяем получен ли пакет
    if (packetSize)                                    // если не 0 то будет выполнен следующий код:
      {
        unsigned char recived_udp[13]={};              // обявляем массивы для сохранения полученной информации
        unsigned char data_to_can[8]={};               // блок Data для посылки CAN
        Udpin.read(recived_udp,13);                    // загружаем полученный массив из буфера данных
        Serial.print(F("UDP+\n"));                     // Если была получена посылка в консоль выведется сообщение
        unsigned long rx_ID = ((unsigned long) recived_udp[3] << 24) + ((unsigned long) recived_udp[2] << 16) + ((unsigned long) recived_udp[1] << 8) + ((unsigned long) recived_udp[0]); // Преобразование 4х отдельных байт в одно число
        data_to_can[0] = recived_udp[5];               // подготавливаем блок данных заполняя его
        data_to_can[1] = recived_udp[6];
        data_to_can[2] = recived_udp[7];
        data_to_can[3] = recived_udp[8];
        data_to_can[4] = recived_udp[9];
        data_to_can[5] = recived_udp[10];
        data_to_can[6] = recived_udp[11];
        data_to_can[7] = recived_udp[12];
        CAN0.enOneShotTX();                           // ВАЖНО - выбираем режим однократной передачи посылки
        byte sndStat = CAN0.sendMsgBuf(rx_ID, 1/*extend 1 or 0*/, recived_udp[4], data_to_can); // Отправляем посылку
      }// UDP end----------------------------------------------------------------------------------------------------------------
    //CAN read-------------------------------------------------------------------------------------------------------------------
      if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
      {
        Serial.print(F("CAN+\n"));                       // Если была получена посылка в консоль выведется сообщение
        CAN0.readMsgBuf(&rxId, &len, rxBuf);             // чтение: идентификатор пакета, длина, данные
        //формирую блок данных для передачи--------------------------------------------------------------------------------------
        unsigned char UDP_PACKET[13] = {};               // посылка состоит из: 4 байт rxID, 1 байт длина посылки DLC, 8 байт блок данных посылки (в сумме 13 байт)
        UDP_PACKET[0] = (rxId & 0x000000FF);             // разбивка числа на отдельные байты
        UDP_PACKET[1] = (rxId & 0x0000FF00) >> 8;
        UDP_PACKET[2] = (rxId & 0x00FF0000) >> 16;
        UDP_PACKET[3] = (rxId & 0xFF000000) >> 24;
        UDP_PACKET[4] = len;                             // длина посылки
        UDP_PACKET[5] = rxBuf[0];                        // блок данных
        UDP_PACKET[6] = rxBuf[1];
        UDP_PACKET[7] = rxBuf[2];
        UDP_PACKET[8] = rxBuf[3];
        UDP_PACKET[9] = rxBuf[4];
        UDP_PACKET[10] = rxBuf[5];
        UDP_PACKET[11] = rxBuf[6];
        UDP_PACKET[12] = rxBuf[7];
        Udpin.beginPacket(dest, REMOTE_PORT);           // подготовка к передаче (IP цели, порт цли)
        Udpin.write(UDP_PACKET,sizeof(UDP_PACKET));     // передача пакета по UDP (Массив, размер массива)
        Udpin.endPacket();                              // выполнение передачи и завершение пакета
      }
    //CAN end---------------------------------------------------------------------------------------------------------------------
    } //loop end
     
  11. PE4ENbKA

    PE4ENbKA Нуб

    все я умею. уже решил, помогли на менее токсичном форуме. Решение на 44 строке.
     
  12. b707

    b707 Гуру

    смешно. На том "менее токсичном форуме" я вам и помог, дал решение из 44 строки. Смотрите на ники :)

    По итогам - я бы вам не советовал заниматься программированием. ничего у вас не выйдет. вы думать не умеете.
     
    DetSimen нравится это.