Працюємо з 09:00 до 19:00 без вихідних
Самовивіз не працює до 03.08

Двухсторонняя связь модулями ENC28J60 между контроллерами Arduino

Я покажу здесь решение, казалось бы, тривиальной простейшей задачи - обмен данными между контроллерами Arduino по сети Ethernet при помощи самых дешевых модулей связи ENC28J60.

Возьмем два модуля Ethernet ENC28J60 и два контроллера Arduino Nano, соединим их через сеть Ethernet.

ENC28J60 имеют коммуникацию SPI - для нас это означает, что соединяются они с контроллером через 4 сигнальных провода.

Подключение модулей делаем согласно следующей таблице:

VCC -  5V (питать нужно по возможности не от платы контроллера)
GND -  GND
SCK - Pin 13
SO  - Pin 12
SI  - Pin 11
CS  - Pin 10

У меня получилась следующая картина подключенных модулей к контроллерам. Один из Nano стоит на монтажном модуле, но вы можете его исключить - он здесь не имеет значения.

Дальше будем покорять UDP-протокол связи. Скачаем библиотеку UIPEthernet.h c гитхаба и установим в Arduino IDE. По сути будем использовать два стандартных примера из этой библиотеки (UdpClient, UdpServer), но с некоторыми изменениями. Один контроллер-клиент будет с заданной периодичностью слать полезные сообщения контроллеру-серверу, а тот при приеме сообщения будет отвечать полезным клиенту сообщением.

По умолчанию, если закачать пример UdpClient в один контроллер, а UdpServer в другой, получим только одностороннюю связь. Сервер будет принимать сообщение от клиента и отсылать ответ, но клиент не сможет читать этот ответ, хотя в его программе это предусмотрено.

Программа контроллера-клиента:

#include <UIPEthernet.h>
EthernetUDP udp;
unsigned long next;
void setup() {
  Serial.begin(9600);
  uint8_t mac[6] = {0x00,0x01,0x06,0x03,0x04,0x05};
  Ethernet.begin(mac,IPAddress(192,168,0,6));
  next = millis()+5000;
  udp.begin(5000);
}
void loop() {
  int success;
  int len = 0;
  if (((signed long)(millis()-next))>0)
    {
      do
        {
          success = udp.beginPacket(IPAddress(192,168,0,1),5000);
          Serial.print("beginPacket: ");
          Serial.println(success ? "success" : "failed");
          //beginPacket fails if remote ethaddr is unknown. In this case an
          //arp-request is send out first and beginPacket succeeds as soon
          //the arp-response is received.
        }
      while (!success && ((signed long)(millis()-next))<0);
      if (!success )
        goto stop;
      success = udp.write("hello world from client");
      Serial.print("bytes written: ");
      Serial.println(success);
      success = udp.endPacket();
      Serial.print("endPacket: ");
      Serial.println(success ? "success" : "failed");
      do
        {
          //check for new udp-packet:
          success = udp.parsePacket();
        }
      while (!success && ((signed long)(millis()-next))<0);
      if (!success )
        goto stop;
      Serial.print("received: '");
      do
        {
          int c = udp.read();
          Serial.write(c);
          len++;
        }
      while ((success = udp.available())>0);
      Serial.print("', ");
      Serial.print(len);
      Serial.println(" bytes");
      //finish reading this packet:
      udp.flush();
      stop:
      udp.stop();
      next = millis()+5000;
      
    //restart with new connection to receive packets from other clients
    Serial.print("restart connection: ");
    Serial.println (udp.begin(5000) ? "success" : "failed");
    }
}

Здесь можете для своей сети поменять IP модуля ENC28J60 клиента

Программа контроллера-сервера:

#include <UIPEthernet.h>
EthernetUDP udp;
void setup() {
  Serial.begin(9600);
  uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
  Ethernet.begin(mac,IPAddress(192,168,0,1));
  int success = udp.begin(5000);
  Serial.print("initialize: ");
  Serial.println(success ? "success" : "failed");
}
void loop() {
  //check for new udp-packet:
  int size = udp.parsePacket();
  if (size > 0) {
    do
      {
        char* msg = (char*)malloc(size+1);
        int len = udp.read(msg,size+1);
        msg[len]=0;
        Serial.print("received: '");
        Serial.print(msg);
        free(msg);
      }
    while ((size = udp.available())>0);
    //finish reading this packet:
    udp.flush();
    Serial.println("'");
    int success;
    do
      {
        Serial.print("remote ip: ");
        Serial.println(udp.remoteIP());
        Serial.print("remote port: ");
        Serial.println(udp.remotePort());
        //send new packet back to ip/port of client. This also
        //configures the current connection to ignore packets from
        //other clients!
        success = udp.beginPacket(udp.remoteIP(),udp.remotePort());
        Serial.print("beginPacket: ");
        Serial.println(success ? "success" : "failed");
    //beginPacket fails if remote ethaddr is unknown. In this case an
    //arp-request is send out first and beginPacket succeeds as soon
    //the arp-response is received.
      }
    while (!success);
    success = udp.println("hello world from server");
    Serial.print("bytes written: ");
    Serial.println(success);
    success = udp.endPacket();
    Serial.print("endPacket: ");
    Serial.println(success ? "success" : "failed");
    udp.stop();
    //restart with new connection to receive packets from other clients
    Serial.print("restart connection: ");
    Serial.println (udp.begin(5000) ? "success" : "failed");
  }
}

Здесь тоже можете поменять IP модуля в тексте программы.

После загрузки программ включаем все в работу и в Мониторе порта наблюдаем следующие строки.

Сервер должен написать нечто подобное:

received: 'hello world from client'
remote ip: 192.168.0.6
remote port: 5000
beginPacket: success
bytes written: 25
endPacket: success
restart connection: success
Клиент будет писать следующее:
beginPacket: success
bytes written: 24
endPacket: success
received: 'hello world from server
', 25 bytes
restart connection: success
Выводы
Связь получается довольно интересной. В одной сети можно объединять множество контроллеров. В некоторых помещениях, опутаных сетью Ethernet вдоль и поперёк, такой способ объединения будет весьма удобен.
Периодичность обмена я пробовал до 400 мс - отрабатывает прекрасно - даже можно уменьшать под быстрые задачи.
Что насторожило - микросхема на модуле ENC28J60 сильно греется при работе. На форумах предлагают делать отдельное питание. А я подумываю о радиаторе.

Написать отзыв

Примечание: HTML разметка не поддерживается! Используйте обычный текст.
    Плохо           Хорошо
Твердотельное реле 40А

Твердотельное реле 40А

Реле без механических контактов на 40 А. Силовым элементом данного реле является симистор.Гальваниче..

147.18грн.

Raspberry PI управление servo-мотором при помощи ползунка на экране

Raspberry PI управление servo-мотором при помощи ползунка на экране

Итак ставим перед собой задачу: управлять серво-мотором от Raspberry PI, используя визуальный элемен..

Монтажный шилд для NodeMcu ESP8266

Монтажный шилд для NodeMcu ESP8266

Монтажный модуль расширения для WiFi контроллера NodeMcu ESP8266Позволяет выполнять монтаж прое..

57.92грн.

Рама 3D принтера Prusa i3 Steel

Рама 3D принтера Prusa i3 Steel

Рама Prusa i3 Steel mk2b - это улучшеная версия оригинального 3D принтера Prusa.Рама 3D принтера Pru..

1521.43грн.

Канифоль 10г

Канифоль 10г

Твердая канифоль для пайкиПрименяется как флюс при пайке свинцово-оловяным припоем..

26.78грн.