Протокол UDP для обмена данными между Arduino

Нет ответов
AndreyD
Offline
Зарегистрирован: 07.10.2018

Просьба сильно не пинать :) это мой первый проект. UDP протокол выбран как самый простой и быстрый для обмена в стабильных сетях. Пример написан для Arduino Nano + сетевой модуль W5500.

/* Шаблон для обмена данными с помощью UDP пакетов между двумя контроллерами или взаимодествия 
с мастер контроллером (для Ардуино Нано + сетевой модуль W5500). 
   Можно отправляти и получать биты (флаги 0-1) и байты (целочисленные беззнаковые 0-255), 
более длинные данные необходмо преобразовывать в байты и обратно. 
   В закоментированных строках взаимосвязанные по скетчу примеры использования передачи данных 
(управление реле на этом контроллере, отправка флага срабатывания цифрового датчика, отправка 
данных от датчика температура\влажность и отправка сигнала от нажатия кнопки */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока подключения библиотек */
#include <SPI.h> //для SPI устройств
#include <Ethernet2.h> // для сетевого модуля
#include <EthernetUdp2.h> // для UDP протокола
#include <MsTimer2.h> // для внутреннего времени

//#include "DHT.h" //для модулей DHT11,21,22
//#include <OneWire.h> //для 1-wire устройств типа датчика температуры DS18B20
//#include <DallasTemperature.h> // для датчика температуры DS18B20
//#include <Bounce.h> //для кнопок
//#include <SD.h> //для SD карты
//#include <DS1307RTC.h> //для модуля времени
//#include <Time.h> //для работы с датой и веменем
//#include <Wire.h> //для I2C
/* Конец блока подключения библиотек */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока сетевых настроек */
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x00}; // мак адрес этого модуля
IPAddress ip(192, 168, 1, 2); //ip этого модуля
IPAddress ipw(192, 168, 1, 1); //ip второго модуля 
/* Конец блока сетевых настроек */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока настроек UDP */
EthernetUDP Udp; // объект для приема UDP пакетов.
EthernetUDP Udpw; // объект для отправки UDP пакетов.
int udp_port = 8888; // порт для UDP
#define CON_PACKET_SIZE 10 //размер пакета для обмена данными, количество байтов
byte Buffin0[CON_PACKET_SIZE]; // первичный буфер приёма udp пакетов
byte Buffin[CON_PACKET_SIZE]; // буфер приема udp пакетов для сравнения
/* описание принимаемых данных (// - примеры)
  in(x) - байт целиком, in(x,y) - бит y в байте x, 0 байт для приема служебных флагов
  
  in(0,0) - подтверждение связи
  //in(1,0) - флаг на включение реле от второго контроллера
  
*/
byte Buff[CON_PACKET_SIZE]; // буфер для отправки udp пакетов
byte Buff0[CON_PACKET_SIZE]; // буфер udp пакетов для проверки изменений
/* описание отправляемых данных (// - примеры)
  (x) - байт целиком, (x,y) - бит y в байте x, 0 байт для отправки служебных флагов 
  
  (0,0) - контроль связи
  //(1,0) - флаг положения реле
  //(1,1) - флаг цифрового датчика
  //(1,2) - флаг кнопки
  //(3) - температура
  //(4) - влажность
  
  (CON_PACKET_SIZE - 1) - идентификатор модуля (последний байт в UDP пакете, значения от 0 до 255)
*/
boolean otpr; //флаг для отправки UDP пакета
byte conok=0; //счетчик минут для проверки связи
/* Конец блока настроек UDP */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока выбора пинов */
/* Для использования дополнительных функций смотрите даташит конкретной версии модуля 
                              Цифровые пины (D):
  0 - RX0;            1 - TX1; 
  2 - INT0;           3 - INT1,PWM (2,3 "продвинутые" прерывания)
  4 - T0;             5 - T1,PWM
  6 - AIN0,PWM        7 - AIN1 (6,7 высокочастотный компаратор)
  8 - CLKO            9 - PWM
  10 - SS             11 - MOSI           12 - MISO          13 - SCK    (10,11,12,13 для подключения по SPI)
                           Аналоговые пины на прием (A):
  A0 - циф-ой 14      A1 - циф-ой 15      A2 - циф-ой 16     A3 - циф-ой 17
  A4 - SDA,циф-ой 18  A5 - SCL,циф-ой 19  (A4,A5 для подключения по I2C)
  A6                  A7  (A6,A7 только аналоговые входы) 
*/
//#define PIN_L1 2 // пин на реле управления лампой
//#define PIN_DATCH 3 // пин цифрового датчика
//#define BUTTON1 4 // пин кнопки
//#define DHTPIN A0 // пин датчика температура/влажность



/* Конец блока выбора пинов */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока выбора датчика температура/влажность */
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
//DHT dht(DHTPIN, DHTTYPE); //объект датчика температура/влажность
/* Конец блока выбора датчика температура/влажность */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока настройки кнопок */
//создаем объект класса Bounce. Указываем пин, к которому подключена кнопка, и время дребезга в мс.
//Bounce bouncer1 = Bounce(BUTTON1,5);
/* Конец блока настройки кнопок */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока настройки внутренних часов */
byte my_h=0, my_m=0, my_s=0, lmy_h=1, lmy_m=1, lmy_s=1; // внутренние часы, минуты, секунды
void mytime() // функция внутренниех часов
{
 my_s++;
 if (my_s > 59) {my_s = 0; my_m++;}
 if (my_m > 59) {my_m = 0; my_h++;}
 if (my_h > 23) my_h = 0;
}
/* Конец блока настройки внутренних часов */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/

void setup() {
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока установки режимов пинов */
//pinMode(PIN_L1,OUTPUT); digitalWrite(PIN_L1, HIGH); //реле
//pinMode(PIN_DATCH,INPUT); //датчик
//pinMode(BUTTON1,INPUT); //кнопка



/* Конец блока установки режимов пинов */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
  Ethernet.begin(mac, ip); // запуск сетевого модуля
  Udp.begin(udp_port); // объект для приема UDP пакетов 
  Udpw.begin(udp_port); // объект для отправки UDP пакетов
  
  //dht.begin(); // запуск датчика температура/влажность
  
  //Активация внутреннего времени
  MsTimer2::set(1000, mytime); // прерывание каждую секунду 
  MsTimer2::start();

  // первичное заполнение буферов (другие по необходимости)
  Buff[CON_PACKET_SIZE-1] = 0; //идентификатор модуля (последний байт в UDP пакете, значения от 0 до 255)
  
}

void loop() {
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока приема UDP пакетов */
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Udp.read(Buffin0,CON_PACKET_SIZE);
    if (byte(Buffin0[CON_PACKET_SIZE-1]) == 1) { //если от контроллера с идентификатором 1
      /* здесь можно "отлавливать" конкретные изменения во входящих пакетах в момент приема пакета */
      //if (bitRead(Buffin0[1],0) && !bitRead(Buffin[1],0)) digitalWrite(PIN_L1, LOW); //включение реле
      //if (!bitRead(Buffin0[1],0) && bitRead(Buffin[1],0)) digitalWrite(PIN_L1, HIGH); //отключение реле
    
    }
    
    for (byte i=0; i < CON_PACKET_SIZE; i++) Buffin[i] = Buffin0[i]; // сохранение первичного буфера в буфер для сравнения
  }
/* Конец блока приема UDP пакетов */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Пример для работы с кнопкой */    
  //if ( bouncer1.update() ) { //если сменилось состояние кнопки 
  //  if ( bouncer1.read() == HIGH) { } //если кнопка нажата
  //  if ( bouncer1.read() == LOW) { //если кнопка отпущена 
  // if (bitRead(Buff[1],2)) bitWrite(Buff[1],2,LOW); else if (!bitRead(Buff[1],2)) bitWrite(Buff[1],2,HIGH); //смена значения флага кнопки по нажатию
  //} 
  //}
/* Конец примера для работы с кнопкой */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока работы с внутренним временем */
  if (my_s != lmy_s) { // каждую секунду
     lmy_s = my_s;
     
  }
  if (my_m != lmy_m) { // каждую минуту
    lmy_m = my_m; 
    if ((bitRead(Buffin[0],0) == 0) && (conok < 255)) conok++; else conok = 0;//сколько минут прошло от последней проверки связи со вторым контроллером
    if (bitRead(Buffin[0],0)) bitWrite(Buff[0],0,LOW); // флаг для проверки связи на этом модуле
    bitWrite(Buff[0],0,HIGH); bitWrite(Buff0[0],0,LOW); //флаг для отправки подтверждение связи на второй модуль

    //Buff[3] = dht.readTemperature(); //чтение c дальнейшей отправкой температуры с датчика DHT
    //Buff[4] = dht.readHumidity(); //чтение c дальнейшей отправкой влажности с датчика DHT
  }
  if (my_h != lmy_h) { // каждый час
     lmy_h = my_h;
     
  }
/* Конец блока работы с внутренним временем */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Место для кода "условий" и др.*/
//if (digitalRead(PIN_DATCH)) bitWrite(Buff[1],1,HIGH); else bitWrite(Buff[1],1,LOW); //отправляем значение флага цифрового датчика
//if (digitalRead(PIN_L1)) bitWrite(Buff[1],0,HIGH); else bitWrite(Buff[1],0,LOW); //отправляем значение пина реле


/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Начало блока отправки пакета если буфер изменился */     
  for (byte i=0; i < CON_PACKET_SIZE; i++) if (Buff0[i] != Buff[i]) otpr = 1; 
  if (otpr) {
    Udpw.beginPacket(ipw, udp_port); 
    Udpw.write(Buff, CON_PACKET_SIZE);
    Udpw.endPacket();
    for (byte i=0; i < CON_PACKET_SIZE; i++) Buff0[i] = Buff[i];
    otpr = 0;
  }
/* Конец блока отправки пакета если буфер изменился */
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
  delay(100); // задержка от "дребезга".
}