Интересно, а вам доплачивают за сэкономленные строки? Пихать по пять операторов на строку - это неуважение к тем, кто будет это читать.
Да и обилие магических чисел в коде его не красит… Какой-то индийский недокод получается
А вы свой код покажите и общество сравнит.
это потом, а кушать хочется уже сейчас, готов продаться в рабство на месяц за 60к, для написания кода, результат не гарантирую, могу и к вам пойти в проект)))
Анализирую код от BABOS из сообщения 612 для Mega. Вижу такое:
// === 2. Приём данных от nano ===
if (Serial1.available()) {
DataFromNano temp;
if (Serial1.readBytes((uint8_t*)&temp, sizeof(temp))) {
uint8_t crc = crc8(&temp, sizeof(temp));
if (crc == 0) {
rxData = temp;
updateArrays();
// === 3. Отображение ===
if (rxData.mistakeOutput > 0) {
String msg;
switch(rxData.mistakeOutput) {
case 1: msg = "CRC error from Mega"; break;
case 2: msg = "Stop: CRC errors"; break;
case 3: msg = "Stop: Cycle error"; break;
case 4: msg = "Stop: Overheat!"; break;
case 5: msg = "Stop: Low pressure!"; break;
case 6: msg = "Connection LOST!"; break;
default: msg = "Unknown error";
}
showMistake(msg);
} else {
if (kindDisplay == 1) {
getAllLastDataToDisplay();
} else {
getMainDisplay();
getGraphics(245, RED, t1_Graph);
getGraphics(245, YELLOW, t2_Graph);
getGraphics(245, GREEN, t3_Graph);
getGraphics(245, MAGENTA, t4_Graph);
getGraphics(245, CYAN, t5_Graph);
getGraphics(245, RED, t6_Graph);
getGraphics(245, YELLOW, t7_Graph);
getGraphics(245, GREEN, t8_Graph);
getGraphics(245, MAGENTA, t9_Graph);
getGraphics(245, CYAN, t10_Graph);
getGraphics(475, RED, Water_Graph);
getGraphics(475, YELLOW, Electr_Graph);
}
}
}
}
}
либо я чего-то не понимаю…
Строка if (crc == 0) { переводится как “если нет ошибки CRC”. Я вижу - что должно сделаться, если ошибки CRC нет.
Но я не вижу - что должно сделаться, если всё-таки ошибка CRC будет. Я так понимаю - в этом случае контроллер ошибку никак не зафиксирует?
Надо бы зафиксировать… наверное.
Ну это будет с налогами 120к.
А ты на столько отработаешь?
Или ты уверен в том, что работодатель деньги из воздуха синтезирует?
Сидеть на ОПЕ ровно за чужие деньги - маловероятно, что получится…
Ну вы же не знаете, может бабос уже давно открыл самозанятость, так что для работодателя по налогам будет 0
Сомневаюсь Я, что бабос достиг такого уровня познания “дзена”
Инфантильность…
а вдруг ))))
Давай у него спросим, дабы интриги ну… Не здесЯ)))
дело в том что в начале CRC была добавлена только для того что бы в вашей сборке исключить неисправность датчиков температуры…
тут она теперь другая, и работает для проверки отправки целостности сообщения, и что делать если не доставлена я понятия не имею…
она ведь не останавливает всю систему… я вообще не понимаю зачем это… но допустим можно так сделать
в меге будет…
// В глобальные переменные добавьте:
uint16_t crcErrorCount = 0;
uint32_t lastCrcErrorTime = 0;
// В loop():
if (crc == 0) {
// ... обработка ...
crcErrorCount = 0; // Сброс при успешном приёме
} else {
crcErrorCount++;
lastCrcErrorTime = millis();
Serial.print("⚠️ CRC Error #");
Serial.println(crcErrorCount);
if (crcErrorCount >= 5) {
// Если 5 ошибок подряд - показываем предупреждение
showMistake("CRC errors: Check wiring!");
crcErrorCount = 0;
}
}
при чем в коде нано, есть тоже функция crc но толку от нее если например нано повиснет… я сам не полностью еще понимаю работу кода)))
Шаг 1: MEGA формирует пакет
MEGA берёт 3 параметра управления:
Целевая температура (например, 22.0°C)
Режим работы (OFF / AUTO / MANUAL)
Ручная команда (если режим MANUAL)
Упаковывает их в пакет из 5 байт:
Первые 2 байта: целевая температура
3-й байт: режим
4-й байт: ручная команда
5-й байт: ПУСТОЕ МЕСТО ДЛЯ CRC
Шаг 2: MEGA вычисляет CRC
Берёт первые 4 байта (все данные, КРОМЕ последнего пустого байта)
Пропускает их через математическую функцию CRC-8
Получает контрольную сумму (число от 0 до 255)
Записывает это число в 5-й (последний) байт
Шаг 3: MEGA отправляет полный пакет
Отправляет все 5 байт по проводу в NANO:
[температура] [режим] [команда] [CRC]
Делает это каждые 30 секунд
ЧАСТЬ 2: ПРИЁМ ПАРАМЕТРОВ В NANO
Шаг 4: NANO получает 5 байт
Читает из порта все 5 байт во временную переменную
Теперь у него есть: [температура] [режим] [команда] [CRC]
Шаг 5: NANO проверяет целостность
Берёт ВСЕ 5 байт (включая CRC)
Снова пропускает через ТУ ЖЕ САМУЮ функцию CRC-8
Смотрит на результат:
Если результат = 0 → данные не повреждены, можно использовать
Если результат ≠ 0 → данные повреждены, использовать НЕЛЬЗЯ
Почему это работает:
При отправке мы вычислили CRC от 4 байт и дописали его 5-м
Если мы теперь вычислим CRC от ВСЕХ 5 байт, математически должно получиться 0
Если хоть один бит изменился, получится НЕ 0
Шаг 6: NANO принимает решение
Если CRC верный (результат = 0):
✅ Применяет новые параметры:
Меняет целевую температуру
Меняет режим работы
Запоминает команду
Сбрасывает счётчик потери связи
Сбрасывает флаг "потеря связи"
Обнуляет код ошибки
Если CRC неверный (результат ≠ 0):
❌ ИГНОРИРУЕТ полученные параметры (не применяет их!)
Устанавливает код ошибки = 1 ("CRC error from Mega")
ОСТАВЛЯЕТ старые параметры (которые работали до этого)
НЕ обновляет время последнего приёма
Шаг 7: Важный момент с потерей связи
NANO постоянно следит: сколько прошло времени с последнего успешного приёма
Если прошло более 5 секунд → увеличивает счётчик пропусков
Если пропусков стало 3 подряд (15 секунд):
Устанавливает флаг "потеря связи"
Устанавливает код ошибки = 6 ("Connection LOST!")
ПЕРЕХОДИТ НА ПОСЛЕДНИЕ ВАЛИДНЫЕ ПАРАМЕТРЫ (которые были до потери)
ЧАСТЬ 3: ОТПРАВКА ДАННЫХ ОТ NANO К MEGA
Шаг 8: NANO собирает все данные
Берёт 10 температур от датчиков DS18B20
Добавляет давление
Добавляет время (часы, минуты, день, месяц)
Добавляет расход воды
Добавляет потребляемую мощность
Добавляет состояние всех реле (включены/выключены)
Добавляет код ошибки (если есть)
Упаковывает всё это в пакет из 31 байта:
20 байт: 10 температур (по 2 байта каждая)
1 байт: давление
4 байта: время (часы, минуты, день, месяц)
1 байт: расход воды
1 байт: мощность
2 байта: состояние реле
1 байт: код ошибки
1 байт: ПУСТОЕ МЕСТО ДЛЯ CRC
Шаг 9: NANO вычисляет CRC
Берёт первые 30 байт (ВСЕ данные, КРОМЕ последнего пустого байта)
Пропускает через функцию CRC-8
Получает контрольную сумму
Записывает её в последний (31-й) байт
Шаг 10: NANO отправляет полный пакет
Отправляет все 31 байт по проводу в MEGA
Делает это каждые 10 секунд
Отправляет ВСЕГДА, даже если есть ошибка (код ошибки будет в пакете)
ЧАСТЬ 4: ПРИЁМ ДАННЫХ В MEGA
Шаг 11: MEGA получает 31 байт
Читает из порта все 31 байт во временную переменную
Теперь у него есть: [10 температур] [давление] ... [код ошибки] [CRC]
Шаг 12: MEGA проверяет целостность
Берёт ВСЕ 31 байт (включая CRC)
Пропускает через ТУ ЖЕ САМУЮ функцию CRC-8
Смотрит на результат:
Если результат = 0 → данные целые
Если результат ≠ 0 → данные повреждены
Шаг 13: MEGA принимает решение (ВОТ ЗДЕСЬ ПРОБЛЕМА!)
Если CRC верный (результат = 0):
✅ Сохраняет данные в рабочую переменную
✅ Обновляет массивы для графиков
✅ Проверяет код ошибки от NANO:
Если код ошибки > 0 → показывает сообщение об ошибке на дисплее
Если код ошибки = 0 → обновляет дисплей с новыми данными
Если CRC неверный (результат ≠ 0):
❌ НИЧЕГО НЕ ДЕЛАЕТ!
❌ Не сохраняет данные
❌ Не обновляет дисплей
❌ Не показывает ошибку
❌ Не увеличивает счётчик ошибок
❌ Не записывает в лог
ПРОСТО ИГНОРИРУЕТ ВЕСЬ ПАКЕТ!
ЧАСТЬ 5: ЧТО ВИДИТ ПОЛЬЗОВАТЕЛЬ
При нормальной работе:
Дисплей обновляется каждые 10 секунд
Все температуры, расход, мощность показывают актуальные значения
Если нажать кнопку, температура меняется
При ошибке MEGA → NANO (CRC повреждён):
NANO: Не меняет параметры, устанавливает код ошибки = 1
NANO: Отправляет данные с кодом ошибки = 1
MEGA: Получает данные (CRC от NANO верный!), видит код ошибки = 1
MEGA: Показывает на дисплее "CRC error from Mega"
Пользователь видит: красный экран с ошибкой
При ошибке NANO → MEGA (CRC повреждён):
NANO: Отправляет данные (CRC вычислен, но по пути испортился)
MEGA: Получает искажённые 31 байт
MEGA: Вычисляет CRC от искажённых данных → результат НЕ 0
MEGA: ИГНОРИРУЕТ пакет
Дисплей: остаётся с ПРЕДЫДУЩИМИ данными (10 секунд назад)
Пользователь видит: старые показания, но НЕТ НИКАКОЙ ОШИБКИ!
Пользователь думает: всё работает нормально, а на самом деле данные не обновляются
При потере связи:
MEGA: Не отправляет параметры (обрыв провода)
NANO: Через 15 секунд понимает, что связи нет
NANO: Устанавливает код ошибки = 6
NANO: Переходит на последние валидные параметры
NANO: Продолжает отправлять данные с кодом = 6
MEGA: Получает данные (CRC от NANO верный!), видит код = 6
MEGA: Показывает на дисплее "Connection LOST!"
Пользователь видит: красный экран с ошибкой
бабос любит конверты, и если конверты значит доплата +43% должна быть обязательна, (30 +13%-22) а другие 13% я уплачу сам!)))
может и ошибаюсь, или что то путаю… или что то изменилось… но это вы платите налоги за работников а не я)))
легко! только для некоторых это двойной труд)))
вот пример, разработчик прошивок дронов, вместо того что бы заниматься реальным делом и писать код, ты сидишь и делаешь вид что изучаешь чужую прошивку, и модернизируешь ее, потому что если ты реально сделаешь, тебя сразу пнут, и не заплатят достойно))) по этому они сейчас платят тем кто создает вид работы, думая что они экономят и они умнее всех)))
тут и считать не надо, так как нарушается главный принцип: “где найти мне пару миллионов я бы все их бабам раздарил”
где же мои хейтеры… кто бы мне дизлайков накидал…
На вас ещё надежда есть, в силу возраста, а вот туть уже старческое. Тут уже никак, ибо - вера! Ну, может и Наташа, хто их знаить ![]()
А …ть, опять повёлся на этих. Тады для сурьёзности: @PPeterr возьмите Ардуину Мега2560 с большим дисплеем на SPI и тачем, и засуньте всё это в клетку Фарадея в металлический корпус. И не надо ни УНО, ни Нано.
Металлический корпус - как защита, от наводок - так понимаю.
Дисплей (тем более с тачем) - нужен в удобном для подхода месте. То есть - метров 5 от модулей реле, через стену.
Поэтому мне не совсем понятно, где тогда располагать “металлический ящик с Mega и дисплеем-тачскрин”.
Ну а вообще - у меня такое чувство, что я тут уже всех “достал”. Прошу прощения. Вопросов, вроде бы - пока нет. Определился - что мне надо запустить на цикл опрос-ответ пока что имеющееся оборудование (Mega-nano). Вроде в голове имею представление, что хочу и как добиваться - но что-то так тяжело у меня пишется… по вечерам сажусь за комп и долго втыкаю в пару строк.
Вот так пока для Mega на черновике получается
Спойлер
/*
ПРОГРАММА ДЛЯ КОНТРОЛЛЕРА MEGA
*/
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
// ===================================================
// 1. НАСТРОЙКИ ДИСПЛЕЯ
// ===================================================
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4
// ===================================================
// 2. ЦВЕТА
// ===================================================
#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 DARKGREY 0x7BEF
#define DARKGREEN 0x0C80
// ===================================================
// 4. ПЕРЕМЕННЫЕ
// ===================================================
uint8_t kindDisplay = 1;
uint8_t kindDisplayPrev = 1;
uint16_t mistakes = 0;
//бит 0 - ошибка CRC при передаче данных от Mega к nano, менее нескольких раз подряд
//бит 1 - ошибка CRC при передаче данных от Mega к nano, более нескольких раз подряд
//бит 2 - ошибка потери связи с МК Mega, менее нескольких раз подряд
//бит 3 - ошибка потери связи с МК Mega, более нескольких раз подряд
//бит 15 - ошибка CRC при передаче данных от nano к Mega, менее нескольких раз подряд
//бит 14 - ошибка CRC при передаче данных от nano к Mega, ,более нескольких раз подряд
//бит 13 - ошибка потери связи с МК nano, менее нескольких раз подряд
//бит 12 - ошибка потери связи с МК nano, более нескольких раз подряд
uint8_t mistake_15_Count;//счётчик количества ошибок подряд, mistakes, бит 15
uint8_t mistake_13_Count;//счётчик количества ошибок подряд, mistakes, бит 13
uint16_t output_from_Mega_to_nano = 0;
//0 - дизельный котёл и насос дизельного котла
//1 - ТЭН 2,5 кВт
//2 - ТЭН 7,5 кВт
//3 - шаровой кран
//4 - насос радиаторов
//5 - насос тёплых полов
//6 - вентилятор наружного блока
//7 - закрывание клапана
//8 - открывание клапана
//9 - компрессор
//10 - четырёхходовой клапан
//11 - насос пластинчатого теплообменника
uint8_t actuatorMoveTime;//время в течении которого перемещается клапан (выражено в 0, 1 сек.: 10 = 1 сек.)
uint32_t actuatorTimer;//для выдержки времени между срабатыванием клапана
//-------------- проверка работы реле ---------------
uint8_t cycleCount = 0;
//-------------- (проверка работы реле) ---------------
// Данные от nano
struct DataFromNano {
int16_t t1, t2, t3, t4, t5, t6, t7, t8, t9, t10;
uint8_t P;
uint8_t minutes, hours, days, months;
uint8_t Water;
uint8_t Electr;
uint16_t relaysState;
uint8_t mistakesFrom_nano;
uint8_t crc;
} rxData;
// Данные от UNO
struct DataFromUNO {
uint8_t Display;
} rxDataFromUNO;
// Массивы для графиков
uint8_t t1_Graph[320], t2_Graph[320], t3_Graph[320], t4_Graph[320];
uint8_t t5_Graph[320], t6_Graph[320], t7_Graph[320], t8_Graph[320];
uint8_t t9_Graph[320], t10_Graph[320];
uint8_t Water_Graph[320], Electr_Graph[320];
// ===================================================
// 5. CRC
// ===================================================
uint8_t crc8(const void* data, size_t length, uint8_t crc = 0) {
const uint8_t* p = (const uint8_t*)data;
while (length--) {
uint8_t b = *p++, j = 8;
while (j--) {
crc = ((crc ^ b) & 1) ? (crc >> 1) ^ 0x8C : (crc >> 1);
b >>= 1;
}
}
return crc;
}
// ===================================================
// 6. ПРЕОБРАЗОВАНИЕ ДЛЯ ГРАФИКОВ
// ===================================================
int16_t getDataForUintMassiv(int16_t a) {
if (a < -400) return 0;
else if (a >= -400 && a < 500) return round((a + 400) / 5);
else if (a >= 500 && a < 1250) return round(180 + (a - 500) / 10);
else return 255;
}
uint8_t getDataForUintMassiv8(uint8_t a) {
if (a <= 160) return round(40 + a);
else if (a < 255) return round(200 + (a - 160) / 10);
else return 255;
}
// ===================================================
// 7. ОТРИСОВКА ГРАФИКОВ
// ===================================================
void getGraphics(uint16_t c, uint16_t d, uint8_t g[320]) {
for (int16_t x = 1; x < 320; x++) {
tft.drawLine(x - 1, (c - g[x - 1]), x, (c - g[x]), d);
}
}
// ===================================================
// 8. ОСНОВНОЙ ЭКРАН
// ===================================================
void getMainDisplay() {
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 || i == 5 || i == 6 || i == 7 || i == 9 || i == 10)
tft.drawFastHLine(0, (5 + 20 * i), 320, DARKGREEN);
else if (i == 1 || i == 2 || i == 3 || 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.setTextSize(1);
// Подписи осей (температуры)
tft.setCursor(0, 22); tft.setTextColor(WHITE, BLACK); tft.print("90");
tft.setCursor(0, 42); tft.print("70");
tft.setCursor(0, 62); tft.print("50");
tft.setCursor(0, 82); tft.print("40");
tft.setCursor(0, 102); tft.print("30");
tft.setCursor(0, 122); tft.print("20");
tft.setCursor(0, 142); tft.print("10");
tft.setCursor(0, 162); tft.print("0");
tft.setCursor(0, 182); tft.print("-10");
tft.setCursor(0, 202); tft.print("-20");
// Подписи осей (расход/мощность)
tft.setCursor(0, 238); tft.print("5");
tft.setCursor(0, 258); tft.print("3");
tft.setCursor(0, 272); tft.print("1.6");
tft.setCursor(0, 292); tft.print("1.4");
tft.setCursor(0, 312); tft.print("1.2");
tft.setCursor(0, 332); tft.print("1");
tft.setCursor(0, 352); tft.print("0.8");
tft.setCursor(0, 372); tft.print("0.6");
tft.setCursor(0, 392); tft.print("0.4");
tft.setCursor(0, 412); tft.print("0.2");
tft.setCursor(0, 432); tft.print("0");
// Заголовки
tft.setCursor(0, 0); tft.setTextColor(RED); tft.print("Kompressor:");
tft.setCursor(10, 10); tft.setTextColor(MAGENTA); tft.print("Overheat:");
tft.setCursor(125, 10); tft.setTextColor(CYAN); tft.print("Defrost:");
tft.setCursor(220, 10); tft.setTextColor(RED); tft.print("Isparitel:");
tft.setCursor(120, 0); tft.setTextColor(YELLOW); tft.print("Water in:");
tft.setCursor(220, 0); tft.setTextColor(GREEN); tft.print("Water out:");
tft.setCursor(5, 210); tft.setTextColor(RED); tft.print("Heat power:");
tft.setCursor(152, 210); tft.setTextColor(YELLOW); tft.print("COP:");
tft.setCursor(218, 210); tft.setTextColor(GREEN); tft.print("Electr pow:");
tft.setCursor(22, 220); tft.setTextColor(MAGENTA); tft.print("G water:");
}
// ===================================================
// 9. ТЕКСТОВЫЙ РЕЖИМ
// ===================================================
void getAllLastDataToDisplay() {
tft.fillScreen(BLACK);
tft.setTextSize(1);
tft.setTextColor(YELLOW);
tft.setCursor(0, 0); tft.print("tRoom: "); tft.print(rxData.t1 / 10.0); tft.print(" C");
tft.setCursor(0, 10); tft.print("tGS: "); tft.print(rxData.t2 / 10.0); tft.print(" C");
tft.setCursor(0, 20); tft.print("tBA: "); tft.print(rxData.t3 / 10.0); tft.print(" C");
tft.setCursor(0, 30); tft.print("tOutdoor: "); tft.print(rxData.t4 / 10.0); tft.print(" C");
tft.setCursor(0, 40); tft.print("tKompressorOut: "); tft.print(rxData.t5 / 10.0); tft.print(" C");
tft.setCursor(0, 50); tft.print("tWaterIn: "); tft.print(rxData.t6 / 10.0); tft.print(" C");
tft.setCursor(0, 60); tft.print("tWaterOut: "); tft.print(rxData.t7 / 10.0); tft.print(" C");
tft.setCursor(0, 70); tft.print("tKompressorIn: "); tft.print(rxData.t8 / 10.0); tft.print(" C");
tft.setCursor(0, 80); tft.print("tDefrost: "); tft.print(rxData.t9 / 10.0); tft.print(" C");
tft.setCursor(0, 90); tft.print("tEvaporator: "); tft.print(rxData.t10 / 10.0); tft.print(" C");
tft.setCursor(0, 100); tft.print("Pressure: ");
if (rxData.P == 1) tft.print("OK");
else if (rxData.P == 2) tft.print("HIGH");
else tft.print("LOW");
tft.setCursor(0, 110); tft.print("Time: "); tft.print(rxData.hours); tft.print(":"); tft.print(rxData.minutes);
tft.setCursor(0, 120); tft.print("Date: "); tft.print(rxData.days); tft.print("."); tft.print(rxData.months);
tft.setCursor(0, 130); tft.print("Water flow: "); tft.print(rxData.Water / 100.0); tft.print(" m3/h");
tft.setCursor(0, 140); tft.print("Power: "); tft.print(rxData.Electr / 100.0); tft.print(" W");
tft.setCursor(0, 150); tft.print("Relays: "); tft.print(rxData.relaysState, BIN);
tft.setCursor(0, 160); tft.print("Mistakes "); tft.print(mistakes, BIN);
}
// ===================================================
// 10. ОТОБРАЖЕНИЕ ОШИБОК
// ===================================================
void showMistakes() {
tft.fillScreen(BLACK);
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor(0, 80);
tft.print("❌ ERROR");
tft.setCursor(0, 120);
tft.setTextSize(1);
if (bitRead(mistakes, 0) == HIGH)
tft.println("CRC error from Mega");
if (bitRead(mistakes, 1) == HIGH)
tft.println("Stop: CRC error from Mega");
if (bitRead(mistakes, 2) == HIGH)
tft.println("Connection from Mega to nano LOST!");
if (bitRead(mistakes, 3) == HIGH)
tft.println("Stop: connection from Mega to nano LOST!");
if (bitRead(mistakes, 15) == HIGH)
tft.println("CRC error from nano");
if (bitRead(mistakes, 14) == HIGH)
tft.println("Stop: CRC error from nano");
if (bitRead(mistakes, 13) == HIGH)
tft.println("Connection from nano to Mega LOST!");
if (bitRead(mistakes, 12) == HIGH)
tft.println("Stop: connection from nano to Mega LOST!");
else if (bitRead(mistakes, 0) == LOW and bitRead(mistakes, 1) == LOW and bitRead(mistakes, 2) == LOW and bitRead(mistakes, 3) == LOW and bitRead(mistakes, 15) == LOW and bitRead(mistakes, 14) == LOW and bitRead(mistakes, 13) == LOW and bitRead(mistakes, 12) == LOW)
tft.println("Unknown error");
}
// ===================================================
// 11. ОТПРАВКА ПАРАМЕТРОВ НА NANO
// ===================================================
void sendParamsToNano() {
struct ParamsToNano {
uint16_t output_from_Mega_to_nano;
uint8_t actuatorMoveTime;
uint8_t crc;
} params;
params.output_from_Mega_to_nano = output_from_Mega_to_nano;
params.actuatorMoveTime = actuatorMoveTime;
params.crc = crc8(¶ms, sizeof(params) - 1);
Serial1.write((uint8_t*)¶ms, sizeof(params));
}
// ===================================================
// 14. ФОРМИРОВАНИЕ КОМАНДЫ РЕГУЛИРУЮЩЕМУ КЛАПАНУ
// ===================================================
void actuatorMove(String a, uint8_t b)
{
if (millis() - actuatorTimer > 15000)//если после предыдущего перемещения клапана прошло время
{
if (a == "DOWN")
bitSet(output_from_Mega_to_nano, 7);//закрывать регулирующий клапан
else if (a == "UP")
bitSet(output_from_Mega_to_nano, 8);//открывать регулирующий клапан
actuatorMoveTime = b;
actuatorTimer = millis();
}
}
// ===================================================
// 13. ФИКСАЦИЯ ОШИБОК ОТ nano
// ===================================================
void updateMistakes()
{
if (bitRead(rxData.mistakesFrom_nano, 0) == HIGH)
bitSet(mistakes, 0);
else if (bitRead(rxData.mistakesFrom_nano, 0) == LOW)
bitClear(mistakes, 0);
if (bitRead(rxData.mistakesFrom_nano, 1) == HIGH)
bitSet(mistakes, 1);
else if (bitRead(rxData.mistakesFrom_nano, 1) == LOW)
bitClear(mistakes, 1);
if (bitRead(rxData.mistakesFrom_nano, 2) == HIGH)
bitSet(mistakes, 2);
else if (bitRead(rxData.mistakesFrom_nano, 2) == LOW)
bitClear(mistakes, 2);
if (bitRead(rxData.mistakesFrom_nano, 3) == HIGH)
bitSet(mistakes, 3);
else if (bitRead(rxData.mistakesFrom_nano, 3) == LOW)
bitClear(mistakes, 3);
}
// ===================================================
// 13. СМЕНА ИЗОБРАЖЕНИЯ НА ДИСПЛЕЕ
// ===================================================
void selectDisplay()
{
if (kindDisplay != kindDisplayPrev)
{
if (kindDisplay == 1)
getAllLastDataToDisplay();
kindDisplayPrev = kindDisplay;
}
}
// ===================================================
// 13. ОБНОВЛЕНИЕ МАССИВОВ ДЛЯ ГРАФИКОВ
// ===================================================
void updateArrays() {
for (int i = 0; i < 319; i++) {
t1_Graph[i] = t1_Graph[i + 1];
t2_Graph[i] = t2_Graph[i + 1];
t3_Graph[i] = t3_Graph[i + 1];
t4_Graph[i] = t4_Graph[i + 1];
t5_Graph[i] = t5_Graph[i + 1];
t6_Graph[i] = t6_Graph[i + 1];
t7_Graph[i] = t7_Graph[i + 1];
t8_Graph[i] = t8_Graph[i + 1];
t9_Graph[i] = t9_Graph[i + 1];
t10_Graph[i] = t10_Graph[i + 1];
Water_Graph[i] = Water_Graph[i + 1];
Electr_Graph[i] = Electr_Graph[i + 1];
}
t1_Graph[319] = getDataForUintMassiv(rxData.t1);
t2_Graph[319] = getDataForUintMassiv(rxData.t2);
t3_Graph[319] = getDataForUintMassiv(rxData.t3);
t4_Graph[319] = getDataForUintMassiv(rxData.t4);
t5_Graph[319] = getDataForUintMassiv(rxData.t5);
t6_Graph[319] = getDataForUintMassiv(rxData.t6);
t7_Graph[319] = getDataForUintMassiv(rxData.t7);
t8_Graph[319] = getDataForUintMassiv(rxData.t8);
t9_Graph[319] = getDataForUintMassiv(rxData.t9);
t10_Graph[319] = getDataForUintMassiv(rxData.t10);
Water_Graph[319] = getDataForUintMassiv8(rxData.Water);
Electr_Graph[319] = getDataForUintMassiv8(rxData.Electr);
}
// ===================================================
// 14. НАЧАЛЬНАЯ НАСТРОЙКА
// ===================================================
void setup() {
Serial.begin(9600);
Serial1.begin(9600); // Связь с nano
Serial2.begin(9600); // Связь с UNO
// === Настройка дисплея ===
tft.reset();
tft.begin(38022);
tft.invertDisplay(true);
// === Инициализация графиков ===
for (int i = 0; i < 320; i++) {
t1_Graph[i] = t2_Graph[i] = t3_Graph[i] = t4_Graph[i] = 80;
t5_Graph[i] = t6_Graph[i] = t7_Graph[i] = t8_Graph[i] = 80;
t9_Graph[i] = t10_Graph[i] = 80;
Water_Graph[i] = Electr_Graph[i] = 40;
}
delay(1000);
getMainDisplay();
// Отправляем начальные параметры
delay(500);
sendParamsToNano();
}
// ===================================================
// 15. ГЛАВНЫЙ ЦИКЛ
// ===================================================
void loop() {
static uint32_t lastGet = 0;//для исчисления времени последних полученных данных
selectDisplay();//моментальная смена изображения на дисплее
// === 1. Приём данных от UNO ===
if (Serial2.available()) {
DataFromUNO window;
if (Serial2.readBytes((uint8_t*)&window, sizeof(window))) {
rxDataFromUNO = window;
kindDisplay = rxDataFromUNO.Display;
}
}
// === 2. Приём данных от nano ===
if (Serial1.available()) {
DataFromNano temp;
if (Serial1.readBytes((uint8_t*)&temp, sizeof(temp))) {
uint8_t crc = crc8(&temp, sizeof(temp));
if (crc == 0) {
rxData = temp;
updateArrays();
updateMistakes();
bitClear(mistakes, 15);//снять ошибку передачи данных от nano к Mega
mistake_15_Count = 0;
// === 3. Отображение ===
if (mistakes > 0)
showMistakes;
else {
if (kindDisplay == 1) {
getAllLastDataToDisplay();
} else {
getMainDisplay();
getGraphics(245, RED, t1_Graph);
getGraphics(245, YELLOW, t2_Graph);
getGraphics(245, GREEN, t3_Graph);
getGraphics(245, MAGENTA, t4_Graph);
getGraphics(245, CYAN, t5_Graph);
getGraphics(245, RED, t6_Graph);
getGraphics(245, YELLOW, t7_Graph);
getGraphics(245, GREEN, t8_Graph);
getGraphics(245, MAGENTA, t9_Graph);
getGraphics(245, CYAN, t10_Graph);
getGraphics(475, RED, Water_Graph);
getGraphics(475, YELLOW, Electr_Graph);
}
}
}
else
{
bitSet(mistakes, 15);//зафиксирована ошибка передачи данных от nano к Mega
mistake_15_Count++;
if (mistake_15_Count > 3)
bitSet(mistakes, 14);//зафиксирована несколько раз подряд ошибка передачи данных от nano к Mega
showMistakes;
}
}
bitClear(mistakes, 13);
mistake_13_Count = 0;
lastGet = millis();
}
// === 4. Периодическая отправка параметров ===
if (millis() - lastGet > 5000) {//через 5 сек. после получения данных от nano
//-------------- проверка работы реле ---------------
cycleCount++;
if (cycleCount > 24)
bitSet(output_from_Mega_to_nano, 0); //включить дизельный котёл и насос дизельного котла
if (cycleCount > 22)
bitSet(output_from_Mega_to_nano, 1);//включить ТЭН 2,5 кВт
if (cycleCount > 20)
bitSet(output_from_Mega_to_nano, 2);//включить ТЭН 7,5 кВт
if (cycleCount > 18)
bitSet(output_from_Mega_to_nano, 3);//открыть шаровой кран
if (cycleCount == 17)
actuatorMove("DOWN", 20);
else
bitClear(output_from_Mega_to_nano, 7);
if (cycleCount == 15)
actuatorMove("UP", 20);
else
bitClear(output_from_Mega_to_nano, 8);
if (cycleCount > 12)
bitSet(output_from_Mega_to_nano, 6);//включить вентилятор наружного блока
if (cycleCount > 10)
bitSet(output_from_Mega_to_nano, 4);//включить насос радиаторов
if (cycleCount > 8)
bitSet(output_from_Mega_to_nano, 5);//включить насос тёплых полов
//if (cycleCount > 6)
//bitSet(output_from_Mega_to_nano, 9);//включить компрессор
//if (cycleCount > 4)
//bitSet(output_from_Mega_to_nano, 10);//включить четырёхходовый клапан
if (cycleCount > 2)
bitSet(output_from_Mega_to_nano, 11);//включить насос пластинчатого теплообменника
if (cycleCount > 26)
{
cycleCount = 0;
output_from_Mega_to_nano = 0b0000000000000000;
}
//-------------- (проверка работы реле) ---------------
sendParamsToNano();
}
// === 5. Фиксация потери связи ===
if (millis() - lastGet > 15000) {//если в течение 15 сек. не было связи с nano
{
bitSet(mistakes, 13);//зафиксирована потеря связи с nano
mistake_13_Count++;
lastGet = millis();//попытка связи с nano
if (mistake_13_Count > 3)
{
bitSet(mistakes, 12);//зафиксирована продолжительная потеря связи с nano
output_from_Mega_to_nano = 0; //аварийный останов
}
showMistakes;
}
}
}
Код на МК ещё не проверял.
За основу брал - предложение от BABOS из сообщения 612.
Чувствую - что с помощью ИИ, наверное, это делается легко и просто у других. Я же - пока так, пытаюсь, как могу.
Ну, явно же будет меньше чем Uno+Nano+Mega ![]()
Провода и монтаж будет стоить дороже чем модульное решение.
Для единичного то изделия это конечно важно ![]()
А вааще стоимость ESP будет явно выше чем провод данных/управления/питания учитывая, что силовые там по-любому должны быть.
Судя по подходу - доработка будет сразу после первого удачного варианта.
Я не люблю, когда потом сложно ремонтировать. Поэтом свечи просто закручиваю свечным ключом, и не использую эпоксидный клей и сварку для надежности.
Стопудово ![]()
