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

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

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

Візьмемо два модулі Ethernet ENC28J60 і два контролери Arduino Nano, з'єднаємо їх через мережу Ethernet.

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

Підключення модулів робимо згідно з наступною таблицею:

VCC -  5V (живити потрібно по можливості не від плати контролера)GND -  GNDSCK - Pin 13SO  - Pin 12SI  - Pin 11CS  - Pin 10

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

Далі будемо підкорювати UDP-протокол зв'язку. Скачаємо бібліотеку UIPEthernet.h з гітхаба і встановимо в 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 размітка не підтримується! Використовуйте звичайтий текст.
    Погано           Добре
Цифровий вольтметр + амперметр

Цифровий вольтметр + амперметр

Цифровий вольтметр та амперметр постійного струмуДіапазон вимірювання напруги 0 ...100 ВДіапазон вим..

91.30грн.

Ультразвуковий датчик відстані HC-SR04

Ультразвуковий датчик відстані HC-SR04

Напруга живлення 5 ВРобочий кут відбитої хвилі не більше 15 градусівДіапазон вимірюваних відстаней 2..

35.22грн.

Уроки Arduino для новачків 1.1.3 Пряме програмування мікроконтролера ICSP

Уроки Arduino для новачків 1.1.3 Пряме програмування мікроконтролера ICSP

На цей раз ми поговоримо про те, як програмувати Arduino, не звичайним способом, не через звичн..

Мікроконтролер ATMEGA328P-PU

Мікроконтролер ATMEGA328P-PU

8-бітний мікроконтролер з архітектурою AVR - ATMEGA328P-PU в корпусі DIP28Такі контролери викор..

59.15грн.

Управління servo-мотором через COM-порт Arduino

Управління servo-мотором через COM-порт Arduino

Опишемо програму управління серво-мотором командами з COM-порта на прикладі контролера Arduino Leona..