Передача данных базовой станции Misol Arduino в локальную сеть и Интернет (Народный мониторинг)

Первичной целью разработки базовой станции Misol Arduino было расширение возможностей по передаче получаемых данных пользователям, находящимся в произвольных точках пространства. Современные сетевые технологии предоставляют удобные возможности для передачи необходимых данных в требуемом объеме на любое расстояние. С точки зрения сетевых технологий местонахождение пользователей можно разделить на локальное (в пределах области действия локальной сети) и внешнее (в пределах области действия сети Интернет). Буду считать, что локальным пользователям будут доступны данные в полном объеме, а внешним пользователям перечень передаваемых данных будет ограничен их требованиями. В рассматриваемом случае под внешним пользователем будет считаться сервер интернет ресурса народного мониторинга.

Программное обеспечение, позволяющее перехватывать пакеты данных блока внешних датчиков метеостанции Misol разработано ранее. В этой публикации речь пойдет о том, как полученные данные передать в локальную сеть и в Интернет. Для передачи данных в локальную сеть и Интернет необходимо подключить Arduino Mega к локальной сети. Такое подключение выполняется с помощью сетевой платы, например, Ethernet Shield W5100.

Ethernet Shield W5100 Arduino

Представляет собой плату расширения, устанавливаемую поверх базовой платы Arduino, например, Mega или Uno. Для удобства подключения штыревые контакты снизу удлиненные и дублируются сверху гребенкой, что обеспечивает доступ к контактам базовой платы, даже при подключении платы расширения. Кроме сетевого контроллера W5100, обеспечивающего взаимодействие с сетевым интерфейсом, на плате дополнительно разведен разъем для подключения SD карт памяти. Таким образом, на плате собраны два разных устройства. Выбор доступа к требуемому устройству осуществляется через сигналы CS (Chip Select — выбор микросхемы), в качестве которых используются цифровые сигналы базовой платы. Сигналы CS аппаратно разведены на плате расширения и назначаются в библиотеках. Подключается плата Ethernet Shield W5100 к плате Arduino Mega установкой сверху.

Протоколы передачи данных

Базовым понятием передачи данных является сетевая модель OSI. Она представляет процесс передачи данных, разделенным на различные уровни. В зависимости от уровня, на котором планируется обеспечить передачу данных обратнопропорционально меняются требования к аппаратному и программному обеспечению. Если использовать простые аппаратные средства, то придется разрабатывать объемное программное обеспечение. Если использовать сложные аппаратные средства, то пользовательское программное обеспечение может быть минимальным. Как в большинстве случаев, для решения конкретной задачи целесообразно использовать некий компромиссный вариант. Таким решение является использование транспортного уровня модели OSI, а именно протоколов TCP и UDP.

Протокол TCP

Механизм TCP предоставляет поток данных с предварительной установкой соединения, осуществляет повторный запрос данных в случае потери данных и устраняет дублирование при получении двух копий одного пакета, гарантируя тем самым, в отличие от UDP, целостность передаваемых данных и уведомление отправителя о результатах передачи. TCP осуществляет надёжную передачу потока байтов от одного процесса к другому. TCP реализует управление потоком, управление перегрузкой, рукопожатие, надёжную передачу.

Протокол UDP

UDP (англ. User Datagram Protocol — протокол пользовательских датаграмм) — один из ключевых элементов набора сетевых протоколов для Интернета. С UDP компьютерные приложения могут посылать сообщения (в данном случае называемые датаграммами) другим хостам по IP-сети без необходимости предварительного сообщения для установки специальных каналов передачи или путей данных. UDP использует простую модель передачи, без неявных «рукопожатий» для обеспечения надёжности, упорядочивания или целостности данных. Таким образом, UDP предоставляет ненадёжный сервис, и датаграммы могут прийти не по порядку, дублироваться или вовсе исчезнуть без следа. UDP подразумевает, что проверка ошибок и исправление либо не нужны, либо должны исполняться в приложении. 

Оба эти протокола могут быть использованы. Однако, протокол UDP является более простым с точки зрения требуемой программной поддержки и не требует большого объема программной памяти, что является важным требованием при его реализации на аппаратной платформе с ограниченными ресурсами, например, такой как Arduino. В то же время он не обеспечивает гарантированной доставки сообщения. Это необходимо всегда помнить при его использовании. В качестве базового протокола выбирается протокол UDP.

Программная поддержка передачи данных

Разработка программного обеспечения функционирования Arduino основывается на широком использовании библиотек, реализующих различные функции. Для решения поставленных задач потребуются следующие библиотеки:

Для работы с контроллером W5100 разработана библиотека. Её требуется загрузить и установить в среде программирования Arduino. В примерах к библиотеке есть необходимый скетч, который послужит базой. Пример «слушает» заданный порт. Когда на этот порт приходит сообщение, Arduino формирует ответное сообщение. Данный алгоритм работы отличается от требуемого. Для метеостанции нет необходимости ожидать входящего сообщения. В зависимости от потребителя информации (локальный или глобальный (народный мониторинг) требуется посылать пакет с метеоданными с заданной периодичностью. Локальным потребителям данные должны передаваться каждую минуту, а серверу народного мониторинга — каждые пять минут. Кроме того, состав (формат) данных локальному и глобальному потребителю отличается. С учетом этих требований пример был модифицирован.

/*
   https://github.com/arduino-libraries/Ethernet
   https://github.com/arduino-libraries/Ethernet/tree/master/examples/UDPSendReceiveString
  Этот скетч конфигурирует контроллер W5100 Arduino для работы с протоколом UDP и передает строку широковещательным пакетом в локальную сеть.
*/

#include <Ethernet.h>
#include <EthernetUdp.h>

// ----- ***** ----- ***** ----- NET DATA ----- ***** ----- ***** -----
// ----- ***** ----- LOCAL DATA ----- ***** -----
byte MyMAC[] = { 0x3A, 0xF1, 0x7F, 0xA4, 0x56, 0x7E };  // MAC для идентификации устройства 
                                                        // сервером народного мониторинга
IPAddress MyIP ( 192, 168, 0, 199 );
IPAddress MyDNS  ( 192, 168, 0, 1 );
IPAddress MyGateway ( 192, 168, 0, 1 );
IPAddress MySubnet ( 255, 255, 255, 0 );
unsigned int localPort = 9999;            // Порт для приема пакетов UDP
IPAddress NMDNS;
// ----- End LOCAL DATA -----

// ----- ***** ----- Broadcast udp message ----- ***** -----
IPAddress IPBC( 192, 168, 0, 255 );
const unsigned int PORTBC = 8887;         // Порт для отправки пакетов UDP
// ----- End Broadcast -----

// ----- ***** ----- NM ----- ***** -----
byte IPNMDNS[4];    //Для DNS
byte IPNM[] = { 185, 245, 187, 136 };     // IP сервера народного мониторинга.
                                          // Не требуется при включении DNS
int portNM = 8283;
String mac, mac_d;
// ----- End NM -----
// ----- ***** ----- End NET DATA ----- ***** -----


EthernetUDP Udp;            // Определение UDP


#define LUTime 30000;       // Периодичность передачи пакетов локальным пользователям миллисекунды (30 сек)
#define NMTime 300000;      // Периодичность передачи пакетов на народный мониторинг миллисекунд (55 минут)
long TxLUTime, TxNMTime;



// ----- ***** ----- ***** ----- Setup ----- ***** ----- ***** -----
void setup() {

  Ethernet.begin(MyMAC, MyIP);          // Инициализация контроллера W5100 с заданными параметрами

  Serial.begin(115200);                 // Инициализация последовательного порта
  while (!Serial) {                     // Ожидание инициализации последовательного порта
    ;
  }

  if (Ethernet.hardwareStatus() == EthernetNoHardware) {    // Проверка наличия контроллера W5100
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1);                 // Остановка исполнения при отсутствии контроллера W5100
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  Udp.begin(localPort);         // Запуск службы UDP
}   // ----- End Setup -----


// ----- ***** ----- ***** ----- Loop ----- ***** ----- ***** -----
void loop() {

  //  ----- ***** ----- Отправка пакета локальным пользователям ----- ***** -----
  if (TxLUTime < millis()) {    // Передача пакета локальным пользователям

    //  ----- ***** ----- Формирование строки ----- ***** -----
    String strlip = "MeteoData Local User";           // Строка сообщения локальным пользователям
    strlip += ' ';
    strlip += millis();
    strlip += "; ";
    Serial.print("StrLip=: ");
    Serial.print(strlip);
    //  ----- Конец Формирование строки -----

    //  ----- ***** ----- Преобразование строки в массив символов ----- ***** -----
    uint16_t lenBClip = strlip.length();
    Serial.print("\tLen LIP=: ");
    Serial.println(lenBClip);
    char ttsBClip[lenBClip + 1];
    strcpy(ttsBClip, strlip.c_str());
    // ----- Конец Преобразование строки в массив символов -----

    //  ----- ***** ----- Отправка пакета (массива символов) ----- ***** -----
    Udp.beginPacket(IPBC, PORTBC);
    Udp.write(ttsBClip);
    Udp.endPacket();
    // ----- Конец Отправка пакета (массива символов) -----

    //  ----- ***** ----- Задание времени отправки очередного пакета ----- ***** -----
    TxLUTime += LUTime;
    // ----- Конец Задание времени отправки очередного пакета -----

  }  // ---- Конец Передача пакета локальным пользователям ---- -
  //  ----- Конец Отправка пакета локальным пользователям -----


  //  ----- ***** ----- Отправка пакета серверу народного мониторинга ----- ***** -----
  /*
    if (TxNMTime < millis()) {
      Udp.beginPacket(IPNM, portNM);
      Udp.write(ttsNM);
      Udp.endPacket();

      TxNMTime += NMTime;
    }
  */
  // ----- Конец Отправка пакета серверу народного мониторинга -----

}   // ----- Конец Loop -----

Разбор содержания скетча

Назначение скетча

Скетч конфигурирует контроллер W5100 Arduino для работы с протоколом UDP и передают тестовую строку широковещательным пакетом в локальную сеть.

Используемые библиотеки

Для работы потребуются две библиотеки.

Используемые библиотеки.

Сетевые установочные данные

Установочные данные в основном касаются информации, необходимой для работы в локальной (глобальной) сети.

Сетевые установочные данные.

Установочные данные контроллера W5100. Для самого контроллера задаются: MAC (MyMAC), IP (MyIP). IP контроллера W5100 должен быть уникальными для локальной сети, а MAC должен быть уникальным во Вселенной. Но, можно его задать и случайным образом или установить равным МАС устройству, вышедшего из применения, например, не используемой сетевой карте. Кроме того, с помощью MAC производится идентификация устройства на сервере народного мониторинга.
Установочные данные локальной сети. Для взаимодействия с локальной сетью задаются: IP локального сервера DNS (MyDNS); IP шлюза Internet (MyGateway); маска локальной подсети (MySubnet); номер локального порта UDP (localPort); переменная для хранения IP адреса сервера народного мониторинга (NMDNS), полученного от службы DNS.

Широковещание. Следующим блоком идут установки для широковещательных пакетов UDP. В большинстве случаев, данные в локальной сети передаются от источника IP(Tx) к приемнику IP(Rx). Но существует возможность передавать пакеты нескольким пользователям одновременно, несмотря на имеющиеся у них уникальные IP. Такой способ называется широковещанием (broadcast). Реализуется он заданием специального широковещательного адреса. Особенностью этого адреса является задание четвертого октета IP равным 255 (bin = 1111 1111). В данном случае адрес для широковещательной передачи будет: IPAddress IPBC ( 192, 168, 0, 255 ). Пакеты, отправляемые на такой адрес, будут приниматься всеми устройствами в локальной сети. Пакеты будут адресоваться на порт PORTBC = 8887 принимающих устройств. Этот порт должен быть указан для всех устройств, в качестве UDP порта входящих сообщений.

Данные сервера народного мониторинга. Включают IP адрес byte IPNM[] = { 185, 245, 187, 136 }. Его можно получить через любую службу доменных имен или через командную строку.

Запрос IP сервера народного мониторинга.

Зеленым маркером отмечен запрос. Желтым маркером — ответ.

И порт int portNM = 8283.

Порт сервера народного мониторинга.

Настройка и запуск (Setup)

В модуле настройки и запуска производится задание параметров и запуск контроллера W5100, последовательного порта, проверка наличия контроллера W5100 и сетевого подключения, запускается служба UDP.

Рабочий цикл (Loop)

В рабочем цикле производится проверка времени очередной отправки пакета локальным пользователям, формирование и отправка пакета, задание времени отправки очередного пакета.

Проверка времени очередной отправки пакета осуществляется с использованием управляющего оператора if сравнением заданного времени отправки TxLUTime с текущим временем millis(). Если при проверке millis() превышает заданное время отправки, то процедура формирования и отправки пакета выполняется.

Формирование пакета производится в два этапа.
Первый этап. Формируется строка сообщения strlip (string local IP).
Для примера она состоит из строковой константы «MeteoData Local User» и текущего времени в миллисекундах millis(). Для удобства восприятия строка завершается признаком окончания строки с пробелом «; «.
Второй этап. Строка strlip преобразуется в массив символов ttsBClip (transmit text string broadcast local IP) . Преобразование строки в массив обусловлено посимвольной передачей данных.

Отправка сообщения производится заданием контроллеру IP получателя (IPBC) и порта (PORTBC); передачей контроллеру отправляемого сообщения (ttsBClip). При получении отправляемого сообщения контроллер посимвольно передает его в локальную сеть по протоколу UDP. После завершения передачи сообщения контроллер завершает сеанс связи.

Заключительным действием в рабочем цикле является задание времени отправки очередного пакета TxLUTime.

Для подтверждения правильности передаваемых данных формируемая строка strlip и ее длина lenBClip выводятся в последовательный порт.

Процедура отправки сообщения на сервер народного мониторинга аналогична рассмотренной процедуре и в данной публикации не рассматривается.

Проверить отправку сообщения в локальную сеть возможно с помощью программы TCP/IP Builder.

Если в TCP/IP Builder пакеты получены, то задача, поставленная в данной публикации, выполнена. Широковещательные пакеты могут быть приняты любым устройством в локальной сети. Следующими этапами развития проекта домашней метеостанции являются: подключение базовой станции и требуемых датчиков; формирование и отправка данных потребителям в локальной сети и на сервер народного мониторинга; получение актуального IP адреса сервера народного мониторинга через службу DNS; разработка устройства приема широковещательных пакетов и отображение принимаемых данных.

Перехват данных от метеостанции Misol Arduino

Человек непрерывно взаимодействует с внешней средой. Наиболее актуальными характеристиками внешней среды являются метеопараметры (температура, давление влажность, скорость и направление ветра и др.). Для измерения их значений были разработаны различные средства измерения (термометр, барометр, гигрометр, анемометр). Измеренные значения отображаются на различного вида экранах и табло. Объединение средств измерений и средств отображения в одном устройстве я буду называть метеостанцией.

Китайские друзья выпускают метеостанции марки Misol, которые состоят из комплекта (блока) внешних датчиков с термо-гидро передатчиком

Блок внешних датчиков метеостанции Misol.

и дисплея, на котором отображаются измеренные значения

Модуль дисплея метеостанции Misol.

Передача данных от внешних датчиков на дисплей осуществляется по радиоканалу на частоте 433 МГц. Технические характеристики определяют дальность передачи данных не более 100 метров (на открытой местности). Если передача данных происходит через радиопоглощающие препятствия, то дальность передачи данных значительно сокращается. Для повышения дальности передачи данных требуется использовать другие способы передачи, для чего требуется перехватывать данные от внешних датчиков.

Подключение к модулю передатчика Misol

Все данные с внешних датчиков собираются в термо-гидро передатчике

Термо-гидро передатчик метеостанции Misol.

Для подключения к нему необходимо три провода: Земля (черная метка — черный провод); +3,3 (синяя метка — зеленый провод); Сигнал (желтая метка — желтый провод).

Подключение к термо-гидро передатчику метеостанции Misol.

Подключение сигнала выполнено через резистор 220 Ом (в кембрике). Для подключения использовался мягкий телефонный четырехпроводный кабель. Одна жила (красная) остается свободной. Кабель выпускается наружу через приоткрытый отсек питания. К Arduino Mega сигнал подключается к выводу D2 (Interrupt 0). Остальные провода по предназначению (земля, +3,3 В).

Временные параметры пакета импульсов

Данные между модулем термо-гидро передатчика и дисплеем передаются пакетами. В пакете необходимо было определить параметры импульсов и размерность пакетов (число импульсов). Измерения производились по экрану осциллографа.

Временные параметры импульсов пакетов метеостанции Misol.

В результате анализа временных диаграмм и сравнения с известными способами кодирования информации в радиотехнических системах было установлено, что 0 кодируется импульсом 500 мкс, 1 – 1500 мкс, а пауза составляет 1000 мкс.

 Для декодирования при приеме достаточно отслеживать нарастающий фронт передаваемого импульса и измерять его длительность (интегрировать принимаемый сигнал) и принимать решение о принимаемом символе.

Отслеживать нарастающий фронт импульсов удобно через механизм прерываний микроконтроллера Atmel (МК), на базе которого построена плата Arduino Mega.

Алгоритм декодирования символа следующий: отслеживается изменение (перепад) входного сигнала (или нарастание или спад). В случае нарастания (начало импульса) запускается измерение длительности импульса. В случае спада (конец импульса) измерение длительности останавливается. По длительности импульса принимается решение о принятом символе 0 или 1.

Дальнейший анализ проводился по результатам приема пакета Arduino.

Программа приема пакета импульсов метеостанции Misol Arduino

//  Программа декодирования последовательности передаваемых импульсов метеостанции Misol
byte bitmas[8];
byte bytemas[255];
byte rxpin = 2;              //Пин подключения выхода приемника. Вход Int0
byte RxPinStateOld, RxPinStateNew;     //Значения входа
byte rxb;                    //Принятый бит
byte nbit = 0;               //Количество принятых бит в байте
byte nbyte = 0;              //Количество принятых байт
byte vbyte;                  //Десятичное значение байта
byte errorx;                 //Ошибка приема
volatile unsigned long timpb, timpe, timp, tpause;   //Время начала, конца, длительность импульса, паузы
byte EndPacket = 1;         //Флаг окончания передачи пакета
byte impulse = 0;           //Флаг импульса: 0 - пауза, 1 - импульс
byte Int0was = 0;           //Флаг прерывания

// ***** Бит в байт *****
void BitToByte() {
  byte k = 128;
  vbyte = 0;
  for (int i = 0; i < 8; i++) {
    vbyte = vbyte + bitmas[i] * k;
    k = k / 2;
  }
} // *****

// ***** Прием импульса (Прерывание) *****
void int0rxreceive() {                //
  RxPinStateOld = RxPinStateNew;      //Сохранение предшествующего состояния
  RxPinStateNew = digitalRead(rxpin);  //Получение нового значения

  //Анализ состояний
  if (RxPinStateOld == LOW && RxPinStateNew == HIGH) { //Фронт импульса
    //Старт приема импульса
    timpb = micros(); //Фиксация времени начала импульса
    impulse = 1;      // Установка флага импульса

  }

  else if (RxPinStateOld == HIGH && RxPinStateNew == LOW) //Спад импульса
  { //Окончание приема импульса
    timpe = micros();  //Фиксация времени окончания импульса
    impulse = 0;       //Сброс флага импульса
  }

  Int0was = 1;
}      // *** Окончание приема импульса

// *** Setup ***
void setup() {
  // put your setup code here, to run once:
  attachInterrupt(0, int0rxreceive, CHANGE);    //Подпрограмма обработки принимаемого импульса на 2 (Int0) DPIN
  Serial.begin(230400);
}// *** End setup


// *** Loop ***
void loop() {

  if (Int0was == 1) {     //Обработка прерывания
    if (impulse == 0) {   //Декодирование импульса
      timp = timpe - timpb;
      if (timp > 4500 && timp < 5500) {
        rxb = 0;
      }
      else if ( timp > 12500 && timp < 15500) {
        rxb = 1;
      }        //Окончание принятия решения
      else {
        goto noimp;
      }
      bitmas[nbit] = rxb;   //Присвоение значения биту
      nbit++;               //Определение позиции следующего бита
      if (nbit == 8) {      //Проверка завершения приема байта
        nbit = 0;           //Завершение приема байта
        BitToByte();
        bytemas[nbyte] = vbyte;
        ++nbyte;
        EndPacket = 0;      //Сброс флага окончания обработки пакета
        if (nbyte == 255) {
        }
      }

noimp: {                    //Ошибка приема.

      }

    } //End Прием импульса

    //Подготовка к приему пакета
    nbit = 0;
  } // *** Окончание обработки прерывания


  // *** Определение длительности паузы
  tpause = micros() - timpe;
  if ( tpause > 10500 && EndPacket == 0 ) {  //Признак паузы
    //Пауза

    //Вывод пакета в паузе
    Serial.println (" End data packet: ");
    Serial.print(" Tpause = ");   //Отображение принятых байт
    Serial.println(tpause);
    Serial.print("RxByte(");      
    Serial.print(nbyte);
    Serial.print(") = ");
    for (byte i = 0 ; i < nbyte; i++) {
      Serial.print(bytemas[i]);
      Serial.print(", ");
    }
    Serial.println();
    Serial.println (" ***** ");
    Serial.println();
  } // *** Окончание определения длительности паузы

}//End loop

Обработка пакета данных метеостанции Misol

Для выделения необходимых данных из пакета необходимо производить его декодирование. Неоценимую помощь в этом оказал неизвестный герой. К сожалению ссылка на его работу была утрачена в веках, а полнотекстный поиск не дал результатов. Благодарность ему всегда будет жить моем сердце.

Пакет может содержать 11 (короткий) или 22 (длинный) байт данных. Длинный пакет состоит из двух коротких. Поэтому рассматриваться будет только короткий пакет. Пакет состоит из одного синхробайта и десяти информационных байт. Каждый байт (восемь бит) разделяется на четверки (тетрады (англ. — nibbles) битов.

Информационное содержание пакета данных метеостанции Misol.

Требуемое значение, в зависимости от требуемого числа значений кодируется одной, двумя или тремя тетрадами:

  • abc: Серийный номер (device identifier (SN — serial number))
  • def: Температура (temperature)
  • gh: Влажность (humidity (H %))
  • ij: Скорость ветра средняя (average wind speed (low byte) (AW))
  • kl: Скорость ветра в порыве (gust wind speed (low byte) (GW))
  • m:  Неизвестное назначение (unknown (UK))
  • n: Счетчик дождя (старшая тетрада) (rainfall counter (RC))
  • op: Счетчик дождя (младшие тетрады) (rainfall counter)
  • q: Уровень заряда батареи (battery-low indicator (LB))
  • r: Направление ветра (wind direction (DW))
  • st: Контрольная сумма (checksum (CRC))

Пример пакета данных:

Пример пакета данных с разбивкой на тетрады и привязки к значениям.

Одной тетрадой можно закодировать 16 значений; двумя — 256 значений; тремя — 4096 значений. Каждое значение представляет собой целое число, которое требуется преобразовать в заданную величину. Для преобразования применяются формулы пересчета.

Температура в градусах Цельсия (тетрады 5, 6 7) T = (Nh – 400) / 10
Пример: 2-10-3 = 2*16**2 + 10*16**1 + 3*16**0 = 512 + 160 + 3 = 675
T = (675 – 400)/10 = 27.5

Влажность H % (тетрады 8, 9) отображается непосредственными значениями. Например, 3-10 = 3*16**1 + 10*16**0 = 48 + 10 = 58 %

Средняя скорость ветра AW м/с (тетрады 10, 11) Naw*0,34

Скорость ветра в порыве GW м/с (тетрады 12, 13) Ngw*0.34

Счетчик осадков RC мм (тетрады 15, 16, 17) Nrc*0.3 (значение только накапливается! Для определения дифференциальной величины, например, за час, необходимо в начале каждого часа находить разницу между предшествующим и текущим значением).

Заряд батареи LB (тетрада 18) (значение не определено).

Направление ветра DW (градусы) (тетрада 19)

Определение направления ветра.

N — noth (север); E — eath (восток); S — south (юг); W — west (запад).

В пакете отсутствует величина давления. Она измеряется в модуле дисплея.

Программа декодирования пакета данных метеостанции Misol

// Программа декодирования пакетов данных метеостанции Misol
volatile byte bitmas[528];
volatile byte tetramas[132];
byte rxb;                    // Значение принятого бита
volatile int nbit = 0;
byte nbyte = 0;
byte rxpin = 2;              // Назначен пин 2 ExtInt0
volatile byte rxpinold, rxpinnew;     // Значения входа

volatile unsigned long timpb, timpe, timp, tpause, timpem ;   //Время начала, конца импульса, паузы
volatile byte imprx;

#define CRC3B   40  // Контрольная сумма первых трех байт. Отличается для каждого устройства! Считается по строке приема.


// ***** Подпрограммы *****

// ***** Прием импульса *****
void int0rxreceive() {
  rxpinold = rxpinnew;      //Сохранение предшествующего состояния
  rxpinnew = digitalRead(rxpin);  //Получение нового значения

  //Анализ состояний
  if (rxpinold == LOW && rxpinnew == HIGH) { // *** Фронт импульса
    //Старт приема импульса
    timpb = micros();
  }

  else if (rxpinold == HIGH && rxpinnew == LOW) // *** Спад импульса
  { //Окончание приема импульса
    timpe = micros();
    timpem = millis();
    timp = timpe - timpb;


    if (timp > 450 && timp < 550) {
      rxb = 1;
    }
    else if ( timp > 1250 && timp < 1550) {
      rxb = 0;
    } //Окончание принятия решения

    else {
      Serial.print("/ \n");
      goto noimp;
    }
    bitmas[nbit] = rxb; //Присвоение значения бита элементу массива
    nbit++;             //Определение позиции следующего бита
    imprx = 1;          // Флаг вывода данных

noimp: {
    }
  }
} // End Прием импульса *****

// Окончание подпрограмм


// ***** Setup *****
void setup() {

  attachInterrupt(0, int0rxreceive, CHANGE);    //Подпрограмма обработки принимаемого импульса на 2 DPIN (Interrupt 0)

  Serial.begin(115200);

  //Разметка для экранного вывода данных
  Serial.println("  Sync__  Serial__ Tempera_  Humid  AvWin GstWn UK RC_____ LB DW  CRC__");
} // End setup *****


// ***** Loop *****
void loop() {

  // *** Count Pause ***
  tpause = millis() - timpem;

  if (imprx == 1 && tpause > 200) {

    //****** Вывод пакета данных по тетрадам
    Serial.print(": ");

    //Сброс массива байтов
    for (int i = 0; i < 132; i++) {
      tetramas[i] = 0;
    }

    // *** Преобразование массива бит в массив тетрад
    byte nbyte = 0;
    byte j = 0;
    byte l = 0;
    byte k = 8;
    for (int i = 0; i < nbit; i++ ) {
      tetramas[l] = tetramas[l] + bitmas[i] * k;
      k = k / 2;
      j++;
      if (j == 4) {
        j = 0;
        l++;
        k = 8;
        Serial.print(tetramas[l - 1]);
        Serial.print(", ");
      }
    }
    Serial.println("***** ");
    //***

    //Контрольная сумма первых трех тетрад
    int sum = 0;
    for (byte i = 0; i < 3; i++) {
      sum = sum + tetramas[i];
    }

    //***** Рабочий цикл
    if ( sum == CRC3B) {
      //Преобразование тетрадных значений в float
      //Температура Temp
      int q = 256;
      byte s = 5;
      float Temp = 0;
      for (byte i = 0; i < 3; i++) {
        Temp = Temp + q * tetramas[i + s];
        q = q / 16;
      }
      Temp = (Temp - 400) / 10;
      Serial.print("Temperature = ");
      Serial.print(Temp);
      Serial.println(" *C");

      //Влажность Hum
      q = 16;
      s = 8;
      float Hum = 0;
      for (byte i = 0; i < 2; i++) {
        Hum = Hum + q * tetramas[i + s];
        q = q / 16;
      }
      Serial.print("Humidity    = ");
      Serial.print(Hum);
      Serial.println(" %");

      //Средняя скорость ветра AW
      q = 16;
      s = 10;
      float AW = 0;
      for (byte i = 0; i < 2; i++) {
        AW = AW + q * tetramas[i + s];
        q = q / 16;
      }
      AW = AW * 0.34;
      Serial.print("AW          = ");
      Serial.print(AW);
      Serial.println(" mps");

      //Скорость ветра в порыве GW
      q = 16;
      s = 12;
      float GW = 0;
      for (byte i = 0; i < 2; i++) {
        GW = GW + q * tetramas[i + s];
        q = q / 16;
      }
      GW = GW * 0.34;
      Serial.print("GW          = ");
      Serial.print(GW);
      Serial.println(" mps");

      //Счетчик осадков Rn
      q = 256;
      s = 15;
      float RnC = 0;
      for (byte i = 0; i < 3; i++) {
        RnC = RnC + q * tetramas[i + s];
        q = q / 16;
      }
      RnC = RnC * 0.3;
      Serial.print("Rain        = ");
      Serial.print(RnC);
      Serial.println(" mm");

      //Направление ветра
      byte DW = tetramas[19];
      Serial.print("DW          = ");
      Serial.print(DW);
      Serial.println("  N");

    } //*** Окончание рабочего цикла

    //Подготовка нового цикла приема пакета данных
    nbit = 0;
    imprx = 0;
  }
} // End loop *****

Полученные из пакета данных значения метеопараметров:

  • Temp — температура (0С, float);
  • Hum — влажность (%, float);
  • AW — средняя скорость ветра (м/с, float);
  • GW — скорость ветра в порыве (м/с, float);
  • RnC — уровень осадков (мм, float);
  • DW — направление ветра (номер направления, byte)

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

Объединение блока наружных датчиков с термо-гидро передатчиком метеостанции Misol с Arduino Mega будет называться базовой станцией.

Направлений развития проекта два:

  • усиление функциональной насыщенности базовой станции;
  • передача полученных значений параметров и данных заданным потребителям.