Протокол UDP для обмена данными между Arduino
- Войдите на сайт для отправки комментариев
Пт, 25/01/2019 - 20:21
Просьба сильно не пинать :) это мой первый проект. 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); // задержка от "дребезга".
}