Любой автомобильный, корабельный или иной промышленный датчик температуры масла или ОЖ - это всегда NTC в корпусе с резьбой. Промышленные единственно что отличаются на одно и двухвыводные для подключения в двигателях с землёй на корпусе и с изолированной землей (пароходики морские всякие).
У тех же E-Kits вы можете спокойно купить как дешманский китай, так и вполне оригинальные DS18B20
У них же компания SmartModule какупает их для сборки своих термодатчиков в готовом виде (сразу в гильзах герметичные и с фирменным же силиконовым термостойким кабелем).
По названиям контакты гуглятся без проблем.
В настоящее время появилась новая задача. Бьюсь над ней уже порядка 3 месяца, самостоятельно решить не могу. Обращаюсь к вам. Задача - выполнить автоматизацию теплового насоса. Тепловой насос воздух/вода, на базе б/у сплит системы. В общем то, система уже работает и показывает удовлетворительные результаты, но проблема в том, что не реже чем раз в сутки наступает критическая ошибка, приводящая к останову. По-моему, эта ошибка связана с датчиками температуры DS18B20 (но не факт).
Напишу, что может быть источником проблемы, на мой взгляд. Датчики температуры. Всего их пока что участвует 6 шт. Три из них - находятся в наружном блоке, в экстремальных условиях (температура измеряемой среды может меняться от -20 до +70 град. С за пару минут).
Сначала это была обычная витая пара. Длина от датчиков до контроллера примерно 5 м. Потом проложил новую витую пару, экранированную, по совету с форума две пары выделил - одна пара для питания, вторая для сигнал/земля. На конце линии конденсатор (электролит и керамика), подтягивающий резистор также на конце линии. Помех стало меньше, но полностью проблема не ушла.
В общем, - пока кратко и сумбурно. Если будут уточняющие вопросы - расскажу более развёрнуто.
так выглядит сегодняшняя ошибка на экране дисплея (шаг по горизонтали - один час, некорректное показание - улетевшее в район 50 град. С. После перетыка питания шины - пошло в линию)
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include <OneWire.h>
OneWire ds(21); // выбор пина ардуино, на котором висит шина 1-wire
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define WHITEGREY 0xC638
#define DARKGREY 0x7BEF
#define DARKGREEN 0x0C80
#define pinVoda_tick 18 //счетчик воды
boolean stateCheck_voda;
#define pinElectr_tick 19 //счетчик электричества
boolean stateCheck_electr;
uint8_t relay; //=b00000000 - для указания, в каком состоянии должны быть реле
//бит "0"-для управления (и отображения состояния) вентилятора наружного блока (on/off)
//бит "1"-для управления (и отображения состояния) 4-х ходовым клапаном наружного блока (on/off)
//бит "2"-для управления (и отображения состояния) компрессора наружного блока (on/off)
//бит "3"-для управления (и отображения состояния) насоса (on/off)
//адреса для датчиков температуры
//0xDB00000EB43A8C28, {0x28, 0x8C, 0x3A, 0xB4, 0xE, 0x0, 0x0, 0xDB} //1 (оригинал)
//0x3A00000076A76F28, {0x28, 0x6F, 0xA7, 0x76, 0x0, 0x0, 0x0, 0x3A} //2
//0xAB00000075289528, {0x28, 0x95, 0x28, 0x75, 0x0, 0x0, 0x0, 0xAB} //3
//0x2900000072CDFF28, {0x28, 0xFF, 0xCD, 0x72, 0x0, 0x0, 0x0, 0x29} //4
//0xF9000000739C4F28, {0x28, 0x4F, 0x9C, 0x73, 0x0, 0x0, 0x0, 0xF9} //5
//0xAC00000072FB2C28, {0x28, 0x2C, 0xFB, 0x72, 0x0, 0x0, 0x0, 0xAC} //6
//0x2D00000072D1FC28, {0x28, 0xFC, 0xD1, 0x72, 0x0, 0x0, 0x0, 0x2D} //7
//0x760000007697D528, {0x28, 0xD5, 0x97, 0x76, 0x0, 0x0, 0x0, 0x76} //8
//0x5F00000072E5EA28, {0x28, 0xEA, 0xE5, 0x72, 0x0, 0x0, 0x0, 0x5F} //9
//0x58000000768CEF28, {0x28, 0xEF, 0x8C, 0x76, 0x0, 0x0, 0x0, 0x58} //10
//0xC400000077899C28, {0x28, 0x9C, 0x89, 0x77, 0x0, 0x0, 0x0, 0xC4} //11
//массивы для графиков
uint8_t tIsparitel[320];
uint8_t tOverheat[320];
uint8_t tKompressor[320];
uint8_t tWaterIn[320];
uint8_t tWaterOut[320];
uint8_t tDefrost[320];
uint8_t heatPower[320];
uint8_t gWater[320];
uint8_t ElectrPow[320];
uint8_t COP[320];
//для отображения точных значений с датчиков
int16_t tOverheatReal;
int32_t gWaterReal;
int32_t heatPowerReal;
int32_t ElectrPowReal;
int32_t COPreal;
int32_t gWaterRealPrew;//для фиксирования предыдущего показания для отображения при сбоях
boolean FlagWater = false;//флаг для фиксирования сбоев показаний водомера
boolean FirstImpulsWater = false;//флаг для фиксирования первого импульса с водомера при начале вычисления реального расхода воды
boolean SecondImpulsWater = false;//флаг для фиксирования второго импульса с водомера при начале вычисления реального расхода воды
//для подсчёта тепла и электричества среднее арифметическое
int32_t countHeatAndElectr = 0;
int32_t countHeat = 0;
int32_t countElectr = 0;
//для чередования получения и вывода данных в основном коде
boolean Flag1 = true;
boolean Flag2 = true;
boolean Flag3 = true;
boolean Flag4 = true;
uint8_t countGetGrafic = 9;//для периодической смены по времени экрана с графиками
uint32_t Timer;//для отсчёта времени в цикле
int16_t trend_fan[20]; //массив для отображения графика работы вентилятора
int16_t trend_kompressor[20]; //массив для отображения графика работы компрессора
int16_t trend_pump[20]; //массив для отображения графика работы насоса
int16_t trend_4way_valve[20]; //массив для отображения графика работы четырёхходового клапана
//для водомера
uint32_t tmr;//для фиксации времени, для "антидребезга" контакта
boolean gWaterFlag = false;//флаг для водомера при срабатывании геркона
uint32_t WaterStartTimer;//засечка времени старта отсчёта времени для водомера
uint32_t WaterCountTimer;//сколько времени прошло между срабатываниями
//для электросчётчика
uint32_t tmr2;//для фиксации времени, для "антидребезга" контакта
boolean ElectrFlag = false; //флаг для электросчётчика при срабатывании
uint32_t ElectrStartTimer; //засечка времени старта отсчёта времени для электросчётчика
uint32_t ElectrCountTimer; //сколько времени прошло между срабатываниями
//для контроля режимов
//флаги начала режимов
boolean StartHeatFlag;//флаг для активации и окончания перехода в режим "нагрев"
boolean StopFlag;//флаг для перехода в режим "останов"
boolean HeatOptionFlag;//флаг о том что в работе режим "нагрев"
boolean HeatOptionPauseFlag;//режим приостанова нагрева
boolean DefrostOptionFlag; //флаг о начале работы режима Defrost
//счётчики для срабатывания
uint8_t tKompressorCounter = 0;//для подсчёта количества корректных замеров перед отключением и включением вентилятора при высокой температуре на выходе из компрессора
uint8_t HeatOptionCout = 0; //счётчик для смены режима на приостанов нагрева (когда прогрелась вода перед ППТО)
uint8_t HeatOptionPauseCout = 0; //счётчик для смены режима окончания приостанова нагрева
uint8_t defrostCount = 0; //счётчик для перехода в режим Defrost
uint8_t StopMaxTemp = 0; //счётчик для перехода в режим Stop при повышенной температуре компрессора
uint8_t StopMaxElectr = 0; //счётчик для перехода в режим Stop при повышенной электрической нагрузке
uint8_t StopMinTempHeater = 0; //счётчик для перехода в режим Stop при низкой температуре в точке Defrost
uint8_t StopNo4xvalve = 0; //счётчик для перехода в режим Stop при неправильном положении 4х ходового клапана в режиме нагрев
uint8_t StopNoElectric = 0; //счётчик для перехода в режим Stop при отсутствии электропитания наружного блока
uint8_t StopKind = 0; //указатель причины, почему произошёл останов
// 1 - малая температура в точке Defrost в режиме нагрева
// 2 - высокая температура на выходе компрессора
// 3 - большая потребляемая электрическая мощность
// 4 - малая температура в точке Defrost в режиме нагрева
// 5 - отключение электроэнергии
// 6 - поступили некорректные температуры
// 7 - нет расхода воды
// 8 - у контроллера отсутствует актуальный режим (все флаги режимов опущены)
uint8_t MistakeTemp[6] = {}; //массив для фиксации количества ошибок по температуре подряд
boolean getMistakeFlag = false;//флаг для начала отслеживания ошибок температур
//засекание времени
uint32_t HeatOptionPauseStartTime;//для отсчёта времени и прокрутки насоса в режиме паузы прогрева
uint32_t StartHeatTime;//для фиксации времени начала режима работы "нагрев"
uint32_t StopTime;//для фиксации времени останова
uint32_t DefrostTime;//для фиксации времени начала режима работы Defrost
//переменные температур, изначально ставим 0*С
int16_t Temper[6] =
{
0, //KompressorC 0
0, //WaterInC 1
0, //WaterOutC 2
0, //temp3C 3
0, //DefrostC 4
0 //IsparitelC 5
};
//для выявления ошибок температур
int16_t TemperPrev[6];//предыдущее показание температуры
//соответствие адресов датчиков определённым температурам
byte ADDR_DS18B20 [6][8] =
{
{0x28, 0xD5, 0x97, 0x76, 0x0, 0x0, 0x0, 0x76}, //KompressorC 0
{0x28, 0x4F, 0x9C, 0x73, 0x0, 0x0, 0x0, 0xF9}, //WaterInC 1
{0x28, 0xFC, 0xD1, 0x72, 0x0, 0x0, 0x0, 0x2D}, //WaterOutC 2
{0x28, 0x95, 0x28, 0x75, 0x0, 0x0, 0x0, 0xAB}, //temp3C 3
{0x28, 0xEF, 0x8C, 0x76, 0x0, 0x0, 0x0, 0x58}, //DefrostC 4
{0x28, 0x8C, 0x3A, 0xB4, 0xE, 0x0, 0x0, 0xDB} //IsparitelC 5
};
//функция сброса шины с датчиками температуры
void resetTemp()
{
ds.reset();
ds.write(0xCC); //Обращение ко всем датчикам
ds.write(0x44); //Команда на конвертацию
}
//функция считывания значения температуры с датчиков по шине
void gettingTemp()
{
uint8_t i;
int16_t temp;
for (i = 0; i < 6; i++) //Перебор количества датчиков
{
ds.reset();
ds.select(ADDR_DS18B20[i]);
ds.write(0xBE); //Считывание значения с датчика
temp = (ds.read() | ds.read() << 8); //Принимаем два байта температуры
Temper[i] = (temp * 10) >> 4; //целое в десятых *C (214=>21,4*C)
}
}
//функция для выявления некорректных значений с датчиков температуры
void tempMistake (uint8_t a, int16_t b, int16_t c, uint8_t d) //номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение
{
if (Temper[a] >= b and Temper[a] <= c and abs(Temper[a] - TemperPrev[a]) <= d)//если нормальное значение температуры
{
TemperPrev[a] = Temper[a];
if (MistakeTemp[a] <= 6)
MistakeTemp[a] = 0;
}
else if (MistakeTemp[a] > 6 and StopFlag == false)
{
StopFlag = true;
StopTime = millis();
StopKind = 6;//зафиксирована причина останова
}
else
{
Temper[a] = TemperPrev[a];
if (StopFlag == false)
MistakeTemp[a]++;
}
}
//функция для вычисления расхода воды по водомеру с герконом
void voda_tick() {
//Serial.println("proverka");
boolean current_status = digitalRead(pinVoda_tick);
if (stateCheck_voda and !current_status) {
tmr = millis(); //зафиксировали время срабатывания прерывания
gWaterFlag = true;
stateCheck_voda = current_status;
}
if (!stateCheck_voda and current_status)stateCheck_voda = current_status;
if (current_status)gWaterFlag = false;
if (!current_status and millis() - tmr >= 1000 and gWaterFlag == true)
{
WaterCountTimer = millis() - WaterStartTimer;
WaterStartTimer = millis();
gWaterFlag = false;
if (FirstImpulsWater == true)SecondImpulsWater = true;//если поднят флаг о уже полученном первом импульсе с водомера, то поднимается флаг о получении второго импульса
FirstImpulsWater = true;//поднят флаг о том, что пришёл первый импульс с водомера, при начале вычислений расхода воды
}
}
//функция для вычисления потребляемой электрической мощности, по импульсному выходу электросчётчика
void electr_tick() {
//Serial.println("proverka");
boolean current_status = digitalRead(pinElectr_tick);
if (stateCheck_electr and !current_status) {
tmr2 = millis(); //зафиксировали время срабатывания прерывания
ElectrFlag = true;
stateCheck_electr = current_status;
}
if (!stateCheck_electr and current_status)stateCheck_electr = current_status;
if (current_status)ElectrFlag = false;
if (!current_status and millis() - tmr2 >= 50 and ElectrFlag == true)
{
ElectrCountTimer = millis() - ElectrStartTimer;
ElectrStartTimer = millis();
ElectrFlag = false;
}
}
//функция для вывода значений на дисплей
void getDataInt100(int16_t a)//вывод значений на дисплей у которых делится на 100
{
//Serial.println("proverka");
if (a >= -9 and a < 0)
{
tft.print("-0.0");
tft.print(abs(a));
}
else if (a<9 and a >= 0)
{
tft.print("0.0");
tft.print(a);
}
else if (a <= -10 and a > -100)
{
tft.print("-0.");
tft.print(abs(a % 100));
}
else
{
tft.print(a / 100);
tft.print(".");
if (abs(a % 100) < 10)
tft.print("0");
tft.print(abs(a % 100));
}
}
//функция для вывода значений на дисплей
void getDataInt10(int16_t a)//вывод значений на дисплей у которых делится на 10
{
//Serial.println("proverka");
if (a >= -9 and a < 0)
{
tft.print("-0.");
tft.print(abs(a));
}
else if (a<9 and a >= 0)
{
tft.print("0.");
tft.print(a);
}
else
{
tft.print(a / 10);
tft.print(".");
tft.print(abs(a % 10));
}
}
//функция для создания массива с последующим выводом на дисплей графиков
int16_t getDataForUintMassiv(int16_t a)//границы для последнего значения в массиве для графиков, типа uint8_t
{
//Serial.println("proverka");
int16_t LastInMassive;//ввожу временную переменную для вычисления последнего значения массива для графиков
if (a < -400)
LastInMassive = 0;
else if (a >= -400 and a < 500)
LastInMassive = round ((a + 400) / 5);
else if (a >= 500 and a < 1250)
LastInMassive = round (180 + (a - 500) / 10);
else if (a >= 1250)
LastInMassive = 255;
return LastInMassive;
}
//функция для создания массива с последующим выводом на дисплей графиков
int32_t getDataForUintMassiv32(int32_t a)//границы для последнего значения в массиве для графиков, типа uint8_t
{
//Serial.println("proverka");
int32_t LastInMassive;//ввожу временную переменную для вычисления последнего значения массива для графиков
if (a < -400)
LastInMassive = 0;
else if (a >= -400 and a < 0)
LastInMassive = round ((a + 400) / 10);
else if (a >= 0 and a <= 160)
LastInMassive = round (40 + a);
else if (a > 160 and a < 710)
LastInMassive = round (200 + (a - 160) / 10);
else if (a >= 710)
LastInMassive = 255;
return LastInMassive;
}
//функция для вычерчивания графиков
void getGraphics(uint16_t c, uint16_t d, uint8_t g[320]) //процедура построения графиков
{
//Serial.println("proverka");
int16_t oldX = 0;
int16_t oldY = g[0];
for (int16_t x = 1; x < 320; x++)
{
int16_t nxt_x = x;
tft.drawLine(oldX, (c - oldY), nxt_x, (c - g[x]), d);
oldY = g[x];
oldX = nxt_x;
}
}
//Функция для вывода графики на дисплей
void getMainDisplay()//вычерчивание основного дисплея
{
//Serial.println("proverka");
tft.fillScreen(BLACK);//закраска дисплея чёрным цветом
//сетка по времени:
for (uint8_t i = 1; i < 8; i++)
{
tft.drawFastVLine((40 * i), 20, 190, DARKGREY);
tft.drawFastVLine((40 * i), 230, 210, DARKGREY);
}
//сетка по шкале температур:
for (uint8_t i = 0; i < 11; i++)
{
if (i == 4 or i == 5 or i == 6 or i == 7 or i == 9 or i == 10)
tft.drawFastHLine(0, (5 + 20 * i), 320, DARKGREEN);
else if (i == 1 or i == 2 or i == 3 or i == 8)
tft.drawFastHLine(0, (5 + 20 * i), 320, BLUE);
}
for (uint8_t i = 0; i < 5; i++)
tft.drawFastHLine(0, (231 + 10 * i), 320, BLUE);
tft.drawFastHLine(0, 275, 320, BLUE);
for (uint8_t i = 0; i < 8; i++)
tft.drawFastHLine(0, (295 + 20 * i), 320, DARKGREEN);
//подписи по вертикали на графиках
tft.setCursor(0, 22); // Устанавливаем курсор (X = , Y = )
tft.setTextSize(1); // Указываем размер символов в строке от 1 до 3
tft.setTextColor(WHITE, BLACK); // Указываем цвет текста
tft.print("90");
tft.setCursor(0, 42); // Устанавливаем курсор (X = , Y = )
tft.print("70");
tft.setCursor(0, 62); // Устанавливаем курсор (X = , Y = )
tft.print("50");
tft.setCursor(0, 82); // Устанавливаем курсор (X = , Y = )
tft.print("40");
tft.setCursor(0, 102); // Устанавливаем курсор (X = , Y = )
tft.print("30");
tft.setCursor(0, 122); // Устанавливаем курсор (X = , Y = )
tft.print("20");
tft.setCursor(0, 142); // Устанавливаем курсор (X = , Y = )
tft.print("10");
tft.setCursor(0, 162); // Устанавливаем курсор (X = , Y = )
tft.print("0");
tft.setCursor(0, 182); // Устанавливаем курсор (X = , Y = )
tft.print("-10");
tft.setCursor(0, 202); // Устанавливаем курсор (X = , Y = )
tft.print("-20");
tft.setCursor(0, 238); // Устанавливаем курсор (X = , Y = )
tft.print("5");
tft.setCursor(0, 258); // Устанавливаем курсор (X = , Y = )
tft.print("3");
tft.setCursor(0, 272); // Устанавливаем курсор (X = , Y = )
tft.print("1.6");
tft.setCursor(0, 292); // Устанавливаем курсор (X = , Y = )
tft.print("1.4");
tft.setCursor(0, 312); // Устанавливаем курсор (X = , Y = )
tft.print("1.2");
tft.setCursor(0, 332); // Устанавливаем курсор (X = , Y = )
tft.print("1");
tft.setCursor(0, 352); // Устанавливаем курсор (X = , Y = )
tft.print("0.8");
tft.setCursor(0, 372); // Устанавливаем курсор (X = , Y = )
tft.print("0.6");
tft.setCursor(0, 392); // Устанавливаем курсор (X = , Y = )
tft.print("0.4");
tft.setCursor(0, 412); // Устанавливаем курсор (X = , Y = )
tft.print("0.2");
tft.setCursor(0, 432); // Устанавливаем курсор (X = , Y = )
tft.print("0");
//надписи назначения измерений датчиков
tft.setCursor(0, 0); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(RED); // Указываем цвет текста
tft.print("Kompressor:");
tft.setCursor(10, 10); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(MAGENTA); // Указываем цвет текста
tft.print("Overheat:");
tft.setCursor(125, 10); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(CYAN); // Указываем цвет текста
tft.print("Defrost:");
tft.setCursor(220, 10); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(RED); // Указываем цвет текста
tft.print("Isparitel:");
tft.setCursor(120, 0); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(YELLOW); // Указываем цвет текста
tft.print("Water in:");
tft.setCursor(220, 0); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(GREEN); // Указываем цвет текста
tft.print("Water out:");
tft.setCursor(5, 210); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(RED); // Указываем цвет текста
tft.print("Heat power:");
tft.setCursor(152, 210); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(YELLOW); // Указываем цвет текста
tft.print("COP:");
tft.setCursor(218, 210); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(GREEN); // Указываем цвет текста
tft.print("Electr pow:");
tft.setCursor(22, 220); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(MAGENTA); // Указываем цвет текста
tft.print("G water:");
}
void setup()
{ // put your setup code here, to run once:
//Serial.println("proverka");
Serial.begin(9600);
tft.reset();
tft.begin(38022); //указание модели экрана
tft.invertDisplay(true); //инверсия цветов - т.к. по умолчанию инвертирует цвета
//tft.setRotation(1); //поворот экрана на 90 градусов
//для водомера
pinMode(18, INPUT_PULLUP);// подключили импульсный выход на D18
stateCheck_voda = digitalRead(pinVoda_tick);
//для электросчётчика
pinMode(19, INPUT_PULLUP);// подключили импульсный выход на D19
stateCheck_electr = digitalRead(pinElectr_tick);
//присвоение массивам значений, чтобы на графике сначала были нули
for (int i = 0; i < 320; i++) {
tIsparitel[i] = 80;
tOverheat[i] = 80;
tKompressor[i] = 80;
tWaterIn[i] = 80;
tWaterOut[i] = 80;
tDefrost[i] = 80;
heatPower[i] = 40;
gWater[i] = 40;
ElectrPow[i] = 40;
COP[i] = 40;
}
//для управления реле
pinMode(48, OUTPUT);//пин реле вентилятора
digitalWrite(48, HIGH);//управление вентилятором
pinMode(49, OUTPUT);//пин реле четырёхходового клапана
digitalWrite(49, HIGH);//управление четырёхходовым клапаном
pinMode(50, OUTPUT);//пин реле компрессора
digitalWrite(50, HIGH);//управление компрессором
pinMode(51, OUTPUT);//пин реле насоса
digitalWrite(51, HIGH);//управление насосом
//инициирую режим "нагрев" при старте микроконтроллера, другие режимы отключены
StopFlag = false;//опущен флаг для перехода в режим "останов"
HeatOptionFlag = false;//опущен флаг о том что в работе режим "нагрев"
HeatOptionPauseFlag = false;//опущен флаг режима приостанова нагрева
DefrostOptionFlag = false; //опущен флаг о начале работы режима Defrost
StartHeatFlag = true;//поднят флаг о том, что начался переход в режим "нагрев"
StartHeatTime = millis();//фиксация времени начала перехода в режим "нагрев"
Timer = millis(); //для запуска цикла
delay(1000); //задержка 1 сек
}
void loop()// put your main code here, to run repeatedly:
{
voda_tick();//переход на функцию по подсчёту расхода воды
electr_tick();//переход на функцию по подсчёту электрической мощности
//первый шаг выполнения по таймеру
if (millis() - Timer >= 3000 and millis() - Timer < 5000 and Flag1 == true)//если от 3 до 5 сек и флаг1 поднят
{
resetTemp();//направление на процедуру по сбросу шины с датчиками
Flag1 = false;
}
//второй шаг выполнения по таймеру
if (millis() - Timer >= 5000 and millis() - Timer < 7000 and Flag2 == true)//если от 5 до 7 сек и флаг2 поднят
{
gettingTemp();//направление на процедуру по получению значений температуры с шины с датчиками
Flag2 = false;
}
//третий шаг выполнения по таймеру
if (millis() - Timer >= 7000 and millis() - Timer < 9000 and Flag3 == true)//если от 7 до 9 сек и флаг3 поднят
{
if (getMistakeFlag == false)//при первом получении значений температур
{
for (uint8_t i = 0; i < 6; i++)
{
TemperPrev[i] = Temper[i];
}
getMistakeFlag = true;
}
//отсылка на процедуру проверки корректности полученных температур
tempMistake (0, -100, 1200, 200); // - датчик на выходе из компрессора - (номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение)
tempMistake (1, 0, 600, 100); // - датчик на входе воды в ППТО - (номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение)
tempMistake (2, 0, 900, 50); // - датчик на выходе воды из ППТО - (номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение)
tempMistake (3, -400, 800, 400); // - датчик на входе в компрессор - (номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение)
tempMistake (4, -400, 600, 300); // - датчик в точке Defrost в нижней части ППТО - (номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение)
tempMistake (5, -400, 800, 200); // - датчик в начале испарителя - (номер датчика в массиве, минимальное значение, максимальное значение, максимальное изменение)
//вычисляю перегрев
tOverheatReal = (Temper[3] - Temper[5]);
//расчёт расхода воды
if (digitalRead(51) == HIGH) //если выключен насос
{
gWaterReal = 0;
gWaterRealPrew = gWaterReal;
FlagWater = false;//сброшен флаг подсветки значения
}
else if (digitalRead(51) == LOW and millis() - WaterStartTimer > 400000)//если за 400 секунд работы насоса не пришёл сигнал с геркона водомера
{
StopFlag = true;
StopTime = millis();
StopKind = 7;//зафиксирована причина останова
}
else if (SecondImpulsWater == false)//если ещё не произошло второе срабатывание геркона водомера
{
gWaterReal = gWaterRealPrew;
FlagWater = true;//поднят флаг для подсветки значения неизвестного расхода
}
else
{
gWaterReal = round (3600000 / WaterCountTimer); //итоговое значение в м3/ч умноженные на 100
gWaterRealPrew = gWaterReal;
FlagWater = false;//сброшен флаг подсветки значения
}
//расчёт электрической мощности
if (millis() - ElectrStartTimer > 60000) //если нет данных с счётчика в течение 1 мин.
ElectrPowReal = 0;
else
ElectrPowReal = 72000 / ElectrCountTimer; //значение в кВт умноженные на 100
//расчёт полезной тепловой мощности
heatPowerReal = ((int32_t)Temper[2] - (int32_t)Temper[1]) * gWaterReal * 1163 / 10000; //тепловая мощность на теплообменнике в кВт умноженная на 100
//расчёт СОР
if (ElectrPowReal < 10)
COPreal = 0;
else
COPreal = 100 * heatPowerReal / ElectrPowReal; //вычисление COP, умноженное на 100
//подсчёт среднеарифметической тепловой мощности и электроэнергии
countHeat = countHeat + heatPowerReal;
countElectr = countElectr + ElectrPowReal;
countHeatAndElectr++;
//останов вентилятора при перегреве компрессора
if (HeatOptionFlag == true and Temper[0] >= 850 and tOverheatReal >= 300 and digitalRead(48) == LOW)//если высокая температура на выходе из компрессора и перегрев с запасом и вентилятор включён
{
tKompressorCounter++;
if (tKompressorCounter >= 4)//если сработал счётчик
{
bitClear(relay, 0);//остановить вентилятор
tKompressorCounter = 0;
}
}
else if (HeatOptionFlag == true and (Temper[0] <= 750 or tOverheatReal <= 200) and digitalRead(48) == HIGH)//если остыл компрессор или перегрев мал и вентилятор выключен
{
tKompressorCounter++;
if (tKompressorCounter >= 2)//если сработал счётчик
{
bitSet(relay, 0);//включить вентилятор
tKompressorCounter = 0;
}
}
else
tKompressorCounter = 0;
//смена режимов
if (HeatOptionFlag == true and Temper[1] >= 360)//если температура воды перед теплообменником достигла 36 град.
{
HeatOptionCout++;
if (HeatOptionCout >= 6)//если устоялся режим
{
HeatOptionFlag = false;
HeatOptionPauseFlag = true;
HeatOptionCout = 0;
HeatOptionPauseStartTime = millis();
bitClear(relay, 2);//остановить компрессор
bitClear(relay, 0);//остановить вентилятор
}
}
else
HeatOptionCout = 0;
if (HeatOptionPauseFlag == true and digitalRead(49) == LOW and millis() - HeatOptionPauseStartTime >= 120000) //если началась пауза обогрева и 4х ход. клапан включён и вышло время
bitClear(relay, 1);//перевести четырёхходовой клапан в штатное положение (режим "охлаждение")
if (HeatOptionPauseFlag == true and digitalRead(51) == HIGH and millis() - HeatOptionPauseStartTime >= 960000) //если прошло время 15 мин. после остановки насоса
{
if (digitalRead(51) == HIGH)//если насос выключен
{
WaterStartTimer = millis();//фиксирование времени начала отсчёта расхода
FirstImpulsWater = false;//ожидание первого импульса от водомера
SecondImpulsWater = false;//ожидание второго импульса от водомера
}
bitSet(relay, 3);//включить насос
HeatOptionPauseStartTime = millis();
}
if (HeatOptionPauseFlag == true and digitalRead(51) == LOW and millis() - HeatOptionPauseStartTime >= 60000) //если прошло время 1 мин. после включения насоса
{
bitClear(relay, 3);//выключить насос
HeatOptionPauseStartTime = millis();
}
if (HeatOptionPauseFlag == true and Temper[1] <= 280)//если в режиме паузы обогрева температура воды перед теплообменником низкая
{
HeatOptionPauseCout++;
if (HeatOptionPauseCout >= 5)//если устоялся режим
{
HeatOptionPauseFlag = false;
HeatOptionPauseCout = 0;
StartHeatTime = millis();//фиксация времени начала перехода в режим "нагрев"
StartHeatFlag = true;//поднят флаг о том, что начался переход в режим "нагрев"
}
}
else
HeatOptionPauseCout = 0;
//режим оттайки
if (HeatOptionFlag == true and Temper[5] < -100)
{
defrostCount++;
if (defrostCount >= 6)
{
HeatOptionFlag = false;
DefrostOptionFlag = true;
DefrostTime = millis();
defrostCount = 0;
}
}
else
defrostCount = 0;
//защита от неправильного положения 4х ходового клапана
if (HeatOptionFlag == true and digitalRead(49) == HIGH)//если 4х ходовый клапан в неправильном положении
{
StopNo4xvalve++;
if (StopNo4xvalve >= 3)
{
bitClear(relay, 2);//остановить компрессор
StopFlag = true;//переход в режим останов
StopTime = millis();
StopKind = 1; //зафиксирована причина остановки
StopNo4xvalve = 0;
}
}
else
StopNo4xvalve = 0;
//защита от превышения температуры на выходе из компрессора
if ((StartHeatFlag == true or HeatOptionFlag == true or HeatOptionPauseFlag == true or DefrostOptionFlag == true) and Temper[0] >= 1000)
{
StopMaxTemp++;
if (StopMaxTemp >= 5)
{
StopFlag = true;
StopTime = millis();
StopKind = 2;//зафиксирована причина останова
StopMaxTemp = 0;
}
}
else
StopMaxTemp = 0;
//защита от превышения электрической мощности
if ((StartHeatFlag == true or HeatOptionFlag == true or HeatOptionPauseFlag == true or DefrostOptionFlag == true) and ElectrPowReal >= 151)
{
StopMaxElectr++;
if (StopMaxElectr >= 6)
{
StopFlag = true;
StopTime = millis();
StopKind = 3;//зафиксирована причина останова
StopMaxElectr = 0;
}
}
else
StopMaxElectr = 0;
//защита от замерзания теплообменника (кроме режима Defrost)
if ((StartHeatFlag == true or HeatOptionFlag == true or HeatOptionPauseFlag == true) and Temper[4] <= 50)
{
StopMinTempHeater++;
if (StopMinTempHeater >= 3)
{
StopFlag = true;
StopTime = millis();
StopKind = 4;//зафиксирована причина останова
StopMinTempHeater = 0;
}
}
else
StopMinTempHeater = 0;
//при отключении электроэнергии
if (digitalRead(50) == LOW and ElectrPowReal <= 10)//если включён компрессор и электрическая мощность очень мала
{
StopNoElectric++;
if (StopNoElectric >= 6)
{
StopFlag = true;
StopTime = millis();
StopKind = 5;//зафиксирована причина останова
StopNoElectric = 0;
}
}
else
StopNoElectric = 0;
//режим старта обогрева
if (StartHeatFlag == true and millis() - StartHeatTime >= 20000 and Temper[1] >= 50)//если начат переход в режим "нагрев" и при этом прошло время после старта перехода и температура воды перед ППТО более 5 град.
{
if (digitalRead(51) == HIGH)//если насос выключен
{
WaterStartTimer = millis();//фиксирование времени начала отсчёта расхода
FirstImpulsWater = false;//ожидание первого импульса от водомера
SecondImpulsWater = false;//ожидание второго импульса от водомера
}
bitSet(relay, 3);//включить насос
}
if (StartHeatFlag == true and digitalRead(51) == LOW and millis() - StartHeatTime >= 30000 and Temper[0] <= 850)//если начат переход в режим "нагрев" и при этом прошло время после старта перехода и температура компрес. менее 85 град.
bitSet(relay, 0);//включить вентилятор
if (StartHeatFlag == true and digitalRead(51) == LOW and digitalRead(48) == LOW and millis() - StartHeatTime >= 40000)//если начат переход в режим "нагрев" и при этом прошло время после старта перехода
bitSet(relay, 1);//переключить четырёхходовой клапан в режим "нагрев"
if (StartHeatFlag == true and digitalRead(51) == LOW and digitalRead(48) == LOW and digitalRead(49) == LOW and millis() - StartHeatTime >= 45000)//если начат переход в режим "нагрев" и при этом прошло время после старта перехода и включён насос и четырёхходовой клапан в режим "нагрев"
bitSet(relay, 2);//включить компрессор
//переход в режим обогрева после старта
if (StartHeatFlag == true and digitalRead(51) == LOW and digitalRead(48) == LOW and digitalRead(50) == LOW and digitalRead(49) == LOW)//если начат переход в режим "нагрев" и все требуемые для этого устройства включены
{
StartHeatFlag = false;//окончен переход в режим "нагрев"
HeatOptionFlag = true;//действует режим "нагрев"
}
if (StopFlag == true)
{
StartHeatFlag = false;
HeatOptionFlag = false;
HeatOptionPauseFlag = false;
DefrostOptionFlag = false;
bitClear(relay, 2);//остановить компрессор
bitClear(relay, 0);//остановить вентилятор
if (millis() - StopTime >= 120000)
bitClear(relay, 1);//перевести четырёхходовой клапан в штатное положение (режим "охлаждение")
if (millis() - StopTime >= 180000)
bitClear(relay, 3);//выключить насос
}
if (DefrostOptionFlag == true)
{
if (digitalRead(51) == HIGH)//если насос выключен
{
WaterStartTimer = millis();//фиксирование времени начала отсчёта расхода
FirstImpulsWater = false;//ожидание первого импульса от водомера
SecondImpulsWater = false;//ожидание второго импульса от водомера
}
bitSet(relay, 3);//включить насос
bitClear(relay, 2);//остановить компрессор
bitSet(relay, 0);//включить вентилятор если температура воздуха на улице больше +3 град. С - то вентилятор не отключать
if (millis() - DefrostTime >= 120000)
bitClear(relay, 1);//перевести четырёхходовой клапан в штатное положение (режим "охлаждение")
if (millis() - DefrostTime >= 900000 and Temper[5] >= 20)
{
DefrostOptionFlag = false;
StartHeatTime = millis();
StartHeatFlag = true;
}
}
//вычерчивание чёрных прямоугольников для закрашивания предыдущих значений с датчиков
tft.fillRect(74, 0, 30, 20, BLACK);
tft.fillRect(181, 0, 30, 20, BLACK);
tft.fillRect(289, 0, 30, 20, BLACK);
tft.fillRect(74, 210, 30, 20, BLACK);
tft.fillRect(181, 210, 30, 10, BLACK);
tft.fillRect(289, 210, 30, 10, BLACK);
tft.fillRect(152, 220, 60, 10, BLACK);
tft.fillRect(100, 470, 30, 8, BLACK);
tft.fillRect(200, 470, 30, 8, BLACK);
//отображение точных значений с датчиков
tft.setCursor(74, 0); // Устанавливаем курсор (X = , Y = )
if (MistakeTemp[0] > 0)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(RED); // Указываем цвет текста
getDataInt10(Temper[0]);
tft.setCursor(181, 0); // Устанавливаем курсор (X = , Y = )
if (MistakeTemp[1] > 0)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(YELLOW); // Указываем цвет текста
getDataInt10(Temper[1]);
tft.setCursor(289, 0); // Устанавливаем курсор (X = , Y = )
if (MistakeTemp[2] > 0)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(GREEN); // Указываем цвет текста
getDataInt10(Temper[2]);
tft.setCursor(74, 10); // Устанавливаем курсор (X = , Y = )
if (MistakeTemp[3] > 0)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(MAGENTA); // Указываем цвет текста
getDataInt10(tOverheatReal);
tft.setCursor(181, 10); // Устанавливаем курсор (X = , Y = )
if (MistakeTemp[4] > 0)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(CYAN); // Указываем цвет текста
getDataInt10(Temper[4]);
tft.setCursor(289, 10); // Устанавливаем курсор (X = , Y = )
if (MistakeTemp[5] > 0)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(RED); // Указываем цвет текста
getDataInt10(Temper[5]);
tft.setCursor(74, 210); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(RED); // Указываем цвет текста
getDataInt100(heatPowerReal);
tft.setCursor(181, 210); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(YELLOW); // Указываем цвет текста
getDataInt100(COPreal);
tft.setCursor(289, 210); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(GREEN); // Указываем цвет текста
getDataInt100(ElectrPowReal);
tft.setCursor(74, 220); // Устанавливаем курсор (X = , Y = )
if (FlagWater == true)
tft.setTextColor(CYAN, MAGENTA); // Указываем цвет текста
else
tft.setTextColor(MAGENTA); // Указываем цвет текста
getDataInt100(gWaterReal);
tft.setCursor(100, 470); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(RED); // Указываем цвет текста
getDataInt100(countHeat / countHeatAndElectr);
tft.setCursor(200, 470); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(GREEN); // Указываем цвет текста
getDataInt100(countElectr / countHeatAndElectr);
/*
tft.setCursor(200, 460); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(GREEN,BLACK); // Указываем цвет текста
tft.print(Temper[3]);
*/
tft.setCursor(152, 220); // Устанавливаем курсор (X = , Y = )
tft.setTextColor(RED); // Указываем цвет текста
if (StopFlag == true)//если режим "останов" активен
{
tft.print("Stop");
if (StopKind == 1)
tft.print(" No 4x valve");
else if (StopKind == 2)
tft.print(" maxT Kompr");
else if (StopKind == 3)
tft.print(" maxW Electr");
else if (StopKind == 4)
tft.print(" minT Heater");
else if (StopKind == 5)
tft.print(" No Electr");
else if (StopKind == 6)
tft.print(" Err Temp");
else if (StopKind == 7)
tft.print(" No G_water");
else if (StopKind == 8)
tft.print(" No Option");
}
else if (StartHeatFlag == true)
tft.print("Start heat");
else if (HeatOptionFlag == true)
tft.print("Heat option");
else if (HeatOptionPauseFlag == true)
tft.print("Pause heat");
else if (DefrostOptionFlag == true)
tft.print("Defrost");
else //если ни один из флагов не поднят
{
StopFlag = true;
StopTime = millis();
StopKind = 8;//зафиксирована причина останова
}
//надписи для линий "включено_выключено"
tft.setCursor(0, 440); // Устанавливаем курсор (X = , Y = )
if (bitRead(relay, 2) == 1)
tft.setTextColor(RED); // Указываем цвет текста
else
tft.setTextColor(BLUE); // Указываем цвет текста
tft.print("Kompressor");
tft.setCursor(0, 450); // Устанавливаем курсор (X = , Y = )
if (bitRead(relay, 3) == 1)
tft.setTextColor(RED); // Указываем цвет текста
else
tft.setTextColor(BLUE); // Указываем цвет текста
tft.print("Pump");
tft.setCursor(0, 460); // Устанавливаем курсор (X = , Y = )
if (bitRead(relay, 1) == 1)
tft.setTextColor(RED); // Указываем цвет текста
else
tft.setTextColor(BLUE); // Указываем цвет текста
tft.print("4 way valve");
tft.setCursor(0, 470); // Устанавливаем курсор (X = , Y = )
if (bitRead(relay, 0) == 1)
tft.setTextColor(RED); // Указываем цвет текста
else
tft.setTextColor(BLUE); // Указываем цвет текста
tft.print("Fan");
Flag3 = false;
}
//четвёртый шаг выполнения по таймеру
if (millis() - Timer >= 9000 and millis() - Timer < 10000 and Flag4 == true)//если от 9 до 10 сек и флаг4 поднят
{
if (bitRead(relay, 0) == 1) //если нулевой бит равен единице
digitalWrite(48, LOW);//включить вентилятор
else if (bitRead(relay, 0) == 0) //если нулевой бит равен нулю
digitalWrite(48, HIGH);//выключить вентилятор
if (bitRead(relay, 1) == 1) //если первый бит равен единице
digitalWrite(49, LOW);//переключить четырёхходовой клапан в режим "нагрев"
else if (bitRead(relay, 1) == 0) //если первый бит равен нулю
digitalWrite(49, HIGH);//переключить четырёхходовой клапан в режим "оттайка"
if (bitRead(relay, 2) == 1) //если второй бит равен единице
digitalWrite(50, LOW);//включить компрессор
else if (bitRead(relay, 2) == 0) //если второй бит равен нулю
digitalWrite(50, HIGH);//выключить компрессор
if (bitRead(relay, 3) == 1) //если третий бит равен единице
digitalWrite(51, LOW);//включить насос
else if (bitRead(relay, 3) == 0) //если третий бит равен нулю
digitalWrite(51, HIGH);//выключить насос
Flag4 = false;
}
//пятый шаг выполнения по таймеру
if (millis() - Timer >= 10000)//если больше 10 сек
{
Timer = millis(); //запускаем отсчёт нового цикла
//(график периодически)
if (countGetGrafic >= 9)//между циклами 90 сек
{
//перенос значений в массиве
for (uint16_t x = 0; x < 319; x++)
{
tIsparitel[x] = tIsparitel[x + 1];
tOverheat[x] = tOverheat[x + 1];
tKompressor[x] = tKompressor[x + 1];
tWaterIn[x] = tWaterIn[x + 1];
tWaterOut[x] = tWaterOut[x + 1];
gWater[x] = gWater[x + 1];
heatPower[x] = heatPower[x + 1];
ElectrPow[x] = ElectrPow[x + 1];
COP[x] = COP[x + 1];
tDefrost[x] = tDefrost[x + 1];
}
tKompressor[319] = (uint8_t)getDataForUintMassiv(Temper[0]);
tWaterIn[319] = (uint8_t)getDataForUintMassiv(Temper[1]);
tWaterOut[319] = (uint8_t)getDataForUintMassiv(Temper[2]);
tOverheat[319] = (uint8_t)getDataForUintMassiv(tOverheatReal);
tDefrost[319] = (uint8_t)getDataForUintMassiv(Temper[4]);
tIsparitel[319] = (uint8_t)getDataForUintMassiv(Temper[5]);
heatPower[319] = (uint8_t)getDataForUintMassiv32(heatPowerReal);
COP[319] = (uint8_t)getDataForUintMassiv32(COPreal);
ElectrPow[319] = (uint8_t)getDataForUintMassiv32(ElectrPowReal);
gWater[319] = (uint8_t)getDataForUintMassiv32(gWaterReal);
//формирование массивов для графиков включения оборудования
for (uint8_t i; i < 20; i++)
{
trend_fan[i] = trend_fan[i] << 1;
bitWrite(trend_fan[i], 0, bitRead(trend_fan[i + 1], 15));
trend_kompressor[i] = trend_kompressor[i] << 1;
bitWrite(trend_kompressor[i], 0, bitRead(trend_kompressor[i + 1], 15));
trend_pump[i] = trend_pump[i] << 1;
bitWrite(trend_pump[i], 0, bitRead(trend_pump[i + 1], 15));
trend_4way_valve[i] = trend_4way_valve[i] << 1;
bitWrite(trend_4way_valve[i], 0, bitRead(trend_4way_valve[i + 1], 15));
}
bitWrite(trend_fan[19], 0, bitRead(relay, 0));
bitWrite(trend_kompressor[19], 0, bitRead(relay, 2));
bitWrite(trend_pump[19], 0, bitRead(relay, 3));
bitWrite(trend_4way_valve[19], 0, bitRead(relay, 1));
getMainDisplay();//прорисовка всего экрана
//прорисовка графиков
getGraphics(245, RED, tKompressor);
getGraphics(245, YELLOW, tWaterIn);
getGraphics(245, GREEN, tWaterOut);
getGraphics(245, MAGENTA, tOverheat);
getGraphics(245, CYAN, tDefrost);
getGraphics(245, RED, tIsparitel);
getGraphics(475, RED, heatPower);
getGraphics(475, YELLOW, COP);
getGraphics(475, GREEN, ElectrPow);
getGraphics(475, MAGENTA, gWater);
//прорисовка графика состояний исполнительных реле
for (uint8_t i = 0; i < 20; i++)
{
for (uint8_t j = 0; j < 16; j++)
{
if (bitRead(trend_fan[i], j) == 1)
tft.drawPixel ((i * 16 + (15 - j)), 479, YELLOW);
if (bitRead(trend_kompressor[i], j) == 1)
tft.drawPixel ((i * 16 + (15 - j)), 449, YELLOW);
if (bitRead(trend_pump[i], j) == 1)
tft.drawPixel ((i * 16 + (15 - j)), 459, YELLOW);
if (bitRead(trend_4way_valve[i], j) == 1)
tft.drawPixel ((i * 16 + (15 - j)), 469, YELLOW);
}
}
countGetGrafic = 0; //для подсчёта времени между выводами графика
}
countGetGrafic++;//для подсчёта времени между выводом графиков на дисплей
Flag1 = true;
Flag2 = true;
Flag3 = true;
Flag4 = true;
}
}
Собственно, почему решил написать…
Устал самостоятельно искать причину сбоев. Менял провода, ставил экранированные. Внедрил два блока питания, внедрил опторазвязку от датчиков… Несколько раз менял код получения температуры - полностью устранить проблему не могу. Обращаюсь сюда с надеждой выяснить - как мне устранить проблему? В голове уже крайние мысли - смена датчиков (на профильном форуме по тепловым насосам - упоминались NTC). Тогда - на какие именно и как их правильно подключать.
Для проверки, напишите функцию- заглушку, в которой вместо опроса датчиков просто переменной присваивается определённое значение температуры, и, физически отключите датчики.
P.S.
А как у вас реализована задержка для работы АЦП датчиков?
P.P.S.
Возможно, что код слишком “громоздкий” для Уно/Нано и просто не хватает памяти. Как вариант - проверить на Меге.
Не совсем понял, что предлагается… отключить шину с датчиками температуры от контроллера и вместо обращений к датчикам - записывать некое постоянное значение в переменную? И просмотреть - не случится ли сбой? И на основании этого - сделать вывод, виновен ли именно датчик температуры?
DS18B20 нужно закупать у проверенных поставщиков, но и это не уберегает от подделок и глюков.
У меня был опыт сборки устройств измерения влажности, основанных на двух таких датчиках в герметичной гильзе (один влажный, второй сухой). Собрал я в общей сложности штук 30 их за пару лет, датчики мне закупал заказчик. Так вот, бывало некоторые устройства начинали глючить через какое-то время, периодически показывали не ту температуру. Решалась эта проблема только заменой датчика на новый. Иногда глючные датчики попадались реже, иногда чаще.
Если нет требований по точности, мне кажется можно взять ntc-резистор, как уже тут советовали, откалибровать его и пользоваться. Точность можно поднять увеличением количества измерений.
Конечно. Напишите функцию - замену для датчиков. Из неё передавайте в основной код значения температуры, к примеру, увеличивая каждый раз на 1 .
Если косяк останется - виноваты не датчики.
Ну, тогда надо брать какой-нибудь blue-pill, или ESP32. У вас код написан в среде Ардуино, возможно, получится перенести.
Но это на случай, если не выявите явных косяков в коде. Я лишь бегло глянул, сейчас нет времени на это, может ещё кто что-нибудь подскажет.
Ещё вариант проверки - запустите код без дисплея(есс-но закоментить всё лишнее) оставить только сериал, и, проверьте работу датчиков
Вроде как экранированную витую не рекомендуют. Обычную. Почитайте рекомендации Dallas uLan. Хотя, если расстояния не большие…
А потом, что мешает контролировать аномально резкие изменения температуры и реагировать на них?
Но в этом случае - у меня не будут срабатывать реле и сильноточные цепи. Есть большая вероятность, что сбои происходят - в том числе из-за них. В спокойном состоянии (без срабатываний реле и контактора) - ошибок не прилетает (не было зафиксировано).