Працюємо з 09:00 до 19:00 Пн-Сб
Київ біля ТЦ Квадрат бул.Перова

Двухсторонняя связь модулями 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 разметка не поддерживается! Используйте обычный текст.
    Плохо           Хорошо
Пинцет для монтажа SMD компонентов

Пинцет для монтажа SMD компонентов

Классный пинцет немагнитный и антистатичный - идеален для пайки миниатюрных SMD компонентовОчень удо..

40.22грн.

Переменный резистор 10 кОм

Переменный резистор 10 кОм

Переменный резистор или потенциометрСопротивление 10 кОмМощность 0,5 ВтТип BЛинейная характеристикаТ..

12.36грн.

Модуль PN532 NFC RFID

Модуль PN532 NFC RFID

NFC модуль на базе микросхемы NXP PN532, контроллера для бесконтактной связи на частоте 13,56 МГц на..

170.50грн.

Электро замок 12В 2А

Электро замок 12В 2А

Очень функциональный надёжный и удобный в использовании замокТакие замки используются в электронных ..

315.42грн.

Датчик скорости оптический

Датчик скорости оптический

Модуль открытой оптопары для измерения скорости вращения.Так же можно использовать как оптический ко..

23.54грн.