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

Держатель аккумулятора 3,7В типа 18650

Держатель для цилиндрических аккумуляторов типа 18650 на 3,7В..

18.14грн.

HTTP запрос через GSM GPRS модуль NEOWAY M590

HTTP запрос через GSM GPRS модуль NEOWAY M590

Постановка задачи. В этом проекте посмотрим на практический пример отправки http get запроса при по..

Датчик открытия окна, двери, шкафа

Датчик открытия окна, двери, шкафа

Датчик открытия окна или двери на основе герконаИспользуется для сигнализации или автоматического вк..

44.02грн.

Светодиод ультраяркий 3мм

Светодиод ультраяркий 3мм

Сверхяркий светодиод диаметром 3 ммКорпус прозрачный у светодиодов разного цвета свечения. То есть р..

0.66грн.

Модуль Bluetooth HC 06

Модуль Bluetooth HC 06

Связь с контроллером через UART портУправляется АТ-командамиПо умолчанию скорость обмена 9600 бодПар..

123.50грн.