2560 зависает с LoRa

alexbel620017
Offline
Зарегистрирован: 26.03.2017


Здравствуйте, коллеги, подскажите пожалуйста кто знает - есть проект в частный дом из двух аппаратных блоков (каждый на Mega2560). Один блок собирает данные с котельной и близлежащих помещений и по радиоканалу транслирует каждые 10 сек на другой блок. Изначально радиоканал создавался на nRF24L01+. Работало всё хорошо. Потом решил сделать радиоканал на модулях LoRa SX1278. Всё работает, но приёмная часть регулярно зависает. Может зависнуть через 20 минут, может через 8 часов.... Если убираю код (приведён ниже), который обрабатывает этот модуль - всё хорошо. Питание отфильтровано на самой переходной плате к SX1278 и танталовыми электролитами и керамикой. Код привожу. Может кто-то что-то подсказать?.....

Могу конечно сделать внешний аппартный WDT (и потом сделаю), но хотелось бы знать и устранить причину зависаний.

Библиотека используемая RadioHead, модули такие: https://sc02.alicdn.com/kf/HTB1DlmtSVXXXXaJXXXXq6xXFXXXS/SX1278-433MHz-LOra-Spreading-High-Sensitivity-Wireless.jpg

Приведённый код это обработка этого модуля, если его  убрать /* */  то зависаний нет. Может что не так в этом коде? Писал его по видео из ютуба.....

Весь код не выкладываю - он 825 строк

  // ------------------------------- приём данных на LoRa (SX1278) ---------------------------------------

  if (rf95.available()) {
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    if (rf95.recv((uint8_t*)&data, &len)) {
      d1 = data[0];
      d2 = data[1];
      d3 = data[2];
      d4 = data[3];
      d5 = data[4];
      d6 = data[5];
      d7 = data[6];
      d9 = data[7];     // отопл.
      d8 = data[8];     // водосн.
      d10 = data[9];
      d11 = data[10];
      d12 = data[11];
      d13 = data[12];
      d14 = data[13];
      d15 = data[14];
      olddata = millis();
      SendDataP("q0.picc", 0);                         // удаляем надпись "Данные устарели!"
    }
  }
  if (millis() - olddata > 300000) {
    SendDataP("t6.font", 3);                         // пишем "Данные устарели!" через 5 минут
  }

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вас не смущает, что Вы:

  1. Заводите buf (строка №4)
  2. Берете длину buf (строка №5)
  3. А читаете в data по длине buf (строка №6).

Кстати, что там за data - ХЗ.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

data - массив из 15 переменных int.

самый верхний кусок кода:

#include <TinyGPS.h>
#include <Nextion.h>
#include <OneWire.h>
#include <DS1307RTC.h>
#include <DS3231.h>
#include <Time.h>
#include <SPI.h>
#include <Ethernet2.h>
#include <SD.h>
#include <iarduino_Pressure_BMP.h>
#include <Adafruit_SHT31.h>
#include <RH_RF95.h>

// ------------------------- сеть ---------------------------------
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);
EthernetServer server(80);

// ------------------------- LoRa ---------------------------------
RH_RF95 rf95(3, 2);                       // 3 - чипселект (NSS), 2 - прерывание DI00, требования по этим выводам в папке LoRa
int data[15];                             // Создаём массив для приёма данных

// ------------------------- часы ---------------------------------
DS3231 Clock;
TinyGPS gps;

Евгений, подскажите пожалуйста как надо сделать, написать данную часть кода, - я электронщик, не программист....

Строка 04 задаёт buf (буфер), в скобках длина буфера? Какая она, что означает то что в скобках?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, "как делать" я не знаю, т.к. не знаю, "что делать".

А так,

во-первых у Вас ошибка в размере массива. Вот смотрите: RH_RF95_MAX_MESSAGE_LEN -  равна 259, а Вы в строке 5 присваиваете это число переменной uint8_t len, в которую больше, чем 255 не лезет. В итоге, len получает несколько неожиданное для Вас значение 3 - (выведите её в Serial и полюбуйтесь). В резудьтате Вы читаете только 3 байта. Виноват - это бред -  я там сослепу минус за плюс принял.

Во-вторых, судя по Вашей логике, читать Вы собиралиcь в buf, а не в data, иначе этот buf вообще ни для чего не нужен. Но это уже предположения - я не знаю, что Вы на самом деле хотели делать.

А зависает она скорее всего потому. что Вы пытаетесь читать не столько байтов, сколько реально пришло, а столько, сколько максимально возможно. А реально пришло меньше, вот она и ждёт пока остальные придут. Попробуйте читать столько, сколько пришло реально.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Я согласен с вами, но если я читаю в 6 строке не data, а buf, то получается каша какая-то.... 

Вывожу в монитор порта принятый массив - есть только половина значений, остальные нули, и действительные значения не по порядку, например data[0], data[3] и data[4] имеют нормальные значения (как передал), а остальные значения этого принятого массива нули..... как будто нумерация значений массива сбивается....

Код передатчика:

  // ------------------------------------------ передача данных LoRa ----------------------------------------------------


  if (fgk) {
    celsiusKout = celsius4;                  // датчики температуры газового котла
    celsiusKint = celsius5;
  }
  else {
    celsiusKout = celsius9;                  // датчики температуры электро котла
    celsiusKint = celsius10;
  }

  if ((millis() - periodnrf > 10000) && td == false) {  // таймер для отправки данных по nRF24L01 вне обработки температуры (td)
    int data[15] = {celsiusKout, celsiusKint, d2, d3, celsius6, celsius7, celsius8, PW, PH, celsius1, celsius2, celsius3, d13, d14, d15};
    periodnrf = millis();
    rf95.send((uint8_t*)&data, sizeof(data));
    rf95.waitPacketSent();
  }

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

НУ, Вот смотрите, Вы передаёте значения типа int - пятнадцаь штук, т.е. 30 байтов.

Читаете же Вы (пытаетесь ситать) 251 байт, и более того, присваиваете прочитанное переменным d1, d2 и т.д., какого типа - ХЗ.

Наведите порядок. Читайте то, что передаёте.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Не, d1 d2 и т.д. в начале обозначены как переменные int.

Вот, Евгений, такой код также прекрасно работает, только на зависания конечно не проверял ещё....

  // ------------------------------- приём данных на LoRa (SX1278) ---------------------------------------

  if (rf95.available()) {
    //uint8_t data[RH_RF95_MAX_MESSAGE_LEN];
    //uint8_t buf[30];
    //uint8_t len = sizeof(data);
    if (rf95.recv((uint8_t*)&data, 30)) {
      d1 = data[0];
      d2 = data[1];
      d3 = data[2];
      d4 = data[3];
      d5 = data[4];
      d6 = data[5];
      d7 = data[6];
      d9 = data[7];     // отопл.
      d8 = data[8];     // водосн.
      d10 = data[9];
      d11 = data[10];
      d12 = data[11];
      d13 = data[12];
      d14 = data[13];
      d15 = data[14];
      olddata = millis();
      SendDataP("q0.picc", 0);                         // удаляем надпись "Данные устарели!"
    }
  }
  if (millis() - olddata > 300000) {
    SendDataP("t6.font", 3);                         // пишем "Данные устарели!" через 5 минут
  }

Явно указал длину читаемого массива - 30 байт (15 int), поскольку размер массива не изменяем.

Вопрос - могли ли эти три вычеркнутые строчки повлиять на зависания?.... как-то сомневаюсь я..... Может задержка где какая нужна?..... Может пытался вычитать слишком много?....

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Похоже опять завис.... опять что ли переходить на nRF.......

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нет, ну Вы же не слышаете. Вот смотрите, Вы передаёте int'ы. Так и лопишите Ваш buf как int - чего он у Вас uint8_t. 

далее, сообщение всегда состоит из 15 int'ов, или возможны варианты? Если всегда, то опишите его как int [15] (как data) и спокойно используйте. Если возможны варианты, то это отдельный разговор.

Далее, что у Вас за библиотека? Потому, что если вот эта, то recv пишется не так, у него второй параметр - указатель, а не голимое число. Показывайте свою.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Шестую строку поставил так:

if (rf95.recv(int(data), 30)) {

работает, принимает, посмотрю дальше....

Спасибо!

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Я не помню уже где брал библиотеку, архив с ней называется     RadioHead-1.89.zip

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Если в шестой строке указываю не 30, а 15 - читает половину массива..... Видимо указывается кол-во байт, а не int-ов

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbel620017 пишет:

Если в шестой строке указываю не 30, а 15 - читает половину массива..... Видимо указывается кол-во байт, а не int-ов

Это да - вне всякого сомнения.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Нет..... виснет.....  Буду эксперементировать с задержками.

У меня на SPI сидит три устройства - SD карта, SX1278 и W5500. Изначально шёл конфликт, поскольку аппартное разделение устройств присутствует, сделал переходные буферные платы на 74HC125. Конфликты ушли. С nRF24 всё было нормально... Чем отличается SX1278?... фиг знает... Я толком не знаю принцип работы этого модуля - может он отсылает обратно CRC, может библиотека подрабатывает после приёма и идёт конфликт по SPI... не пойму...    Наводка с антенны? - так модуль на приём вроде работает, Другой блок, который работает на передачу инфы не виснет...     

Может подскажет кто?... Работает от получаса до нескольких часов и... фсё... намертво, пока не перезагрузишь. Пробовал ставить метки по всей программе дабы найти место зависания - так оказалось виснет в разных частях программы.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А чего толку экспериментировать. Для начала надо понять в каком месте виснет и что при этом делает.

Понавставляйте везде по коду (хоть через строчку) печать всех меняющихся переменных в тот же сериал. Запустите, а когда завистет, посомотрите в каокм месте, чему переменные равны, ну и какие-то выводы сделаете.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну может ваша лора жрет больше, чем нрф. Чуть посильнее дало в эфир и готово.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

ЕвгенийП пишет:

А чего толку экспериментировать. Для начала надо понять в каком месте виснет и что при этом делает.

Понавставляйте везде по коду (хоть через строчку) печать всех меняющихся переменных в тот же сериал. Запустите, а когда завистет, посомотрите в каокм месте, чему переменные равны, ну и какие-то выводы сделаете.

Я примерно по этому пути и иду, Евгений....  Интуиция подсказывает - аппартная это проблема...

 

alexbel620017
Offline
Зарегистрирован: 26.03.2017

sadman41 пишет:

Ну может ваша лора жрет больше, чем нрф. Чуть посильнее дало в эфир и готово.

Уровень передачи выставлен минимальный - 5 (5-23). БП стоит 4 амперный, питание везде шунтировано, самая большая просадка по питанию это 0,15В в момент регистации в сети GSM модуля.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Вобщем, пошёл я, коллеги, таким путём....  Поскольку 4 десятка лет с паяльником в руках кое-чему научили решил поступить радикальным способом... )))   Весь проект предполагается в частный дом сестре, ну а человеческий интернет там не только скоро не появится, а есть подозрение что не появится вовсе. И, сделав над собой усилие и отодрав от себя часть живого я решил расстаться с сетевым модулем, который рисовал мне в браузере красивое ромашковое поле со сводкой погоды и всей телеметрией котельной... (((

Как только W5500 покинул проект всё заработало достойно..... ну, во всяком случае, почти сутки ни одного зависания, программка побежала шустрее, ну и вообще.... W5500 и так-то работал через пень-колоду, пусть отдохнёт. Тем более что засунул я его сюда практически из любви к исскуству, а не по необходимости.

Спасибо большое всем участвующим, особенно Евгению!

sadman41
Offline
Зарегистрирован: 19.10.2016

Наврядли сам по себе W5500 вис... Железка неплохая.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Согласен полностью - очень не плохая, но на SPI голышом три устройства не работали - MOSI, MISO, SCK - все сидят параллельно и кто-то подкорачивал линию. Только когда буферами все их разделил - заработали. Модуль SD карты работает всегда, как танк, W5500 в этом плане противоположность. Какие-то временнЫе косяки может быть... аппаратно буферы (на 74HC125) на все три модуля одинаковы, а стабильность работы этих модулей разная....

alexbel620017
Offline
Зарегистрирован: 26.03.2017

ЕвгенийП

Здравствуйте, Евгений, можно как-то с вами связаться - хочу код вам показать, момент есть который не могу понять.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbel620017 пишет:

хочу код вам показать

Показывайте.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

851 строка.......

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

почты нет у вас?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Выкладывайте, только спойлером прикройте. А комментарии ... "жизнь такова, какова она есть, и больше никакова" :-)

alexbel620017
Offline
Зарегистрирован: 26.03.2017
// при окончательной установке убрать коммент. "аварию отоления"  562 стр.

#include <RH_RF95.h>
#include <Adafruit_SHT31.h>
#include <EEPROM.h>
#include <TinyGPS.h>
#include <Ethernet2.h>
#include <Nextion.h>
#include <OneWire.h>
#include <DS1307RTC.h>
#include <DS3231.h>
#include <Time.h>
#include <SPI.h>
#include <SD.h>
#include <iarduino_Pressure_BMP.h>


// ------------------------- сеть ---------------------------------
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xC3, 0xE2};
IPAddress ip(192, 168, 1, 6);
EthernetServer server(765);

// ------------------------- LoRa ---------------------------------
RH_RF95 rf95(53, 2);                       // (SS, interrupt) внимательно с выводом прерывания на Ардуине!
int bn[5];                                 // Создаём массив для приёма данных

// ------------------------- часы ---------------------------------
DS3231 Clock;
TinyGPS gps;

// ------------------------- давление -----------------------------
iarduino_Pressure_BMP sensor;

// ------------------------- влажность ----------------------------
Adafruit_SHT31 sht31 = Adafruit_SHT31();

// ------------------------- температура --------------------------
OneWire sensDs1(7);                        // датчик температуры подключен к выводу 7 дом
byte bufData1[9];                          // буфер данных температуры в доме
byte addr1[8];                             // массив адреса датчика темп. в доме
OneWire sensDs2(6);                        // датчик температуры подключен к выводу 6 вход
byte bufData2[9];                          // буфер данных
byte addr2[8];                             // массив адреса датчика
bool frchtd = false;                       // флаг разрешения чтения с дисплея "сброса"
bool newdata = false;
bool Century = false;
bool h12;
bool PM;
bool td = false;                           // флаг разрешения обработки данных датчика температуры в доме
bool fwdt = true;                          // флаг WDT
bool fsd = true;                           // флаг однократности вывода "данные устарели"
byte m, s, h, d, M;                        // переменные даты и времени
int Y = 2000;
bool fscht;                                // флаг разрешения суммирования при чтении с дисплея
bool BanTM = false;                        // флаг наличия данных из бани
bool Zu = false;                           // флаг печати значка SD-карты на дисплей
bool fp = false;                           // флаг разрешения сброса раз в сутки
bool fa = true;                            // флаг для однократности сработывания аварии
int celsius1, celsius2, celsius3;          // температура в доме
float celsgis = 100;                       // промежуточная темп. для прохождения гистерезиса
int toutside = 0;                          // температура на улице с датчика влажности
int tPred;                                 // переменная для проверки перехода с одного разряда на два и обратно при печати ул. температуры на дисплей
int p;                                     // давление
int hum;                                   // влажность на улице
int ch;                                    // переменная для вычитывания буфера Nextion
int val;                                   // строка из дисплея
int i;
float tuprm;                               // считанное значение уличной температуры
float huprm;                               // считанное значение уличной влажности
float dvl;                                 // считанное значение атм. давления
bool gisalarm;
float toutsidegis = 100;                   // переменная для гистерезиса
unsigned long mln = 300000;                // период синхронизации с GPS (сначала ч/з 5 минут (считывание альманаха при перв вкл, потом раз в 7 сут. (604800000)
unsigned long sinhr;                       // переменная в мсек задающ. период синхронизации
unsigned long za;                          // переменная в мсек задающ. задержку на сработывание аварии (2 мин, искл. ложных срабатываний)
unsigned long zadavar;                     // переменная в мсек задающ. период синхронизации
unsigned long start;                       // переменная в мсек задающ. цикл считывания данных gps
unsigned long registr;                     // переменная в мсек для таймера регистратора
unsigned long dvt = 3000;                  // период измерения давл. вл. и температуры (нач. 5 сек, потом раз в минуту)
unsigned long dvtperiod;                   // переменная в мсек для таймера измерен. давл.вл и у.темп.
unsigned long loraperiod;                  // переменная таймера проверки приёма LoRa
unsigned long treg = 290000;               // период записи регистратора 5 мин (переменная на 10 сек меньше - догоняет остаток от деления =0)
unsigned long tperiod;                     // переменная в мсек для таймера обработки измерен. темп. в доме
unsigned long nadisplei;                   // переменная в мсек для таймера вывода на дисплей
unsigned long disp = 50;                   // период таймера вывода на дисплей, нач. 1 сек, потом 10 сек.
unsigned long olddata;                     // переменная
unsigned long pwdt;                        // переменная для WDT
unsigned long time, date;                  // переменные для считыв. даты и времени для вычисления "пустой" даты
float gis = 0.2;                           // гистерезис температуры и влажности
float pgis, hgis;                          // вспомогательная переменная для гистерезиса влажн. и давления
String pch;                                // переменная для вывода на дисплей
String SMSOUT;                             // текстовая переменная "номер для смс"
int db1;                                   // темпеатура парной
int db2;                                   // темпеатура комната бани
int db3;                                   // темпеатура т. пола бани
int db4;                                   // нагрев (0 - нет, 1 - нагрев)
int db5;                                   // CRC с LoRa
int d1;                                    // темпеатура выход котла К-->
int d2;                                    // темпеатура вход котла (обратка) K<--
int d5;                                    // темпеатура выход на ТП
int d6;                                    // темпеатура вход с ТП (обратка)
int d7;                                    // темпеатура бойлера
int d8;                                    // давление системы водоснабжения
int d81, d82, d91, d92;                    // промеж. параметры для отобр. гидро давления в СМС
int d9;                                    // давление системы отопления
int d10;                                   // темпеатура в котельной
int d11;                                   // темпеатура в гараже
int d12;                                   // темпеатура скважины
int d3, d4, d13, d14, d15;                 // резерв
String(s1), (s2), (s3), (s4), (s5), (s6), (s7), (s8), (s9), (s10), (s11), (s12), (s13), (s14), (s15), (s16);
String(s151), (s152), (s161), (s162);
String(ss1), (ss2), (ss3), (ss4), (ss5), (ss6), (ss7);

int ttt;

// ------------------------------------------------------ setup --------------------------------------------------------------

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);                      // порт GPS
  Serial2.begin(9600);                      // порт Nextion
  Serial3.begin(9600);                      // порт SIM800

  pinMode(48, OUTPUT);                      // CS SD-карты
  pinMode(49, OUTPUT);                      // CS W5500
  pinMode(33, OUTPUT);                      // выход на WDT
  digitalWrite(33, LOW);

  setSyncProvider(RTC.get);                 // библиотечная команда извлечения данных из модуля часов

  za = millis();                            // переменная в мсек задающ. задержку на сработывание аварии (2 мин, искл. ложных срабатываний)
  sinhr = millis();                         // переменная в мсек для синхронизации по GPS
  zadavar = millis();                       // переменная задержки сработки АВАРИИ по давлению отопл. или t котла (на минуту после вкл. или сброса аварии)
  registr = millis();                       // переменная в мсек для таймера регистратора
  dvtperiod = millis();
  loraperiod = millis();
  tperiod = millis();                       // переменная в мсек для таймера изм. температуры
  nadisplei = millis();                     // переменная в мсек для таймера вывода на дисплей
  olddata = millis();                       // переменная для проверки новизны данных с котельной
  pwdt = millis();

  SendDataP("q0.picc", 11);                 // очистка уличной температуры
  SendDataP("pio0", 0);                     // выключили сирену в Nextion

  if (EEPROM.read(10) == 1) {
    SendDataP("tm5.en", 1);                 // запустили тревогу на дисплее
    frchtd = true;                          // разрешили чтение с дисплея "сброса"
  }
  else {
    SendDataP("page0.tm5.en", 0);           // остановили таймеры мигания "АВАРИИ" на дисплее
    SendDataP("page0.tm6.en", 0);
    SendDataP("page0.p0.pic", 10);          // опять нарисовали "БАНЬКУ"
    frchtd = false;                         // запретили чтение с дисплея "сброса"
  }
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  sensor.begin();                           // инициализация датчика давления
  delay(10);
  sht31.begin(0x44);                        // инициализация датчика влажности
  delay(10);
  SD.begin(48);                             // инициализация модуля SD карты
  delay(10);
  rf95.init();                              // инициализация SX1278
  delay(10);
  //rf95.setTxPower(5, false);                       // мощность 5 - 23, максимальная мощность (при 23) 100мВт (шаги с 5 по 23 не подряд! смотреть в библиотеке)
  //void clearRxBuf();
  delay(10);

  sensDs1.search(addr1);                    // поиск и запись адреса датчика температуры
  sensDs1.write(0x4E);                      // разрешение записи 3-х байт в DS18B20 (предустановка)
  sensDs1.write(0x7F);                      // TH
  sensDs1.write(0xFF);                      // TL
  sensDs1.write(0x20);                      // регистр конфигурации (разрешение: 0х00-0.5  0х20-0.25   0х40-0.125  0х60-0.0625)

  sensDs2.search(addr2);                    // поиск и запись адреса датчика температуры
  sensDs2.write(0x4E);                      // разрешение записи 3-х байт в DS18B20 (предустановка)
  sensDs2.write(0x7F);                      // TH
  sensDs2.write(0xFF);                      // TL
  sensDs2.write(0x20);                      // регистр конфигурации (разрешение: 0х00-0.5  0х20-0.25   0х40-0.125  0х60-0.0625)

  Serial3.println("AT+IPR=9600");           // скорость модема
  delay(200);
  //Serial3.println("AT+CSQ");              // уровень сигнала                   // ПРИ УРОВНЕ СИГНАЛА
  //delay(500);
  Serial3.println("AT+CLIP=1");             // включить АОН
  delay(200);
  Serial3.println("AT+CMGF=1");             // текстовый формат SMS
  delay(200);
  Serial3.println("AT+CSCS=\"GSM\"");       // кодировка текста - GSM
  delay(200);
  Serial3.println("AT+CMGD=1,4");           // удалить все смс
  delay(200);
  Serial3.println("AT+CNMI=2,2,0,0,0");     // вывод смс в консоль
  delay(200);
  Serial3.println("AT&W");                  // запомнить настройки
  delay(200);
}

// ==========================================================================================================================
// ============================================================ L O O P =====================================================

void loop() {
  Serial.println("1");
  //Serial.println(millis());
  ttt++;
  if (ttt == 1000) {
    Serial.println(millis());
    ttt = 0;
  }

  // --------------------------------------- суточный брос ------------------------------------------------------------------

  if (h == 10 && m == 6 && fp == true) {              // RESET в 10 часов 06 минут каждый день
    goto M3;                                          // для сут. сброса нет стробов WDT
  }
  if (m == 8) {
    fp = true;
  }

  // --------------------------------------------------- WDT ----------------------------------------------------------------

  if (millis() - pwdt > 500) {
    if (fwdt) {
      //digitalWrite(33, HIGH);
      fwdt = false;
      pwdt = millis();
    }

    else {
      //digitalWrite(33, LOW);
      fwdt = true;
      pwdt = millis();
    }
  }
M3:

  // -------------------------------------------------- Сеть ------------------------------------------------------------------

  Serial.println("2");
  EthernetClient client = server.available();
  if (client) {
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println("Connection: close");                // the connection will be closed after completion of the response
    client.println("Refresh: 15");                      // обновление страницы через 30 сек
    client.println();
    client.println("<!DOCTYPE HTML>");
    client.println("<html>");  //---------------------- Пишем страницу -------------
    client.println("<head>");
    client.println("<meta charset=\"UTF-8\">");         // Установка кодировки
    client.println("<title>п.Залесье, ул.Весенняя, д.38</title>");
    client.println("</head>");
    client.println("<body background=http://bgpics.ru/pictures/1920x1080/8155-leto-romashki-fon-1920x1080.jpg>");
    client.println("<blockquote>");
    client.println("<h1><u>Погодные данные:</u></h2>");
    client.println("<h2>Температура на улице:     ");
    client.println(50);
    client.println("&deg;");
    client.println("<br />");
    client.println("Влажность на улице:     ");
    client.println(40);
    client.println("&deg;");
    client.println("<br />");
    client.println("Атм. давление:     ");
    client.println(777);
    client.println(" мм.р.ст.");
    client.println("<br />");
    client.println("<br />");
    client.println("Температура в комнате:     ");
    client.println(60);
    client.println("&deg;");
    client.println("<br />");
    client.println("Влажность в комнате:     ");
    client.println(70);
    client.println("&deg;");
    client.println("<br />");
    client.println("</html>"); //------------------------- Закончили страницу -------------------------------
    //delay(300);
    client.stop();
  }

  // ------------------------------------------------- SIM800 ---------------------------------------------------------------
  Serial.println("3");
  //Serial3.println("AT+CSQ");                                               // ПРИ УРОВНЕ СИГНАЛА
  if (Serial3.available()) {
    delay(20);
    char ch = ' ';
    String val = "";
    while (Serial3.available())
    {
      ch = Serial3.read();
      val += char(ch);                                                       // собираем принятые символы в строку
      delay(2);
    }
    //Serial.println(val);                                                   // ПРИ УРОВНЕ СИГНАЛА
    if (val.indexOf("RING") > -1) {                                          // если есть входящий вызов
      if (val.indexOf("9122230000") > -1) {
        SMSOUT = "+79122230000";                                             // мой номер
      }
      else {
        if (val.indexOf("79121111111") > -1) {
          SMSOUT = "+79122857000";                                           // другой номер
        }
        else {
          if (val.indexOf("79121111111") > -1) {
            SMSOUT = "+79122459000";                                         // другой номер
          }
          else {
            Serial3.println("ATH");        // разрываем связь в случае "левого" звонка
            goto M1;
          }
        }
      }
      Serial3.println("ATH");              // разрываем связь в случае одного из трёх звонков
      delay(1000);
      balans();                            // запрос баланса
      s1 = String(toutside);               // строковая переменная с уличной температурой
      s2 = String(hum);                    // строковая переменная с уличной влажностью
      s3 = String(p);                      // строковая переменная с давлением
      s4 = String(celsius1);               // строковая переменная с температурой в доме
      s5 = String(d11);                    // строковая переменная с температурой в гараже
      s6 = String(d10);                    // строковая переменная с температурой в котельной
      s7 = String(d12);                    // строковая переменная с температурой скважины
      s8 = String(d1);                     // строковая переменная с температурой выхода из котла
      s9 = String(d2);                     // строковая переменная с температурой входа в котёл (обратка)
      s10 = String(d5);                    // строковая переменная с температурой выход на ТП
      s11 = String(d6);                    // строковая переменная с температурой ТП обратка
      s14 = String(d7);                    // строковая переменная с температурой бойлера
      d81 = (d8 / 10);                     // формирование дробных переменных для давл. в.с.
      d82 = (d8 - (d8 / 10) * 10);         // формирование дробных переменных для давл. в.с.
      d91 = (d9 / 10);                     // формирование дробных переменных для давл. отопл.
      d92 = (d9 - (d9 / 10) * 10);         // формирование дробных переменных для давл. отопл.
      s151 = String(d81);                  // строковая переменная с давлением водоснабжения
      s152 = String(d82);                  // строковая переменная с давлением водоснабжения
      s161 = String(d91);                  // строковая переменная с давлением отопления
      s162 = String(d92);                  // строковая переменная с давлением отопления

      sms(String("Balans sim: " + ss1 + ss2 + ss3 + ss4 + ss5 + ss6 + ss7 + '\n' + '\n'
                 + "Temp. ulica: " + s1 + '\n'
                 + "Vlagnost ulica: " + s2 + "%" + '\n'
                 + "Davlenie atm: " + s3 + "mm" + '\n' + '\n'
                 + "Temp. dom: " + s4 + '\n'
                 + "Temp. garag: " + s5 + '\n'
                 + "Temp. kotelnay: " + s6 + '\n'
                 + "Temp. skvagina: " + s7 + '\n' + '\n'
                 + "Temp. kotel podacha: " + s8 + '\n'
                 + "Temp. kotel vozvrat: " + s9 + '\n'
                 + "Temp. TP podacha: " + s10 + '\n'
                 + "Temp. TP vozvrat: " + s11 + '\n'
                 + "Temp. boyler: " + s14 + '\n' + '\n'
                 + "Davl. vodosn: " + s151 + "," + s152 + '\n'
                 + "Davl. otopl: " + s161 + "," + s162), String(SMSOUT));   // номер на кот пойдет смс
    }

    if (val.indexOf("+CMT") > -1) {                                         // если есть входящее смс
      if (val.indexOf("9122230000") > -1) {
        if (val.indexOf("Reset") > -1) {
          EEPROM.write(10, 0);                 // сбросили тревогу
          delay(5);
          SendDataP("p21.pic", 7);             // установили картинку на Nextion без треугольника
          SendDataP("tm1.en", 0);
          SendDataP("tm2.en", 0);
          fa = true;                           // разрешили вновь сработку тревоги, сбросив её с дисплея   tm1.en=0
          digitalWrite(64, HIGH);              // пикнули
          delay(40);
          digitalWrite(64, LOW);
          digitalWrite(62, HIGH);              // аппаратный RESET
          delay(100);
        }
        if (val.indexOf("S") > -1) {           // смотрим время последней синхронизации с GPS, отправл. СМС
          sms(String("Poslednyy sinhr: " + String(EEPROM.read(13)) + "." + String(EEPROM.read(12))
                     + "." + String(EEPROM.read(11)) + "  " + String(EEPROM.read(14))
                     + ":" + String(EEPROM.read(15))), "+79122230000");
        }
      }
    }
  }
M1:

  // -------------------------------------------------- SD карта ------------------------------------------------------------------------------
  Serial.println("4");
  if ((millis() - registr) > treg && m % 5 == 0) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.
    SD.begin(48);
    String logStringData = "";                                          // формирование строки с данными
    String Bm;                                                          // переменная для минут меньше 10, чтобы минуты на дисплее были с нулём
    if (m < 10) {
      Bm = "0" + String(m);
    }
    else {
      Bm = String(m);
    }
    String Bh;                                                          // переменная для часов меньше 10, чтобы часы на дисплее были с нулём
    if (h < 10) {
      Bh = "0" + String(h);
    }
    else {
      Bh = String(h);
    }
    // формируем строку с данными
    logStringData = Bh + ":" + Bm + " > " + "Котёл " + d1 + "/" + d2 + "; ТП " + d5 + "/" + d6 + "; Бойл " + d7 + "; Давл.вс " + d8 / 10 + ","
                    + (d8 - (d8 / 10) * 10) + "; Давл.от. " + d9 / 10 + "," + (d9 - (d9 / 10) * 10) + ";" + "\n" + "        Темп ул. " + toutside + "; Вл. "
                    + hum + "; Давл. " + p + "; Темп. дом " + celsius1 + "; Темп. гараж " + d11 + "; Темп. кот. " + d10 + "; Темп. скв. " + d12 + ";";
    //Serial.println(logStringData);
    String DirectName = "20" + String(Y) + "/" + String(M);                // Создаём имя папки из месяца и года
    SD.mkdir(DirectName);
    // Открываем файл, Если файла с таким именем не будет, ардуино создаст его.
    String logStringName = DirectName + "/" + String(d) + ".txt";          // формируем текстовый файл на один день максимум 12 знаков в названии файла
    //Serial.println (logStringName);
    File dataFile = SD.open(logStringName, FILE_WRITE);
    // Если все хорошо, то записываем строку:
    if (dataFile) {
      dataFile.println(logStringData);                                     // в файл записываем строку данных с переводом строки
      dataFile.close();                                                    // закрываем файл
      SendDataP("page0.p1.pic", 3);                                        // ЗЕЛЁНЫЙ значёк
      //Serial.println("Запись прошла на SD");
      Zu = true;                                                           // флаг для печати нужного значка в цикле печати
    }
    else {
      SendDataP("page0.p1.pic", 4);                                        // КРАСНЫЙ значёк
      //Serial.println("Ошибка записи на SD!");
      Zu = false;                                                          // флаг для печати нужного значка в цикле печати
    }
    registr = millis();
  }

  // -------------------------------------------------- ОСНОВНОЙ ЦИКЛ ------------------------------------------------
  // --------------------------------------- влажность и температура с датчика влажности -----------------------------
  Serial.println("5");

  if (millis() - dvtperiod > dvt) {               // таймер для измерения температуры, давл. и влажности, dvt 5c\60c
    tuprm = sht31.readTemperature();              //снятые с датчика значения вл и темп для работы с ними  (float)
    huprm = sht31.readHumidity();

    if ((huprm - hgis > gis) || (hgis - huprm > gis)) {                    // проверка на гистерезис для влажности
      hum = huprm;
      if (huprm - hum >= 0.5) {
        hum = hum + 1;
      }
      hgis = huprm;
    }

    if ((toutsidegis - tuprm > gis) || (tuprm - toutsidegis > gis) || (toutsidegis - tuprm < -gis) || (tuprm - toutsidegis < -gis)) {    // проверка на гистерезис для температуры
      toutside = tuprm;
      if (tuprm - toutside >= 0.5) {
        toutside = toutside + 1;
      }
      if (tuprm - toutside <= -0.5) {
        toutside = toutside - 1;
      }
      toutsidegis = tuprm;
    }

    // --------------------------------------- давление -----------------------------------------------------------
    sensor.read(1);
    dvl = sensor.pressure;
    if ((pgis - dvl > gis) || (dvl - pgis > gis)) {
      p = dvl;
      if (dvl - p >= 0.5) {
        p = p + 1;
      }
      pgis = dvl;
    }
    Serial.println("6");
    // ------------------------------------- температура DS18B20 (дом) ---------------------------------------------
    sensDs1.reset();
    sensDs1.select(addr1);
    sensDs1.write(0x44, 0);                   // инициализация измерения с первого датчика
    sensDs2.reset();
    sensDs2.select(addr2);
    sensDs2.write(0x44, 0);                   // инициализация измерения с второго датчика
    delay(300);
    sensDs1.reset();
    sensDs1.select(addr1);
    sensDs1.write(0xBE, 0);                                             // команда чтения памяти датчика
    sensDs1.read_bytes(bufData1, 9);                                    // чтение памяти датчика, 9 байтов
    if ( OneWire::crc8(bufData1, 8) == bufData1[8] ) {
      float cels1 = (float)((int)bufData1[0] | (((int)bufData1[1]) << 8)) * 0.0625;
      celsius1 = cels1;                                                 // температура в доме
      if ((cels1 - celsius1) >= 0.5) {
        celsius1 = celsius1 + 1;
      }
    }
    sensDs2.reset();
    sensDs2.select(addr2);
    sensDs2.write(0xBE, 0);                                             // команда чтения памяти датчика
    sensDs2.read_bytes(bufData2, 9);                                    // чтение памяти датчика, 9 байтов
    if ( OneWire::crc8(bufData2, 8) == bufData2[8] ) {
      float cels2 = (float)((int)bufData2[0] | (((int)bufData2[1]) << 8)) * 0.0625;
      celsius2 = cels2;                                                 // температура входа
      if ((cels2 - celsius2) >= 0.5) {
        celsius2 = celsius2 + 1;
      }
    }
    dvtperiod = millis();
    dvt = 5000;                              // установка таймера изм. темп, давления и влажности в 1 мин.

    // -------------------------------------------- LoRa ------------------------------------------------------------
    Serial.println("7");
    if (rf95.available()) {
      delay(10);
      //rf95.recv(int(bn), sizeof(bn));
      rf95.recv(int(bn), 10);
      if (bn[0] + bn[2] + bn[4] + bn[6] == bn[8] && bn[0] + bn[2] + bn[4] + bn[6] != 0) {       // проверка на отсутствие 0 приёма и на соответствие CRC
        db1 = bn[0];
        db2 = bn[2];
        db3 = bn[4];
        db4 = bn[6];
        db5 = bn[8];

        Serial.println(bn[0]);
        Serial.println(bn[1]);
        Serial.println(bn[2]);
        Serial.println(bn[3]);
        Serial.println(bn[4]);
        Serial.println(bn[5]);
        Serial.println(bn[6]);
        Serial.println(bn[7]);
        Serial.println(bn[8]);
        Serial.println(bn[9]);
        Serial.println();

        olddata = millis();
        fsd = true;
        BanTM = true;                         // есть данные из бани
      }
    }
    void clearRxBuf();
    if (millis() - olddata > 60000 && fsd == true) {
      BanTM = false;                         // нет данных из бани
      fsd = false;
    }

  }          // ------------------- конец ОСНОВНОГО цикла температуры, влажности, LORA ---------------------

  //----------------------------------------------- работа  GPS  модуля ----------------------------------------------------------------------
  Serial.println("8");
  if (millis() - sinhr > mln) {
    newdata = false;
    start = millis();
    while (millis() - start < 2000)
    {
      if (Serial1.available())
      {
        char c = Serial1.read();    // чтение массива, переданного NEO-6M
        //Serial.print(c);          // вывести на печать массив из NEO-6M
        if (gps.encode(c))          // проверка данных на правильность
        {
          newdata = true;
          break;                    // остановить цикл при нормальной декодировке
        }
      }
    }
    if (newdata)
    {
      getgps(gps);                  // при нормальной декодеровке уходим на выполнение getgps(TinyGPS &gps)
    }
  }

  d8 = 26;                                  //
  d9 = 20;                                  // отопл.

  // --------------------------------- вывод на Nextion уличной температуры ------------------------------------------------
  Serial.println("9");
  if ((millis() - nadisplei) > disp) {

    if ((abs(tPred) == 10 && abs(toutside) == 9) || (tPred < 0 && toutside >= 0) || (toutside < 0 && tPred >= 0)) {  // переход с двух разрядов температуры на один - очистка знакомест
      SendDataP("q0.picc", 11);                  // очистка всей температуры
    }
    if (toutside < 0 && toutside > -10) {              // ----  два разряда температуры    (  -5  )
      SendDataP("n29.picc", 11);                  // печать минуса
      SendDataP("n32.val", abs(toutside));
      SendDataP("t43.picc", 11);                  // печать градуса двух разрядов
    }
    if (toutside < 10 && toutside >= 0) {              // ------------  один разряд температуры   (  8  )
      SendDataP("n30.val", toutside);
      SendDataP("t42.picc", 11);                  // печать градуса одного разряда
    }
    if (toutside <= -10) {                             // ------------  три разряда температуры   (  -23   )
      SendDataP("n0.val", abs(toutside));         // печать температуры
      SendDataP("n31.picc", 11);                  // печать минуса
      SendDataP("t0.picc", 11);                   // печать градуса одного разряда
    }
    if (toutside >= 10) {                              // ------------  три разряда температуры   (  40   )
      SendDataP("n28.val", toutside);             // печать температуры
      SendDataP("t41.picc", 11);                  // печать градуса одного разряда
    }
    tPred = toutside;

    // ---------------- печать ТМ параметров ------------------
    Serial.println("10");
    SendDataP("n3.val", hum);                                 // печать влажности
    SendDataP("n4.val", p);                                   // печать давления
    SendDataP("n12.val", celsius1);                           // печать температуры в доме
    SendDataP("page0.n14.val", d11);                          // печать температуры в гараже
    SendDataP("page0.n15.val", d10);                          // печать температуры в котельной
    SendDataP("page0.n16.val", d12);                          // печать температуры скважины
    SendDataP("page0.n7.val", d1);                            // печать температуры котёл подача
    SendDataP("page0.n8.val", d2);                            // печать температуры котёл обратка
    SendDataP("page0.n21.val", d1 - d2);                      // печать дэльты температуры котла
    SendDataP("page0.n9.val", d5);                            // печать температуры ТП подача
    SendDataP("page0.n10.val", d6);                           // печать температуры ТП обратка
    SendDataP("page0.n22.val", d5 - d6);                      // печать дэльты температуры ТП
    SendDataP("page0.n11.val", d7);                           // печать температуры бойлера
    SendDataP("page0.n23.val", d1 - d7);                      // печать дэльты температуры бойлера
    SendDataP("page0.n17.val", d9 / 10);                      // печать целого давления отопления
    SendDataP("page0.n19.val", d9 - (d9 / 10) * 10);          // печать десяток давления отопления
    SendDataP("page0.n18.val", d8 / 10);                      // печать целого давления водоснабжения
    SendDataP("page0.n20.val", d8 - (d8 / 10) * 10);          // печать десяток давления водоснабжения
    SendDataP("page0.n13.val", celsius2);                     // печать температуры входа
    if (BanTM) {                                              // есть инфа с бани
      SendDataP("page1.n7.val", db1);                         // печать температуры парной в бане
      SendDataP("page1.n9.val", db2);                         // печать температуры комнаты в бане
      SendDataP("page1.n8.val", db3);                         // печать температуры т.пола в бане
      SendDataP("page1.t2.picc", 11);                         // рисуем надписи и градусы
      SendDataP("page1.t1.picc", 11);                         // рисуем надписи и градусы
      SendDataP("page1.t5.picc", 11);                         // рисуем надписи и градусы
      SendDataP("page1.t34.picc", 11);                        // рисуем надписи и градусы
      SendDataP("page1.t7.picc", 11);                         // рисуем надписи и градусы
      SendDataP("page1.t8.picc", 11);                         // рисуем надписи и градусы
      if (db4 == 1) {                                         // нагрев включен
        SendDataP("page1.tm3.en", 1);
      }
      else {                                                  // нагрев выключен
        SendDataP("page1.tm3.en", 0);                         // останавливаем таймеры "костра"
        SendDataP("page1.tm4.en", 0);
        SendDataP("page1.tm5.en", 0);
        SendDataP("page1.tm6.en", 0);
        SendDataP("page1.p3.pic", 12);                        // рисуем картинку "нагрев выключен"
      }
    }
    else {                                                    //  нет инфы с бани
      SendDataP("page1.tm3.en", 0);                           // останавливаем таймеры "костра"
      SendDataP("page1.tm4.en", 0);
      SendDataP("page1.tm5.en", 0);
      SendDataP("page1.tm6.en", 0);
      SendDataP("page1.t9.picc", 11);                         // закрасили верх от "нагрев выключен"
      SendDataP("page1.p4.pic", 16);                          // написали "нет данных" от бани
    }

    // ------------------------------------------------------ часы -------------------------------------------------------

    Y = Clock.getYear();                      // получение года из модуля часов DS3231
    M = Clock.getMonth(Century);              // получение месяца из модуля часов DS3231
    d = Clock.getDate();                      // получение дня из модуля часов DS3231
    h = Clock.getHour(h12, PM);               // получение часов из модуля часов DS3231
    m = Clock.getMinute();                    // получение минут из модуля часов DS3231
    s = Clock.getSecond();                    // получение секунд из модуля часов DS3231

    // ---------------------------------- синхронизация часов  и календаря с Nextion ------------------------------------
    SendDataP("rtc0", 2000 + Y);
    SendDataP("rtc1", M);
    SendDataP("rtc2", d);
    SendDataP("rtc3", h);
    SendDataP("rtc4", m);
    SendDataP("rtc5", s);
    Serial.println("11");
    // ------------------------------------ печать значка SD-карты на дисплей -----------------------------------------
    if (Zu) {
      SendDataP("page0.p1.pic", 3);                                        // ЗЕЛЁНЫЙ значёк
    }
    else {
      SendDataP("page0.p1.pic", 4);                                        // КРАСНЫЙ значёк
    }

    disp = 10000;                                         // установка периода вывода на дисплей основной информации (10 сек)
    nadisplei = millis();
  } // -------------------------------------- конец печати на Nextion ----------------------------------------------------


  // ---------------------------------------------------------------- авария ----------------------------------------------------------

  d9 = 7;
  d1 = 31;
  if ((d9 < 6 || d1 < 30) && fa == true) {                                     // условия аварии: давл отопл <0,6 Атм или темп выхода котла <30 градусов / флаг однократности сработки "Аварии"
  }
  else {
    za = millis();
  }
  // при наступлении аварийного условия ждём минуту устоявшегося события (типа защита от "дребезга")
  if ((millis() - za) > 60000) {
    sms(String("AVARIY OTOPLENIY!"), String("+79122230000"));
    EEPROM.write(10, 1);                                                       // записали аварию в память
    delay(5);
    SendDataP("page0.tm5.en", 1);                                              // запустили таймеры "АВАРИИ" на Nextion
    frchtd = true;                                                             // флаг разрешения чтения с дисплея "сброс аварии"
    digitalWrite(64, HIGH);
    delay(40);
    digitalWrite(64, LOW);
    delay(100);                                                                // сработка разрешена один раз через 10 мин после включения
    digitalWrite(64, HIGH);
    delay(40);
    digitalWrite(64, LOW);
    delay(400);
    digitalWrite(64, HIGH);
    delay(700);
    digitalWrite(64, LOW);
    fa = false;                                                                // флаг однократности сработки "Аварии"
  }
  Serial.println("12");
  // ---------------------------------------- сброс тревоги и смена страницы (принимаем с Nextion) ----------------------------

  if (Serial2.available()) {
    delay (20);
    i = 1;
    val = 0;
    while (Serial2.available()) {
      ch = Serial2.read();
      delay (2);
      if (ch == 101) {
        fscht = true;                         // разрешили счёт считываемых байт если передача началась со 101
      }
      if (i < 5 && fscht) {
        val += ch;                            //собираем принятые символы в строку (4 байта всего): 173 - сброс аварии
        i++;
      }
    }
    //Serial.println(val);
    if (val == 196 || val == 148) {
      disp = 0;                              // разовый период вывода на дисплей  page1.
      nadisplei = millis();
      SendDataP("q0.picc", 11);               // очистка места температуры при переключении страницы
    }
    fscht = false;                              // закончили и опять разрешили счёт четырёх первых байт с дисплея
    if (frchtd) {                               // разрешение сброса тревоги с дисплея
      if ((val == 196 || val == 115) && EEPROM.read(10) == 1) {               // приняли с дисплея "сброс аварии"
        EEPROM.write(10, 0);                    // сбросили тревогу в ЕЕПРОМе
        delay(5);
        Serial.println("сброс");
        SendDataP("page0.tm5.en", 0);           // остановили таймеры мигания "АВАРИИ" на дисплее
        SendDataP("page0.tm6.en", 0);
        SendDataP("page0.p0.pic", 10);          // опять нарисовали "БАНЬКУ"
        SendDataP("pio0", 0);                   // выключили сирену в Nextion
        fa = true;                              // разрешили вновь сработку тревоги
        za = millis();
        frchtd = false;                         // запретили читать "сброс" с дисплея, но чтение перекл страницы возможно
      }
    }
  }

}                      // -------------------------- конец LOOP ------------------------------
// --------------------------------------------------------------------

//================================================================================================================================
//================================================================================================================================

// ----------------- подпрограмма вывода данных из gps и синхронизации модуля часов ---------------------

void getgps(TinyGPS & gps)
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  // вынимание данных из массива, полученного из модуля gps
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);
  hour = hour + 5;                                        // переделка час. пояса
  if (hour > 23)                                          // избежание 25, 26 часов на дисплее
  {
    hour = hour - 24;
  }
  if (hour > 0 && hour < 5) {                             // коррекция даты в зависимости от времени и час. пояса
    day = day + 1;                                        // от 0 до 5 утра синхронизируется ещё старая дата (по Гринвичу)
  }
  gps.get_datetime(&date, &time);
  if (date == 0) {                                        // проверка на "нулевую дату" (бывает такой косяк при синхр.)
    mln = 60000;                                          // при косячной дате период синхр. GPS  - 1 минута
    Serial.println("Косячная дата! - нет синхронизации");
  }
  else {
    setTime(hour, minute, second, day, month, year);      // устанавливаем: часы, минуты, секунды, день, месяц, год)
    RTC.set(now());                                       // применяем значение
    // запись времени и даты последней синхронизации с GPS, можно вытащить смской "S"
    EEPROM.write(11, 2000 + Y);     // год
    delay(5);
    EEPROM.write(12, M);            // месяц
    delay(5);
    EEPROM.write(13, d);            // день
    delay(5);
    EEPROM.write(14, h);            // часы
    delay(5);
    EEPROM.write(15, m);            // минуты
    delay(5);
    Serial.println("Дата норма!");
    mln = 90000000;                                      // при норм. дате период синхр. GPS - до след. перезагрузки устройства, для запаса 25 часов. (90000000)
  }
  sinhr = millis();
}

//=========================================== Подпрограмма посылки SMS ====================================

void sms(String text, String phone)
{
  //Serial3.println("AT+CMGS=\"" + phone + "\"");
  delay(1000);
  Serial3.println(text);
  delay(300);
  Serial3.println((char)26);
  delay(300);
  Serial3.println("AT+CMGD=1,4");
  delay(500);
}
// ============================= Подпрограмма отправки на Nextion =========================================

void SendDataP(String dev, int dataP)           // для вывода картинок и чисел
{
  Serial2.print(dev);   // Отправляем данные dev(номер экрана, название переменной) на Nextion
  Serial2.print("=");   // Отправляем данные =(знак равно, далее передаем сами данные) на Nextion
  Serial2.print(dataP); // Отправляем данные data(данные) на Nextion
  Serial2.write(0xff);  // Отправляем данные 0xff(значение показывающее Nextion конец передачи) на Nextion
  Serial2.write(0xff);  // Отправляем данные 0xff(значение показывающее Nextion конец передачи) на Nextion
  Serial2.write(0xff);  // Отправляем данные 0xff(значение показывающее Nextion конец передачи) на Nextion
  dev = "";             // Очищаем переменную
}

// ============================= Подпрограмма получения баланса GSM =========================================

void balans()                                // получение баланса
{
  Serial3.println("AT+CUSD=1,\"#100#\"");    // запрос баланса
  while (Serial3.available())                // очистка буфера
  {
    Serial3.read();
    delay(2);
  }
  delay(7000);
  if (Serial3.available()) {                 // задержка спец. не нужна - 7 сек. хватает
    char ch = ' ';
    String val = "";
    while (Serial3.available())
    {
      ch = Serial3.read();
      val += char(ch);                       //собираем принятые символы в строку
      delay(3);
    }
    if (val.indexOf("+CUSD") > -1) {
      char result1 = val.charAt(21);         // для МТС\SIM800 21
      char result2 = val.charAt(22);
      char result3 = val.charAt(23);
      char result4 = val.charAt(24);
      char result5 = val.charAt(25);
      char result6 = val.charAt(26);
      char result7 = val.charAt(27);
      ss1 = String(result1);
      ss2 = String(result2);
      ss3 = String(result3);
      ss4 = String(result4);
      ss5 = String(result5);
      ss6 = String(result6);
      ss7 = String(result7);
    }
  }
}

Блок с 499-533 строки - если вставляю в другое место, не там где сейчас стоит, принимается всякая ерунда.

И если идёт приём на LoRa то результат измерения температуры celsius2 соскакивает на ноль. При следующем измерении - нормально - 25 градусов показывает. Как только LoRa ловит через 10 секунд новую инфу - опять celsius2 ноль.....

Код не сложный, но большой, а программист я начинающий....

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbel620017 пишет:

Блок с 499-533 строки - если вставляю в другое место, не там где сейчас стоит, принимается всякая ерунда.

И если идёт приём на LoRa то результат измерения температуры celsius2 соскакивает на ноль. При следующем измерении - нормально - 25 градусов показывает. Как только LoRa ловит через 10 секунд новую инфу - опять celsius2 ноль.....

Второй абзац - это при коде "как сейчас"? А то я не понял Вашего "если вставляю в другое место"

Я завтра посмотрю, сейчас уже отключаюсь.

sadman41
Offline
Зарегистрирован: 19.10.2016

Наверное начинающему программисту машину кирпичей разгрузить, в принципе, несложно. Просто она большая, а так всё просто...

alexbel620017
Offline
Зарегистрирован: 26.03.2017

ЕвгенийП пишет:

alexbel620017 пишет:

Блок с 499-533 строки - если вставляю в другое место, не там где сейчас стоит, принимается всякая ерунда.

И если идёт приём на LoRa то результат измерения температуры celsius2 соскакивает на ноль. При следующем измерении - нормально - 25 градусов показывает. Как только LoRa ловит через 10 секунд новую инфу - опять celsius2 ноль.....

Второй абзац - это при коде "как сейчас"? А то я не понял Вашего "если вставляю в другое место"

Я завтра посмотрю, сейчас уже отключаюсь.

Да, комментарий мой к этому коду, кот. выше

alexbel620017
Offline
Зарегистрирован: 26.03.2017

sadman41 пишет:

Наверное начинающему программисту машину кирпичей разгрузить, в принципе, несложно. Просто она большая, а так всё просто...

ну вот, о чём я и говорил..... )))

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Блок с 499-533 строки - если вставляю в другое место, не там где сейчас стоит, принимается всякая ерунда.

ну совершенно неудивительно, если сравнить строчки 504 и 25...

Ладно, не буду дальше, оставлю удовольствие Евгению. Тут есть где разгуляться :)

А глядя на строчки 835 - 849 - сразу понимаешь, почему новички предпочитают Мегу.  Разумное использование памяти? - А зачем...

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

ну вот, о чём я и говорил..... )))

если вы пишете огромные простыни "грязного" неэффективного кода - будьте готовы слышать язвительные замечания в свой адрес. Рассматривайте  критику не как обиду и агрессию, а как попытку донести до вас новые знания и толчок к улучшению своего кода.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

b707 пишет:

alexbel620017 пишет:

Блок с 499-533 строки - если вставляю в другое место, не там где сейчас стоит, принимается всякая ерунда.

ну совершенно неудивительно, если сравнить строчки 504 и 25...

Ладно, не буду дальше, оставлю удовольствие Евгению. Тут есть где разгуляться :)

А глядя на строчки 835 - 849 - сразу понимаешь, почему новички предпочитают Мегу.  Разумное использование памяти? - А зачем...

504 и 25  - что не так? подскажите. Массив из пяти интов, 10 байт. Приём у лоры только 8-ми битные переменные, но компилятор не ругается. Если в 504 прямо указываю uint8_t то ничего не меняется.

b707
Offline
Зарегистрирован: 26.05.2017

Почитал ветку сначала - и хочу отметить.

alexbel620017 - вы систематически путаете int и байт.  Они не равны друг другу, в int - 2 байта, а не один.

Именно из-за этого вам приходится делать сложные преобразования массивов, поэтому у вас оказываются после передачи заполнены только каждый второй элемент. Вы регулярно пишете данные за пределы массива либо передаете или принимаете пакеты неверного размера.

С вероятностью в 99% именно этим обьяснялись зависания программы год назад - а вовсе не "аппаратными проблемами". Ровно те же самые проблемы остались в вашем коде и сейчас. То что работоспособность кода зависит от взаимного положения частей и то, что запуск лоры портит значения температуры - обьясняются очень просто - записью за границы массива.

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

504 и 25  - что не так? подскажите. Массив из пяти интов, 10 байт. Приём у лоры только 8-ми битные переменные, но компилятор не ругается. Если в 504 прямо указываю uint8_t то ничего не меняется.

точнее не 504, а начиная со строки 505.

массив из пяти интов, говорите? - так с какой стати вы обращаетесь в этом массиве к элементам вплоть до девятого???

alexbel620017
Offline
Зарегистрирован: 26.03.2017

Я понимаю разницу, знаю что в инте 2 байта, но я перебрал такую кучу вариантов с указанием переменных... а толку нет

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Я понимаю разницу, знаю что в инте 2 байта, но я перебрал такую кучу вариантов с указанием переменных... а толку нет

именно потому и перебирали, что вы этого не понимаете. 

alexbel620017
Offline
Зарегистрирован: 26.03.2017

b707 пишет:

alexbel620017 пишет:

504 и 25  - что не так? подскажите. Массив из пяти интов, 10 байт. Приём у лоры только 8-ми битные переменные, но компилятор не ругается. Если в 504 прямо указываю uint8_t то ничего не меняется.

точнее не 504, а начиная со строки 505.

массив из пяти интов, говорите? - так с какой стати вы обращаетесь в этом массиве к элементам вплоть до девятого???

Передаётся массив из 5 интов, 10 байт. Видимо и приём ведётся также - последовательно 10 байт...... Что я не так делаю? 

Вот код передатчика:

CRC = celsius1 + celsius2 + celsius3 + nagrev;
    int data[5] = {celsius1, celsius2, celsius3, nagrev, CRC};
    //int data[5] = {-20, -30, -40, 0, 66};
    rf95.send((uint8_t*)&data, sizeof(data));
    rf95.waitPacketSent();

 

alexbel620017
Offline
Зарегистрирован: 26.03.2017

b707 пишет:

alexbel620017 пишет:

Я понимаю разницу, знаю что в инте 2 байта, но я перебрал такую кучу вариантов с указанием переменных... а толку нет

именно потому и перебирали, что вы этого не понимаете. 

Скорее всего......

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Едрить там кадавр! Без ящика водки - точно не разберёсси.

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Передаётся массив из 5 интов, 10 байт. Видимо и приём ведётся также - последовательно 10 байт...... Что я не так делаю?

что вы не так делаете???

Вот код:

   if (rf95.available()) {
      delay(10);
      //rf95.recv(int(bn), sizeof(bn));
      rf95.recv(int(bn), 10);
      if (bn[0] + bn[2] + bn[4] + bn[6] == bn[8] && bn[0] + bn[2] + bn[4] + bn[6] != 0) {       // проверка на отсутствие 0 приёма и на соответствие CRC
        db1 = bn[0];
        db2 = bn[2];
        db3 = bn[4];
        db4 = bn[6];
        db5 = bn[8];

        Serial.println(bn[0]);
        Serial.println(bn[1]);
        Serial.println(bn[2]);
        Serial.println(bn[3]);
        Serial.println(bn[4]);
        Serial.println(bn[5]);
        Serial.println(bn[6]);
        Serial.println(bn[7]);
        Serial.println(bn[8]);
        Serial.println(bn[9]);
        Serial.println();

если в массиве только пять интов, то куда вы обращаетесь в строчках 9 и 10? Что такое элементы 6 и 8 ?

- вот вы и влезли в чужую область памяти, при этом знаете что бывает? - программа либо зависает (привет вопросам годичной давности) либо в ней портятся другие переменные - вот вам и обнуление температуры

b707
Offline
Зарегистрирован: 26.05.2017

Алекс, Вы реально путаете инты и байты. Обьявили массив из 5 интов, запомнили, что в нем 10 байт - но у вас в голове каша, поэтому когда вы начинаете обращаться к массиву - вы помните, что там "чего-то десять", а чего - забыли. Вот и вышло, что в массиве пять элементов, а вы обращаетесь к десяти и вылезаете в чужую область памяти.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

"- вот вы и влезли в чужую область памяти, при этом знаете что бывает? - программа либо зависает (привет вопросам годичной давности) либо в ней портятся другие переменные - вот вам и обнуление температуры"

я вижу что это так и происходит, только не могу понять почему. При чтении rf95.recv(int(bn), 10); мои данные содержатся в чётных байтах, потому и печатаю с нулевого по девятый. И вынимаю чётные.

b707
Offline
Зарегистрирован: 26.05.2017

DIYMan пишет:

Едрить там кадавр! Без ящика водки - точно не разберёсси.

"Код несложный, но большой". И бестолковый.

Типично новичковый, когда писать еще не умеем, а уже хочется "мега-прогу" :)))

sadman41
Offline
Зарегистрирован: 19.10.2016

Главное - штоп до управления газовым котлом дело не дошло.

alexbel620017
Offline
Зарегистрирован: 26.03.2017

b707 пишет:

Алекс, Вы реально путаете инты и байты. Обьявили массив из 5 интов, запомнили, что в нем 10 байт - но у вас в голове каша, поэтому когда вы начинаете обращаться к массиву - вы помните, что там "чего-то десять", а чего - забыли. Вот и вышло, что в массиве пять элементов, а вы обращаетесь к десяти и вылезаете в чужую область памяти.

Блин, подскажите как надо пожалуйста! Я понимаю что вы правы, но не знаю как на деле это написать.....

Если я отправляю 5 интов (10 байт), то и приняться должны 10 байт....

Что-то я не допонимаю или не знаю.....

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

При чтении rf95.recv(int(bn), 10); мои данные содержатся в чётных байтах, потому и печатаю с нулевого по девятый. И вынимаю чётные.

Вы голову-то включите. Вы читаете четные инты, а не четные байты!

alexbel620017
Offline
Зарегистрирован: 26.03.2017

sadman41 пишет:
Главное - штоп до управления газовым котлом дело не дошло.

))))))) Не, система чисто информационная, не управляющая. Тот проект что я год назад делал уже давно в частном доме сестры стоит и работает. Это себе делаю.

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Блин, подскажите как надо пожалуйста! Я понимаю что вы правы, но не знаю как на деле это написать.....

Если я отправляю 5 интов (10 байт), то и приняться должны 10 байт....

Оставьте вы байты, раз не понимаете. Если вы отправляете пять интов - то и принимайте пять интов. Ваши данные содержатся в элементах с bn[0] по bn[4], подряд, а не в четных

sadman41
Offline
Зарегистрирован: 19.10.2016

Завидую я вам, новичкам. Глаза горят, руки по клавиатуре бьют. У меня вот даже мысли не возникало все эти умные бани лепить, ибо геморрой это редкостный, когда знаешь, что в перспективе ожидает.

b707
Offline
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Тот проект что я год назад делал уже давно .... стоит и работает.

позвольте вам не поверить. Ваш стиль за год не изменился, в коде косяк на косяке. Сестру жалко.