2560 зависает с LoRa

b707
Онлайн
Зарегистрирован: 26.05.2017

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

+100, нет даже +100500

 

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

b707 пишет:

alexbel620017 пишет:

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

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

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

Поставил приём 5, данные всё также только в чётных...... почему??? Как при присвоении переменным массива принятых данных программа умудряется перепрыгивать через один....

При печати выводится десять чисел: 

27

0

28

0

27

0

1

0

83

0

 

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

При печати выводится десять чисел: 

27

0

28

0

27

0

1

0

82

0

 

Алекс, ну а сколько программа должна напечатать, если у вас в коде 10 оператора print ?

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

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

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Поставил приём 5, данные всё также только в чётных...... почему??? Как при присвоении переменным массива принятых данных программа умудряется перепрыгивать через один....

покажите новый код, как вы поставили прием 5. Только код целиком - и именно тот, что тестируете, а не какой-то "я вот тут чуть-чуть изменил"

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

Так значения записывает программа, а не я. Принтом я только вывожу на печать то что есть. Элементам массива я ничего не присваиваю..... присваивает программа. Я с вами согласен, что данные должны быть в первых пяти, но на деле это не так - они в чётных элементах массива оказываются....  Работа этой строки rf95.recv(int(bn), 5); и вызывает залезание в чужую область памяти скорее всего... но почему?

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

b707 пишет:

alexbel620017 пишет:

Поставил приём 5, данные всё также только в чётных...... почему??? Как при присвоении переменным массива принятых данных программа умудряется перепрыгивать через один....

покажите новый код, как вы поставили прием 5. Только код целиком - и именно тот, что тестируете, а не какой-то "я вот тут чуть-чуть изменил"

Всё тоже самое, только в строке rf95.recv(int(bn), 10);  10 заменил на 5 и всё

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Всё тоже самое, только в строке rf95.recv(int(bn), 10);  10 заменил на 5 и всё

блин, я и не заметил, у вас тут тоже бредятина.

вот так вот напишите (и цифра - именно 10)

rf95.recv((uint8_t*) bn, 10);

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

Нифига!... ))))))      тоже самое.... 

26

0

27

0

26

0

1

0

80

0

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

Я же говорю - перепробовал все варианты, и ваш в том числе - при присвоении перескакивает через элемент массива....

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbel620017 пишет:

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

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

b707 поставил Вам абсолютно точный диагноз: Вы путаете байты и двухбайтовые целые.

PS. Бросайте программирование - не Ваше это.

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 - выкладывайте код передатчика. Полностью.

кстати, передатчик на какой плате? и приемник?  Год назад это были две Мега, но там был другой проект.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbel620017 пишет:

Я же говорю - перепробовал все варианты, и ваш в том числе - при присвоении перескакивает через элемент массива....

Не нужно ничего пробовать - нужно писать сразу единственный правильный вариант.

 

PS. Говорят, если миллион обезьян посадить за пишущие машинки, то за 20 лет они смогут напечатать "Войну и мир". 

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

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

b707 пишет:

alexbel620017 - выкладывайте код передатчика. Полностью.

кстати, передатчик на какой плате? и приемник?  Год назад это были две Мега, но там был другой проект.

На DUE

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

На DUE

б**ть!!!!!!!!!!!! (простите)

На Дуе инты - 4 байта

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

Капец....... я не знал......

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Капец....... я не знал......

поэтому у вас и данные идут через один.

А приемник тоже на Дуе или все еще на Меге?

b707
Онлайн
Зарегистрирован: 26.05.2017

Короче, опишите и на приемнике и на передатчике массив данных одинаково -

на передатчике

uint32_t data[5]

на приемнике

uint32_t bn[5]

строчку приема опишите как

rf95.recv((uint8_t*) bn, sizeof(bn));

 

b707
Онлайн
Зарегистрирован: 26.05.2017

andriano пишет:

PS. Бросайте программирование - не Ваше это.

alexbel620017 - а ведь Андриано прав.

Писать огромные портянки кода, не выяснив за год даже размер типов данных на используемом контроллере... это ламерство.

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

И о чудо! - всё встало на свои места.......

Спасибо вам большое, b707!  Ейбогу не знал что инты в дуе другой размерности! Первый раз на ней что-то делал.  И температура перестала соскакивать на ноль ))))))

Спасибо!

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

b707 пишет:

andriano пишет:

PS. Бросайте программирование - не Ваше это.

alexbel620017 - а ведь Андриано прав.

Писать огромные портянки кода, не выяснив за год даже размер типов данных на используемом контроллере... это ламерство.

Да я и не претендую на хакера, так, для себя по-мелочи делаю и всё.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

alexbel620017 пишет:

На DUE

всегда поражаюсь. 

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

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

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

Но для начала пара комментариев, которые мне кажутся наиболее важными.

alexbel620017 пишет:

Так значения записывает программа, а не я. 

Стоп! Кто в доме хозяин? Программа ничего никуда не записывает. Всё делаете всегда Вы сами. То, что компилятор помогаем Вам в рутинных операциях - вовсе не означает, что он что-то делает. Он делат ровно то, что Вы ему сказали делать. Делаете всегда Вы сами. И Вы должны понимать каждый "чих". Если Вы не понимаете, что "он" делает, значит Вы потеряли контроль над ситуацией -  немедленно опускайтесь ниже и разбирайтесь что на самом деле происходит. Делаете всегда Вы, и Вы должны понимать что Вы делаете до последних мелких нюансов.

alexbel620017 пишет:

Капец....... я не знал......

Вы не поверите, но переходя на новый процессор или новый компилятор для старого процессора, я ВСЕГДА запускаю нечто вроде вот такого:

#include <Printing.h>

void setup(void) {
	Serial.begin(115200);
	printVar(sizeof(int));
	printVar(sizeof(long));
	printVar(sizeof(long long));
	printVar(sizeof(float));
	printVar(sizeof(double));
	printVar(sizeof(long double));
}

void loop(void) {}

например, на Нане это даёт вот такой результат (только что специально запустил):

sizeof(int)=2
sizeof(long)=4
sizeof(long long)=8
sizeof(float)=4
sizeof(double)=4
sizeof(long double)=4

после этого я точно знаю что у меня за типы.  Делайте тоже самое, заведите это привычкой. Вот сейчас запустите это на своей DUE и покажите нам результат (мне, кстати, очень интересно, т.к. я не знаю как там сделаны double).

Так, ну теперь к "полезностям". Я могу рассказать Вам про работы с памятью и типами данных так, как я рассказывал внуку. У него с тех пор проблем нет, потому я думаю, что это было понятно. Хотя, конечно, ничего нового я не скажу - откуда тут новое. Надо? Или Вы итак уже всё поняли, просто с DUE затык вышел?

b707
Онлайн
Зарегистрирован: 26.05.2017

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

Или Вы итак уже всё поняли, просто с DUE затык вышел?

Евгений, позволю себе опять влезть. Это не просто "затык с Дуе". Думаю тут все серьезно.

Почему мне так кажется? -Не заметить другой размер целого мог и более опытный программист. Но ни один даже самый начинающий - не стал бы решать проблему чтением шестого-десятого элементов из массива int bn[5]. Это дичь, очевидная даже школьнику, вчера прочитавшего про массивы. И любой школьник, хотя бы, догадался бы описать массив как int bn[10] :) - это был бы кривой костыль - но он решил бы все проблемы в коде ТС :)

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

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

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

Евгений, за это спасибо, обязательно буду иметь это в виду.

#include <Printing.h>

void setup(void) {
	Serial.begin(115200);
	printVar(sizeof(int));
	printVar(sizeof(long));
	printVar(sizeof(long long));
	printVar(sizeof(float));
	printVar(sizeof(double));
	printVar(sizeof(long double));
}

void loop(void) {}

А по поводу всего остального.... Господа Гуру, вы поймите, что я не ПРОГРАММИСТ. Этой хренью я занимаюсь чисто для себя. Я никогда не учился этим языкам (исключая Бэйсик в школе в 87-м году) и программированию. Моё образование, работа лежат совсем в другой сфере. Два года назад если бы меня спросили что такое С++ я бы сказал что это буква с двумя плюсами...   Я леплю маленькие проектики типа GSM сигналки в гараж, метеостанцию с выходом в НМ, часы с синхрой от GPS, инфосистема в котельную в частный дом и подобное для себя. Да, код не только кривой, но и, даже я вижу, очень не рациональный. И часто копирую код из примеров досконально не понимая как он работает.Занимаюсь я этим либо по ночам, либо в выходной. Времени у меня уходит на всё много. Проект годичной давности с последующим двух-трёх месячным прогоном я делал почти год - времени и знаний (по софту) не хватает. Напрасно вы так на меня нападаете, то что вам кажется элементарным может для другого человека оказаться не известным или не понятным. 

По поводу вчерашнего вопроса с размерностью на DUE - я не "просто скопировал" строчки, когда b707 сказал что размерность инта  в два раза больше всё сразу стало понятно - и про неприём, и захват чужой области памяти... Я не то что не знал этого нюанса, я даже предположить не мог что такая хрень может быть. Это надо просто знать. Я никогда не имел дело с армовскими процами. Эта DUE приехала мне из китая только пару недель назад. И тот код, который Евгений показал я мог бы и сам конечно написать, но я и предположить не мог что на разных платах может быть разная размерность одного типа данных.

Очень благодарен Евгению и b707 за помощь! 

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

Так, а как с моей просьбой? Мне правда интересно, как там на дуе.

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

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

Так, а как с моей просьбой? Мне правда интересно, как там на дуе.

С какой просьбой, Евгений?

Выложить код передатчика?

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

С какой просьбой, Евгений?

Выложить код передатчика?

запустить на Дуе код, который выводит размеры разных типов данных

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

Блин, чё-то не могу найти printing.h

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Блин, чё-то не могу найти printing.h

зачем? только не говорите, что вы этот код не можете переписать под обычный Serial.print()

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

Пардон, почти три ночи, мозги уже не те...

4

4

8

4

8

8

Теперь буду проверять все платы перед писаниной кода...

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

alexbel620017 пишет:

Блин, чё-то не могу найти printing.h

https://github.com/elilitko/ArduinoStuff/tree/master/Printing

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

Ещё.....  вопрос из прошлой жизни....

Вся эта хрень всё же зависает на работе какого-нибудь модуля SPI. Их три - W5500, SD карта и RA-01(LoRa). Все модули имеют питание 3,3 вольта, уровни, как пишут, "толерантны к пити вольтам". Но что бы сделать всё по-человечески на каждый модуль спаял переходную плату на 74HC125. Питание на неё беру с самого модуля - 3,3 в. Виснет (по меткам в программе) именно на работе W5500 или SD карты. Работать без зависания может от нескольких секунд до нескольких десятков минут.


andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbel620017 пишет:
Я не то что не знал этого нюанса, я даже предположить не мог что такая хрень может быть. Это надо просто знать.

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

Вообще-то для того, чтобы это знать, достаточно один раз прочитать любой учебник по Си.

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

andriano пишет:
один раз прочитать любой учебник по Си.

https://www.youtube.com/watch?v=aw10753OJyg

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[] = {0x2C, 0xF7, 0xF1, 0x08, 0x00, 0x9A};
IPAddress ip(192, 168, 1, 6);
EthernetServer server(756);

// ------------------------- LoRa ---------------------------------
RH_RF95 rf95(48, 2);                       // (SS, interrupt) внимательно с выводом прерывания на Ардуине!
uint32_t data[5];                                 // Создаём массив для приёма данных - 32 разряда, тк передатчик DUE

// ------------------------- часы ---------------------------------
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 swi = millis();              // перенная для смены фона на сайте ТМ данных
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 d9;                                  // давление системы отопления
int d81, d82, d91, d92;                    // промеж. параметры для отобр. гидро давления в СМС
int d10;                                   // темпеатура в котельной
int d11;                                   // темпеатура в гараже
int d12;                                   // темпеатура скважины
int d13;                                   // расход фильтра Мех.
int d14;                                   // расход фильтра Ca Mg.
int d15;                                    // расход фильтра Fe.
int d3, d4;                                // резерв
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() {
  SPI.begin;
  //SPI.setClockDivider(SPI_CLOCK_DIV16);

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

  pinMode(48, OUTPUT);                      // CS LoRa
  pinMode(49, OUTPUT);                      // CS W5500
  pinMode(47, OUTPUT);                      // CS SD
  pinMode(33, OUTPUT);                      // выход на WDT
  digitalWrite(47, HIGH);
  digitalWrite(48, HIGH);
  digitalWrite(49, HIGH);
  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();
  sensor.begin();                           // инициализация датчика давления
  sht31.begin(0x44);                        // инициализация датчика влажности
  SD.begin(47);                             // инициализация модуля SD карты
  rf95.init();                              // инициализация SX1278
  //rf95.setTxPower(5, false);                // мощность 5 - 23, максимальная мощность (при 23) 100мВт (шаги с 5 по 23 не подряд! смотреть в библиотеке)
  //void clearRxBuf();

  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);

  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

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

void loop() {
  //Serial.println("1");
  //Serial.println(millis());
  ttt++;
  if (ttt == 100) {
    //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:

  // -------------------------------------------- LoRa ------------------------------------------------------------

  Serial.println("1");
  if (rf95.available()) {
    delay(10);
    rf95.recv((uint8_t*)data, sizeof(data));
    if (data[0] + data[1] + data[2] + data[3] == data[4] && data[0] + data[1] + data[2] + data[3] != 0) {       // проверка на отсутствие 0 приёма и на соответствие CRC
      db1 = data[0];
      db2 = data[1];
      db3 = data[2];
      db4 = data[3];
      db5 = data[4];
      olddata = millis();
      fsd = true;
      BanTM = true;                         // есть данные из бани
    }
  }
  if (millis() - olddata > 60000 && fsd == true) {
    BanTM = false;                         // нет данных из бани
    fsd = false;
  }

  // -------------------------------------------------- SD карта ------------------------------------------------------------------------------

  Serial.println("2");
  
    //delay(10);
    //if ((millis() - registr) > treg && m % 5 == 0) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.

    if ((millis() - registr) > 10000) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.
    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 + "; Темп. вход " + celsius2 + "; Темп. гараж " + d11 + "; Темп. кот. " + d10 + "; Темп. скв. " + d12 + ";";
    //Serial.println(logStringData);
    String DirectName = "20" + String(Y) + "/" + String(M);                // Создаём имя папки из месяца и года
    String logStringName = DirectName + "/" + String(d) + ".txt";          // формируем текстовый файл на один день максимум 12 знаков в названии файла
    //Serial.println (logStringName);
    if (SD.begin(47)) {
      if (SD.mkdir(DirectName)) {                                            // создаём на SD указанную территорию, может включать в себя вложенные папки, разделенные прямым слешем "/"
        // Открываем файл, Если файла с таким именем не будет, ардуино создаст его.
        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("3");
  d9 = 16;                 // для отработки
  d8 = 32;
  html();
  //Serial.println("4");

  // -------------------------------------------------- ОСНОВНОЙ ЦИКЛ ------------------------------------------------
  // --------------------------------------- влажность и температура с датчика влажности -----------------------------
  //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 мин.


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


  // ------------------------------------------------- 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("9122234744") > -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("page0.tm5.en", 0);           // остановили таймеры мигания "АВАРИИ" на дисплее
          SendDataP("page0.tm6.en", 0);
          SendDataP("page0.p0.pic", 10);          // опять нарисовали "БАНЬКУ"
          fa = true;                           // разрешили вновь сработку тревоги  tm1.en=0
          digitalWrite(62, HIGH);              // аппаратный RESET
          delay(500);
        }
        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:

  //----------------------------------------------- работа  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) > 10000) {
    sms(String("AVARIY OTOPLENIY!"), String("+79122230000"));
    EEPROM.write(10, 1);                                                       // записали аварию в память
    delay(5);
    SendDataP("page0.tm5.en", 1);                                              // запустили таймеры "АВАРИИ" на Nextion
    frchtd = true;                                                             // флаг разрешения чтения с дисплея "сброс аварии"
    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;                              // разовый период вывода на дисплей
      delay(100);                            // таймер пиканья на Nextion не даёт очистить знакоместо - ждём пока пикнет Nextion
      nadisplei = millis();
      SendDataP("q0.picc", 11);               // очистка места температуры при переключении страницы
    }
    fscht = false;                              // закончили и опять разрешили счёт четырёх первых байт с дисплея
    if (frchtd) {                               // разрешение сброса тревоги с дисплея
      if ((val == 196 || val == 148) && 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("pio5", 0);                   // заткнули пищалку
        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);
    }
  }
}

//=================================== Пишем страницу html ============================================

void html()
{
  EthernetClient client = server.available();
  if (client) {
    //Serial.println("00");
    float d8p = d8;                                     // промежуточная переменная для индикации давления
    d8p = d8p / 10;
    float d9p = d9;                                     // промежуточная переменная для индикации давления
    d9p = d9p / 10;
    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");                      // обновление страницы через 60 сек
    client.println();
    //Serial.println("11");
    client.println("<!DOCTYPE HTML>");
    client.println("<html>");  //---------------------- Пишем страницу -------------
    client.println("<head>");
    client.println("<meta charset=\"UTF-8\">");         // Установка кодировки
    client.println("<title>п.Залесье, ул.Осенняя, д.00</title>");
    //Serial.println("22");
    client.println("</head>");
    if (millis() - swi < 60000) {         //1800000 3600000 5400000 7200000 9000000 10800000 12600000 14400000
      client.println("<body background=https://wmpics.pics/di-TW62.jpg><font color=\"WHITE\">"); // из мурманска в Питер
    }
    if (millis() - swi > 60000 && millis() - swi < 120000) {
      client.println("<body background=https://wmpics.pics/di-EAI35.jpg><font color=\"WHITE\">"); // разлив Ишима
    }
    if (millis() - swi > 120000 && millis() - swi < 180000) {
      client.println("<body background=https://wmpics.pics/di-M3D9.jpg><font color=\"WHITE\">"); // полуостров ночью
    }
    if (millis() - swi > 180000 && millis() - swi < 240000) {
      client.println("<body background=https://wmpics.pics/di-7QFR2.jpg><font color=\"BLACK\">"); // Санрайз 2
    }
    if (millis() - swi > 240000 && millis() - swi < 300000) {
      client.println("<body background=https://wmpics.pics/di-5QQV.jpg><font color=\"WHITE\">"); // Санрайз
    }
    if (millis() - swi > 300000 && millis() - swi < 360000) {
      client.println("<body background=https://wmpics.pics/di-T3D0.jpg><font color=\"WHITE\">"); // в открытом море
    }
    if (millis() - swi > 360000 && millis() - swi < 420000) {
      client.println("<body background=https://wmpics.pics/di-9GCF.jpg><font color=\"WHITE\">"); // колокольня в Калязине
    }
    if (millis() - swi > 420000 && millis() - swi < 480000) {
      client.println("<body background=https://wmpics.pics/di-I4U1.jpg>");         // ромашковое поле
    }
    if (millis() - swi > 480000) {
      swi = millis();
    }
    //Serial.println("23");
    //client.println("<blockquote>");

    client.println("<div style=\"position: absolute; top: 42px; left: 90px\">");   // блок Котельная
    client.println("<h1>Котельная:</h1>");
    client.println("<h2>Котёл подача:  ");    client.println(d1);    client.println("&deg;");    client.println("<br />");
    client.println("Котёл возврат: ");    client.println(d2);    client.println("&deg;");    client.println("<br />");
    client.println("Тёплый пол подача:");    client.println(d5);    client.println("<br />");
    client.println("Тёплый пол возврат:");    client.println(d6);    client.println("&deg;");    client.println("<br />");
    client.println("Бойлер:");    client.println(d7);    client.println("&deg;");    client.println("<br />");
    client.println("Давление отопления:");    client.println(d9p);    client.println("Bar.");    client.println("<br />");
    client.println("Давление водоснабж.:");    client.println(d8p);    client.println("Bar.");    client.println("<br />");
    client.println("</h2></div>");

    client.println("<div style=\"position: absolute; top: 42px; left: 500px\">");   // блок Температурные параметры
    client.println("<h1>Температурные параметры:</h1>");
    client.println("<h2>Температура на улице:  "); client.println(toutside); client.println("&deg;"); client.println("<br />");
    client.println("Влажность: "); client.println(hum); client.println("&#37;"); client.println("<br />");
    client.println("Атмосф. давление:"); client.println(p); client.println("мм.рт.ст."); client.println("<br /><br />");
    client.println("Дом:"); client.println(celsius1); client.println("&deg;"); client.println("<br />");
    client.println("Вход:"); client.println(celsius2); client.println("&deg;"); client.println("<br />");
    client.println("Гараж:"); client.println(d11); client.println("&deg;"); client.println("<br />");
    client.println("Котельная:"); client.println(d10); client.println("&deg;"); client.println("<br />");
    client.println("Скважина:"); client.println(d12); client.println("&deg;"); client.println("</div>");

    client.println("<div style=\"position: absolute; top: 42px; left: 980px\">");   // блок Баня
    client.println("<h1>Баня:</h1>");
    if (BanTM) {
      client.println("<h2>Парная:  "); client.println(db1); client.println("&deg;"); client.println("<br />");
      client.println("Комната: "); client.println(db2); client.println("&deg;"); client.println("<br />");
      client.println("Тёплый пол:"); client.println(db3); client.println("&deg;"); client.println("<br />");
      if (db4 != 0) {
        client.println("<p><font color=\"red\">Нагрев включен</font></p>");
      }
      else {
        client.println("<br />Нагрев выключен");
      }
    }
    else {
      client.println("<h2>Нет данных</h2>");
    }
    client.println("</div>");

    client.println("<div style=\"position: absolute; top: 42px; left: 1230px\">");   // блок Расход фильтров
    client.println("<h1>Фильтры:</h1>");
    client.println("<h2>Мех.:  "); client.println("&nbsp;&nbsp;&nbsp;&nbsp;"); client.println(d12); client.println("&#37;"); client.println("<br />");
    client.println("Ca Mg: "); client.println("&nbsp;"); client.println(d14); client.println("&#37;"); client.println("<br />");
    client.println("Fe:"); client.println("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"); client.println(d15); client.println("&#37;"); client.println("<br />");
    client.println("</div>");
    if (frchtd) {
      client.println("<div style=\"position: absolute; top: 420px; left: 400px\">");   // Авария
      client.println("<h1><p><blink><font color=\"red\">АВАРИЯ! АВАРИЯ! АВАРИЯ! АВАРИЯ! АВАРИЯ!</font></blink></p></h1>"); client.println("</div>");
    }
    client.println("</html>"); //------------------------- Закончили страницу -------------------------------
    //Serial.println("33");
    delay(500);
    client.stop();
    //Serial.println("44");
    Serial.println(millis());

  }
}

b707
Онлайн
Зарегистрирован: 26.05.2017

а без буферов они не работают, что ли?

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

Нет, конфликт по MISO идёт. Ну и для согласования уровней.

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Нет, конфликт по MISO идёт. Ну и для согласования уровней.

если честно, Алекс, после прошлой темы я уверен, что вы опять где-то накосячили. Но копаться в вашем коде... увольте

У меня три девайса SPI без проблем работали одновременно без всяких буферов

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

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

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

Вот код, где отключено почти всё кроме обращения к трём модулям SPI. Всё равно виснет....

По одному работают нормально, два или три  - виснет через несколько секунд или минут. Виснет на любом модуле, не на каком-то одном. Не понятно почему не сразу. Был бы аппаратный конфликт не работало бы вообще, а так - не ясно. 

Может не успевает отключиться предыдущий модуль? 

Проверял свободную память - 1607 байт свободно. Софт или железо всё-таки?...

Плата МЕГА 2560

#include <SD.h>

// при окончательной установке убрать коммент. "аварию отоления"  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 <iarduino_Pressure_BMP.h>

// ------------------------- сеть ---------------------------------
byte mac[] = {0x2C, 0xF7, 0xF1, 0x08, 0x00, 0x9A};
IPAddress ip(192, 168, 1, 6);
EthernetServer server(756);

// ------------------------- LoRa ---------------------------------
RH_RF95 rf95(48, 2);                       // (SS, interrupt) внимательно с выводом прерывания на Ардуине!
uint32_t data[5];                                 // Создаём массив для приёма данных - 32 разряда, тк передатчик DUE

// ------------------------- часы ---------------------------------
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 swi = millis();              // перенная для смены фона на сайте ТМ данных
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 d9;                                  // давление системы отопления
int d81, d82, d91, d92;                    // промеж. параметры для отобр. гидро давления в СМС
int d10;                                   // темпеатура в котельной
int d11;                                   // темпеатура в гараже
int d12;                                   // темпеатура скважины
int d13;                                   // расход фильтра Мех.
int d14;                                   // расход фильтра Ca Mg.
int d15;                                    // расход фильтра Fe.
int d3, d4;                                // резерв
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 LoRa
  pinMode(49, OUTPUT);                      // CS W5500
  pinMode(47, OUTPUT);                      // CS SD
  pinMode(53, OUTPUT);                      // штатный CS не используется, но надо определить его
  pinMode(33, OUTPUT);                      // выход на WDT
  digitalWrite(47, HIGH);
  digitalWrite(48, HIGH);
  digitalWrite(49, HIGH);
  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;                         // запретили чтение с дисплея "сброса"
  }

  SPI.begin;
  SPI.setClockDivider(SPI_CLOCK_DIV4);

  Ethernet.begin(mac, ip);
  server.begin();
  sensor.begin();                           // инициализация датчика давления
  sht31.begin(0x44);                        // инициализация датчика влажности
  SD.begin(47);                             // инициализация модуля SD карты
  rf95.init();                              // инициализация SX1278
  //rf95.setTxPower(5, false);                // мощность 5 - 23, максимальная мощность (при 23) 100мВт (шаги с 5 по 23 не подряд! смотреть в библиотеке)
  //void clearRxBuf();

  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);

  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

// ==========================================================================================================================
// ============================================================ 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:
*/
  // -------------------------------------------- LoRa ------------------------------------------------------------

  Serial.println("1");
  if (rf95.available()) {
    rf95.recv((uint8_t*)data, sizeof(data));
    if (data[0] + data[1] + data[2] + data[3] == data[4] && data[0] + data[1] + data[2] + data[3] != 0) {       // проверка на отсутствие 0 приёма и на соответствие CRC
      db1 = data[0];
      db2 = data[1];
      db3 = data[2];
      db4 = data[3];
      db5 = data[4];
      olddata = millis();
      fsd = true;
      BanTM = true;                         // есть данные из бани
    }
  }
  if (millis() - olddata > 60000 && fsd == true) {
    BanTM = false;                         // нет данных из бани
    fsd = false;
  }

  // -------------------------------------------------- SD карта ------------------------------------------------------------------------------

  Serial.println("2");
  //delay(10);
  SDcard();

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

  Serial.println("3");
  d9 = 16;                 // для отработки
  d8 = 38;
  html();
  Serial.println("4");
/*
  // -------------------------------------------------- ОСНОВНОЙ ЦИКЛ ------------------------------------------------
  // --------------------------------------- влажность и температура с датчика влажности -----------------------------
  //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(100);
    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 мин.

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


  // ------------------------------------------------- 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("9122234744") > -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("page0.tm5.en", 0);           // остановили таймеры мигания "АВАРИИ" на дисплее
          SendDataP("page0.tm6.en", 0);
          SendDataP("page0.p0.pic", 10);          // опять нарисовали "БАНЬКУ"
          fa = true;                           // разрешили вновь сработку тревоги  tm1.en=0
          digitalWrite(62, HIGH);              // аппаратный RESET
          delay(500);
        }
        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:

  //----------------------------------------------- работа  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) > 10000) {
    sms(String("AVARIY OTOPLENIY!"), String("+79122230000"));
    EEPROM.write(10, 1);                                                       // записали аварию в память
    delay(5);
    SendDataP("page0.tm5.en", 1);                                              // запустили таймеры "АВАРИИ" на Nextion
    frchtd = true;                                                             // флаг разрешения чтения с дисплея "сброс аварии"
    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;                              // разовый период вывода на дисплей
      delay(100);                            // таймер пиканья на Nextion не даёт очистить знакоместо - ждём пока пикнет Nextion
      nadisplei = millis();
      SendDataP("q0.picc", 11);               // очистка места температуры при переключении страницы
    }
    fscht = false;                              // закончили и опять разрешили счёт четырёх первых байт с дисплея
    if (frchtd) {                               // разрешение сброса тревоги с дисплея
      if ((val == 196 || val == 148) && 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("pio5", 0);                   // заткнули пищалку
        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);
    }
  }
}
*/
//=================================== Пишем страницу html ============================================

void html()
{
  EthernetClient client = server.available();
  if (client) {
    float d8p = d8;                                     // промежуточная переменная для индикации давления
    d8p = d8p / 10;
    float d9p = d9;                                     // промежуточная переменная для индикации давления
    d9p = d9p / 10;
    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");                      // обновление страницы через 60 сек
    client.println();
    client.println("<!DOCTYPE HTML>");
    client.println("<html>");  //------------------------------------- Пишем страницу ------------------------------------
    client.println("<head>");
    client.println("<meta charset=\"UTF-8\">");         // Установка кодировки
    client.println("<title>п.Залесье, ул.Осенняя, д.00</title>");
    client.println("</head>");
    if (millis() - swi < 60000) {         //1800000 3600000 5400000 7200000 9000000 10800000 12600000 14400000
      client.println("<body background=https://wmpics.pics/di-TW62.jpg><font color=\"WHITE\">"); // из мурманска в Питер
    }
    if (millis() - swi > 60000 && millis() - swi < 120000) {
      client.println("<body background=https://wmpics.pics/di-EAI35.jpg><font color=\"WHITE\">"); // разлив Ишима
    }
    if (millis() - swi > 120000 && millis() - swi < 180000) {
      client.println("<body background=https://wmpics.pics/di-M3D9.jpg><font color=\"WHITE\">"); // полуостров ночью
    }
    if (millis() - swi > 180000 && millis() - swi < 240000) {
      client.println("<body background=https://wmpics.pics/di-7QFR2.jpg><font color=\"BLACK\">"); // Санрайз 2
    }
    if (millis() - swi > 240000 && millis() - swi < 300000) {
      client.println("<body background=https://wmpics.pics/di-5QQV.jpg><font color=\"WHITE\">"); // Санрайз
    }
    if (millis() - swi > 300000 && millis() - swi < 360000) {
      client.println("<body background=https://wmpics.pics/di-T3D0.jpg><font color=\"WHITE\">"); // в открытом море
    }
    if (millis() - swi > 360000 && millis() - swi < 420000) {
      client.println("<body background=https://wmpics.pics/di-9GCF.jpg><font color=\"WHITE\">"); // колокольня в Калязине
    }
    if (millis() - swi > 420000 && millis() - swi < 480000) {
      client.println("<body background=https://wmpics.pics/di-I4U1.jpg>");         // ромашковое поле
    }
    if (millis() - swi > 480000) {
      swi = millis();
    }
    //Serial.println("23");
    //client.println("<blockquote>");

    client.println("<div style=\"position: absolute; top: 42px; left: 90px\">");   // блок Котельная
    client.println("<h1>Котельная:</h1>");
    client.println("<h2>Котёл подача:  ");    client.println(d1);    client.println("&deg;");    client.println("<br />");
    client.println("Котёл возврат: ");    client.println(d2);    client.println("&deg;");    client.println("<br />");
    client.println("Тёплый пол подача:");    client.println(d5);    client.println("<br />");
    client.println("Тёплый пол возврат:");    client.println(d6);    client.println("&deg;");    client.println("<br />");
    client.println("Бойлер:");    client.println(d7);    client.println("&deg;");    client.println("<br />");
    client.println("Давление отопления:");    client.println(d9p);    client.println("Bar.");    client.println("<br />");
    client.println("Давление водоснабж.:");    client.println(d8p);    client.println("Bar.");    client.println("<br />");
    client.println("</h2></div>");

    client.println("<div style=\"position: absolute; top: 42px; left: 500px\">");   // блок Температурные параметры
    client.println("<h1>Температурные параметры:</h1>");
    client.println("<h2>Температура на улице:  "); client.println(toutside); client.println("&deg;"); client.println("<br />");
    client.println("Влажность: "); client.println(hum); client.println("&#37;"); client.println("<br />");
    client.println("Атмосф. давление:"); client.println(p); client.println("мм.рт.ст."); client.println("<br /><br />");
    client.println("Дом:"); client.println(celsius1); client.println("&deg;"); client.println("<br />");
    client.println("Вход:"); client.println(celsius2); client.println("&deg;"); client.println("<br />");
    client.println("Гараж:"); client.println(d11); client.println("&deg;"); client.println("<br />");
    client.println("Котельная:"); client.println(d10); client.println("&deg;"); client.println("<br />");
    client.println("Скважина:"); client.println(d12); client.println("&deg;"); client.println("</div>");

    client.println("<div style=\"position: absolute; top: 42px; left: 980px\">");   // блок Баня
    client.println("<h1>Баня:</h1>");
    if (BanTM) {
      client.println("<h2>Парная:  "); client.println(db1); client.println("&deg;"); client.println("<br />");
      client.println("Комната: "); client.println(db2); client.println("&deg;"); client.println("<br />");
      client.println("Тёплый пол:"); client.println(db3); client.println("&deg;"); client.println("<br />");
      if (db4 != 0) {
        client.println("<p><font color=\"red\">Нагрев включен</font></p>");
      }
      else {
        client.println("<br />Нагрев выключен");
      }
    }
    else {
      client.println("<h2>Нет данных</h2>");
    }
    client.println("</div>");

    client.println("<div style=\"position: absolute; top: 42px; left: 1230px\">");   // блок Расход фильтров
    client.println("<h1>Фильтры:</h1>");
    client.println("<h2>Мех.:  "); client.println("&nbsp;&nbsp;&nbsp;&nbsp;"); client.println(d12); client.println("&#37;"); client.println("<br />");
    client.println("Ca Mg: "); client.println("&nbsp;"); client.println(d14); client.println("&#37;"); client.println("<br />");
    client.println("Fe:"); client.println("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"); client.println(d15); client.println("&#37;"); client.println("<br />");
    client.println("</div>");
    if (frchtd) {
      client.println("<div style=\"position: absolute; top: 420px; left: 400px\">");   // Авария
      client.println("<h1><p><blink><font color=\"red\">АВАРИЯ! АВАРИЯ! АВАРИЯ! АВАРИЯ! АВАРИЯ!</font></blink></p></h1>"); client.println("</div>");
    }
    client.println("</html>"); //------------------------- Закончили страницу -------------------------------
    delay(50);
    client.stop();
    Serial.println(millis());
  }
}
// -------------------------------------------------- SD карта ------------------------------------------------------------------------------

void SDcard()
{
  //delay(10);
  //if ((millis() - registr) > treg && m % 5 == 0) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.

  if ((millis() - registr) > 10000) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.
    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 + "; Темп. вход " + celsius2 + "; Темп. гараж " + d11 + "; Темп. кот. " + d10 + "; Темп. скв. " + d12 + ";";
    //Serial.println(logStringData);
    String DirectName = "20" + String(Y) + "/" + String(M);                // Создаём имя папки из месяца и года
    String logStringName = DirectName + "/" + String(d) + ".txt";          // формируем текстовый файл на один день максимум 12 знаков в названии файла
    //Serial.println (logStringName);
    if (SD.begin(47)) {
      if (SD.mkdir(DirectName)) {                                            // создаём на SD указанную территорию, может включать в себя вложенные папки, разделенные прямым слешем "/"
        // Открываем файл, Если файла с таким именем не будет, ардуино создаст его.
        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();
      }
    }
  }
}

 

b707
Онлайн
Зарегистрирован: 26.05.2017

Алекс, а что, реально в строчках 785, 788, 791 и тд - кавычки в строках не экранированы? - или это криво вставилось? ... хотя нет, например в строке 814 все нормально

Который раз поражаюсь, как у вас вообще хоть что-то запускается...

Ну и еще - вы про макрос F() вообще не в курсе? - У Меги куча флеш памяти, но довольно мало оперативки, все константные строки в выводе стоило бы положить во флеш - наверно килобайт а то и пару выиграете

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

А чему там не запускаться?

Про макрос слышал, но как-то не сподобился применять его раньше.... 

Мне бы про зависания прояснить как-то.  То ли переполнение где-то идёт, то ли потенциал накапливается....

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

Почитал ваши сообщения в других постах по поводу макроса - переделаю у себя.

b707
Онлайн
Зарегистрирован: 26.05.2017

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

alexbel620017
Offline
Зарегистрирован: 26.03.2017
client.println(F("<body background=https://wmpics.pics/di-TW62.jpg><font color=\"WHITE\">")); // из мурманска в Питер
    }
Вот реальная строка из кода, не прикрытых кавычек нет
alexbel620017
Offline
Зарегистрирован: 26.03.2017
#include <SD.h>

// при окончательной установке убрать коммент. "аварию отоления"  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 <iarduino_Pressure_BMP.h>

// ------------------------- сеть ---------------------------------
byte mac[] = {0x2C, 0xF7, 0xF1, 0x08, 0x00, 0x9A};
IPAddress ip(192, 168, 1, 6);
EthernetServer server(756);

// ------------------------- LoRa ---------------------------------
RH_RF95 rf95(48, 2);                       // (SS, interrupt) внимательно с выводом прерывания на Ардуине!
uint32_t data[5];                                 // Создаём массив для приёма данных - 32 разряда, тк передатчик DUE

// ------------------------- часы ---------------------------------
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 swi = millis();              // перенная для смены фона на сайте ТМ данных
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 d9;                                  // давление системы отопления
int d81, d82, d91, d92;                    // промеж. параметры для отобр. гидро давления в СМС
int d10;                                   // темпеатура в котельной
int d11;                                   // темпеатура в гараже
int d12;                                   // темпеатура скважины
int d13;                                   // расход фильтра Мех.
int d14;                                   // расход фильтра Ca Mg.
int d15;                                    // расход фильтра Fe.
int d3, d4;                                // резерв
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 LoRa
  pinMode(49, OUTPUT);                      // CS W5500
  pinMode(47, OUTPUT);                      // CS SD
  pinMode(53, OUTPUT);                      // штатный CS не используется, но надо определить его
  pinMode(33, OUTPUT);                      // выход на WDT
  pinMode(66, OUTPUT);
  //pinMode(67, OUTPUT);
  //pinMode(68, OUTPUT);
  //pinMode(69, OUTPUT);
  digitalWrite(47, HIGH);
  digitalWrite(48, HIGH);
  digitalWrite(49, HIGH);
  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;                         // запретили чтение с дисплея "сброса"
  }

  SPI.begin;
  SPI.setClockDivider(SPI_CLOCK_DIV4);

  Ethernet.begin(mac, ip);
  server.begin();
  sensor.begin();                           // инициализация датчика давления
  sht31.begin(0x44);                        // инициализация датчика влажности
  SD.begin(47);                             // инициализация модуля SD карты
  rf95.init();                              // инициализация SX1278
  //rf95.setTxPower(5, false);                // мощность 5 - 23, максимальная мощность (при 23) 100мВт (шаги с 5 по 23 не подряд! смотреть в библиотеке)
  //void clearRxBuf();

  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);

  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

// ==========================================================================================================================
// ============================================================ 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:
  */
  // -------------------------------------------- LoRa ------------------------------------------------------------

  Serial.println("1");
  delay(10);
  if (rf95.available()) {
    rf95.recv((uint8_t*)data, sizeof(data));
    if (data[0] + data[1] + data[2] + data[3] == data[4] && data[0] + data[1] + data[2] + data[3] != 0) {       // проверка на отсутствие 0 приёма и на соответствие CRC
      db1 = data[0];
      db2 = data[1];
      db3 = data[2];
      db4 = data[3];
      db5 = data[4];
      olddata = millis();
      fsd = true;
      BanTM = true;                         // есть данные из бани
    }
  }
  if (millis() - olddata > 60000 && fsd == true) {
    BanTM = false;                         // нет данных из бани
    fsd = false;
  }

  // -------------------------------------------------- SD карта ------------------------------------------------------------------------------


  Serial.println("2");
  delay(10);
  //SDcard();

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

  Serial.println("3");
  d9 = 16;                 // для отработки
  d8 = 38;
  delay(10);
  html();
  Serial.println("4");
  
    // -------------------------------------------------- ОСНОВНОЙ ЦИКЛ ------------------------------------------------
    // --------------------------------------- влажность и температура с датчика влажности -----------------------------
    //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(100);
      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 мин.

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


    // ------------------------------------------------- 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("9122234744") > -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("page0.tm5.en", 0);           // остановили таймеры мигания "АВАРИИ" на дисплее
            SendDataP("page0.tm6.en", 0);
            SendDataP("page0.p0.pic", 10);          // опять нарисовали "БАНЬКУ"
            fa = true;                           // разрешили вновь сработку тревоги  tm1.en=0
            digitalWrite(62, HIGH);              // аппаратный RESET
            delay(500);
          }
          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:

    //----------------------------------------------- работа  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) > 10000) {
      sms(String("AVARIY OTOPLENIY!"), String("+79122230000"));
      EEPROM.write(10, 1);                                                       // записали аварию в память
      delay(5);
      SendDataP("page0.tm5.en", 1);                                              // запустили таймеры "АВАРИИ" на Nextion
      frchtd = true;                                                             // флаг разрешения чтения с дисплея "сброс аварии"
      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;                              // разовый период вывода на дисплей
        delay(100);                            // таймер пиканья на Nextion не даёт очистить знакоместо - ждём пока пикнет Nextion
        nadisplei = millis();
        SendDataP("q0.picc", 11);               // очистка места температуры при переключении страницы
      }
      fscht = false;                              // закончили и опять разрешили счёт четырёх первых байт с дисплея
      if (frchtd) {                               // разрешение сброса тревоги с дисплея
        if ((val == 196 || val == 148) && 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("pio5", 0);                   // заткнули пищалку
          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);
    }
  }
  }
*/
//=================================== Пишем страницу html ============================================

void html()
{
  EthernetClient client = server.available();
  if (client) {
    float d8p = d8;                                     // промежуточная переменная для индикации давления
    d8p = d8p / 10;
    float d9p = d9;                                     // промежуточная переменная для индикации давления
    d9p = d9p / 10;
    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");                      // обновление страницы через 60 сек
    client.println();
    client.println("<!DOCTYPE HTML>");
    client.println("<html>");  //------------------------------------- Пишем страницу ------------------------------------
    client.println("<head>");
    client.println(F("<meta charset=\"UTF-8\">"));         // Установка кодировки
    client.println(F("<title>п.Залесье, ул.Осенняя, д.00</title>"));
    client.println("</head>");
    
    if (millis() - swi < 60000) {         //1800000 3600000 5400000 7200000 9000000 10800000 12600000 14400000
      client.println(F("<body background=https://wmpics.pics/di-TW62.jpg><font color=\"WHITE\">")); // из мурманска в Питер
    }
    if (millis() - swi > 60000 && millis() - swi < 120000) {
      client.println(F("<body background=https://wmpics.pics/di-EAI35.jpg><font color=\"WHITE\">")); // разлив Ишима
    }
    if (millis() - swi > 120000 && millis() - swi < 180000) {
      client.println(F("<body background=https://wmpics.pics/di-M3D9.jpg><font color=\"WHITE\">")); // полуостров ночью
    }
    if (millis() - swi > 180000 && millis() - swi < 240000) {
      client.println(F("<body background=https://wmpics.pics/di-7QFR2.jpg><font color=\"WHITE\">")); // Санрайз 2
    }
    if (millis() - swi > 240000 && millis() - swi < 300000) {
      client.println(F("<body background=https://wmpics.pics/di-5QQV.jpg><font color=\"WHITE\">")); // Санрайз
    }
    if (millis() - swi > 300000 && millis() - swi < 360000) {
      client.println(F("<body background=https://wmpics.pics/di-T3D0.jpg><font color=\"WHITE\">")); // в открытом море
    }
    if (millis() - swi > 360000 && millis() - swi < 420000) {
      client.println(F("<body background=https://wmpics.pics/di-9GCF.jpg><font color=\"WHITE\">")); // колокольня в Калязине
    }
    if (millis() - swi > 420000 && millis() - swi < 480000) {
      client.println(F("<body background=https://wmpics.pics/di-I4U1.jpg>"));         // ромашковое поле
    }
    if (millis() - swi > 480000) {
      swi = millis();
    }
    //Serial.println("23");
    //client.println("<blockquote>");

    client.println(F("<div style=\"position: absolute; top: 42px; left: 90px\">"));   // блок Котельная
    client.println("<h1>Котельная:</h1>");
    client.println("<h2>Котёл подача:  ");    client.println(d1);    client.println("&deg;");    client.println("<br />");
    client.println("Котёл возврат: ");    client.println(d2);    client.println("&deg;");    client.println("<br />");
    client.println("Тёплый пол подача:");    client.println(d5);    client.println("<br />");
    client.println("Тёплый пол возврат:");    client.println(d6);    client.println("&deg;");    client.println("<br />");
    client.println("Бойлер:");    client.println(d7);    client.println("&deg;");    client.println("<br />");
    client.println("Давление отопления:");    client.println(d9p);    client.println("Bar.");    client.println("<br />");
    client.println("Давление водоснабж.:");    client.println(d8p);    client.println("Bar.");    client.println("<br />");
    client.println("</h2></div>");

    client.println(F("<div style=\"position: absolute; top: 42px; left: 500px\">"));   // блок Температурные параметры
    client.println("<h1>Температурные параметры:</h1>");
    client.println("<h2>Температура на улице:  "); client.println(toutside); client.println("&deg;"); client.println("<br />");
    client.println("Влажность: "); client.println(hum); client.println("&#37;"); client.println("<br />");
    client.println("Атмосф. давление:"); client.println(p); client.println("мм.рт.ст."); client.println("<br /><br />");
    client.println("Дом:"); client.println(celsius1); client.println("&deg;"); client.println("<br />");
    client.println("Вход:"); client.println(celsius2); client.println("&deg;"); client.println("<br />");
    client.println("Гараж:"); client.println(d11); client.println("&deg;"); client.println("<br />");
    client.println("Котельная:"); client.println(d10); client.println("&deg;"); client.println("<br />");
    client.println("Скважина:"); client.println(d12); client.println("&deg;"); client.println("</div>");

    client.println(F("<div style=\"position: absolute; top: 42px; left: 980px\">"));   // блок Баня
    client.println("<h1>Баня:</h1>");
    if (BanTM) {
      client.println("<h2>Парная:  "); client.println(db1); client.println("&deg;"); client.println("<br />");
      client.println("Комната: "); client.println(db2); client.println("&deg;"); client.println("<br />");
      client.println("Тёплый пол:"); client.println(db3); client.println("&deg;"); client.println("<br />");
      if (db4 != 0) {
        client.println(F("<p><font color=\"red\">Нагрев включен</font></p>"));
      }
      else {
        client.println("<br />Нагрев выключен");
      }
    }
    else {
      client.println("<h2>Нет данных</h2>");
    }
    client.println("</div>");

    client.println(F("<div style=\"position: absolute; top: 42px; left: 1230px\">"));   // блок Расход фильтров
    client.println("<h1>Фильтры:</h1>");
    client.println("<h2>Мех.:  "); client.println("&nbsp;&nbsp;&nbsp;&nbsp;"); client.println(d12); client.println("&#37;"); client.println("<br />");
    client.println("Ca Mg: "); client.println("&nbsp;"); client.println(d14); client.println("&#37;"); client.println("<br />");
    client.println("Fe:"); client.println("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"); client.println(d15); client.println("&#37;"); client.println("<br />");
    client.println("</div>");
    if (frchtd) {
      client.println(F("<div style=\"position: absolute; top: 420px; left: 400px\">"));   // Авария
      client.println(F("<h1><p><blink><font color=\"red\">АВАРИЯ! АВАРИЯ! АВАРИЯ! АВАРИЯ! АВАРИЯ!</font></blink></p></h1>")); client.println("</div>");
    }
    client.println("</html>"); //------------------------- Закончили страницу -------------------------------
    delay(50);
    
    client.stop();
    Serial.println(millis());
  }
}
// -------------------------------------------------- SD карта ------------------------------------------------------------------------------

void SDcard()
{
  //delay(10);
  //if ((millis() - registr) > treg && m % 5 == 0) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.

  if ((millis() - registr) > 10000) {                      // таймер для записи регистратора на 5 мин и кратно 5 мин.
    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 + "; Темп. вход " + celsius2 + "; Темп. гараж " + d11 + "; Темп. кот. " + d10 + "; Темп. скв. " + d12 + ";";
    //Serial.println(logStringData);
    String DirectName = "20" + String(Y) + "/" + String(M);                // Создаём имя папки из месяца и года
    String logStringName = DirectName + "/" + String(d) + ".txt";          // формируем текстовый файл на один день максимум 12 знаков в названии файла
    //Serial.println (logStringName);
    if (SD.begin(47)) {
      if (SD.mkdir(DirectName)) {                                            // создаём на SD указанную территорию, может включать в себя вложенные папки, разделенные прямым слешем "/"
        // Открываем файл, Если файла с таким именем не будет, ардуино создаст его.
        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();
      }
    }
  }
}

Сейчас вот так стоит, ещё раз скопировал весь код

alexbel620017
Offline
Зарегистрирован: 26.03.2017
if (millis() - swi > 60000 && millis() - swi < 120000) {
      client.println(F("<body background=https://wmpics.pics/di-EAI35.jpg><font color=\"WHITE\">")); // разлив Ишима
    }
    if (millis() - swi > 120000 && millis() - swi < 180000) {
      client.println(F("<body background=https://wmpics.pics/di-M3D9.jpg><font color=\"WHITE\">")); // полуостров ночью
    }
    if (millis() - swi > 180000 && millis() - swi < 240000) {
      client.println(F("<body background=https://wmpics.pics/di-7QFR2.jpg><font color=\"WHITE\">")); // Санрайз 2
    }
Вот так на самом деле стоит (часть строк скопировал)
alexbel620017
Offline
Зарегистрирован: 26.03.2017

Менял режимы, скорость SPI - не помогает....

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

Вот если честно - Вы ожидаете, что кто-то будет эти сотни строк у себя в голове прокручивать, чтобы понять, где стек пропарывает кучу?

b707
Онлайн
Зарегистрирован: 26.05.2017

alexbel620017 пишет:

Вот так на самом деле стоит (часть строк скопировал)

на самом деле в коде вот так, просто когда вы вставляете в форум, часть строки вырезается

client.println(F("<body background=<a href="https://wmpics.pics/di-TW62.jpg" rel="nofollow">https://wmpics.pics/di-TW62.jpg</a>><font color=\"WHITE\">")); // из мурманска в Питер

и тут просто дофига не прикрытых кавычек.

Нужно абсолютно все кавычки внутри строки оформить так, как записано "WHITE":

client.println(F("<font color=\"WHITE\">")); // из мурманска в Питер