Что это такое?

Предполагаю, что в некоторые моменты строка содержит более 20 символов.

Попробуйте поменять местами экраны. Поставте глючный экран первым в коде.

Доберусь до компа, покажу код… Он там до того простой. Выводятся литералы… именно на них глючит. А вот динамические данные норм. Но это ни о чем не говорит пока…

мысль понял. Могу для выявления этого момента сделать отдельную переменную, в которой хранить максимальный strlen(str) из функции LCDPrint()
и выводить ее куда-нибудь например на созданный для этого еще один экран. Наверное это и

и это тоже могу попробовать без проблем… Осталось только найти время, добраться до компа сделать ответвленную версию программы и дождаться глюка) Но я это обязательно попробую. Спасибо Вам за наводку

если это на ардуине, проще в Serial наверно.

На ардуине. Я имел ввиду экран отображения а не физический экран.
Про сериал говорил выше - это не удобно сделать на рабочем устройстве. Оставлять соединение по сериал на непонятно какое время… Все же проще на экран вывести.

Спойлер
#pragma once

uint16_t tmr1, PERIOD;
void UpdLCD() {
  uint16_t ms = millis();
  if ((uint16_t)(ms - tmr1) >= PERIOD) {
    FlashParam = !FlashParam;
    if (FlashParam && editParam) PERIOD = 200;
    else PERIOD = 500;
    UpdateScreenData();
    tmr1 = ms;
  }
}

char *CorrectLengthStr(char *_str, const uint8_t _ln) {
  if (_ln) {
    for (byte n = strlen(_str); n < _ln; n++) _str[n] = ' ';
    _str[_ln] = 0;
  }
  return _str;
}

char *GetTimeStr(char *_str) {
  sprintf(_str, "%02d%s%02d", GetHour(), (isFlash ? ":" : " "), GetMinute());
  return _str;
}

char *GetLowBarStr(const uint8_t _np, char *_str) {
  if (Pump[_np].isCritLowPress) strcpy(_str, "*");
  else if (Pump[_np].isLowPress) (FlashParam ? strcpy(_str, "*") : strcpy(_str, " "));
  else strcpy(_str, " ");
  return _str;
}

char *WorkTimeToStr(const uint32_t i, char *_str) {
  if (i == 0) return strcpy(_str, "-NoData-");
  int d = (i / 3600ul) / 24ul;
  int h = (i / 3600ul) % 24ul;
  int m = (i % 3600ul) / 60ul;
  int s = (i % 3600ul) % 60ul;
  if (!d) sprintf(_str, "%d:%02d:%02ds", h, m, s);
  else {
    if (i > 63072000) sprintf(_str, ">2y.%0d:%02d:%02ds", h, m, s);
    else sprintf(_str, "%d.%0d:%02d:%02ds", d, h, m, s);
  }
  return _str;
}

char *IntToStr(const long _N, char *_str, const uint8_t _ln = 0, const char *_fmt = "%d") {
  sprintf(_str, _fmt, _N);
  return CorrectLengthStr(_str, _ln);
}

char *GetBarFromRawStr(const uint16_t _raw, char *_str, const uint8_t _ln = 0, const char *_pfx = "") {
  if (!_raw) strcpy(_str, "Err");
  else {
    uint8_t bar = RawToBar10(_raw);
    sprintf(_str, "%d.%d%s", bar / 10, bar % 10, _pfx);
  }
  CorrectLengthStr(_str, _ln);
  return _str;
}

char *GetBarStr(const uint8_t _bar, char *_str, const uint8_t _ln = 0, const char *_pfx = "") {
  sprintf(_str, "%d.%d%s", _bar / 10, _bar % 10, _pfx);
  return CorrectLengthStr(_str, _ln);
}

char *GetCurrentStr(const uint16_t _curr, char *_str, const uint8_t _ln = 0, const char *_pfx = "") {
  sprintf(_str, "%d.%03d", _curr / 1000, _curr % 1000);
  CorrectLengthStr(_str, _ln - strlen(_pfx));
  return strcat(_str, _pfx);
}

char *GetTempStr(const int _temp, char *_str, const uint8_t _ln = 0, const char *_pfx = "") {
  if (_temp > 9000) strcpy(_str, "Err");
  else sprintf(_str, "%2d.%d%s", _temp / 10, _temp % 10, _pfx);
  return CorrectLengthStr(_str, _ln);
}

char *BoolToStr(const bool _f, char *_str, const uint8_t _ln = 0) {
  if (_f) return CorrectLengthStr(strcpy(_str, "On"), _ln);
  else return CorrectLengthStr(strcpy(_str, "Off"), _ln);
}

void LCDPrint(const byte x, const byte y, const char *_str) {
  test = max(test, strlen(_str)); //временно для проверки максимальной длинны строки
  lcd.setCursor(x, y);
  lcd.print(_str);
}

void UpdateScreen() {
  switch (modeScreen) {
    case ViewMode:
      switch (ViewScreenIndex) {
        case vScr0:
          lcd.clear();
          Pump[0].Enable ? LCDPrint(8, 0, "Pump1") : LCDPrint(8, 0, "-Dis-");
          Pump[1].Enable ? LCDPrint(14, 0, "Pump2") : LCDPrint(14, 0, "-Dis-");
          LCDPrint(0, 1, "Pres(B):");
          LCDPrint(0, 2, "Curr(A):");
          LCDPrint(0, 3, "Counter:");
          break;
        case vScr1:
          lcd.clear();
          Pump[0].Enable ? LCDPrint(0, 0, "P1:") : LCDPrint(0, 0, "--:");
          Pump[1].Enable ? LCDPrint(0, 1, "P2:") : LCDPrint(0, 1, "--:");
          LCDPrint(0, 2, "Ht:");
          break;
        case vScr2:
          lcd.clear();
          if (SubScreen == 0)
            LCDPrint(3, 0, "TIMES WORK DAY");
          else LCDPrint(0, 0, "TIMES WORK ALL (   )");
          LCDPrint(0, 1, "Pump1:");
          LCDPrint(0, 2, "Pump2:");
          LCDPrint(0, 3, "Heatr:");
          break;
        case vScr3:
          lcd.clear();
          if (SubScreen == 0) {
            LCDPrint(2, 0, "CODE ERROR PUMP");
            LCDPrint(0, 1, "PUMP1:");
            LCDPrint(0, 2, "PUMP2:");
          } else {
            LCDPrint(5, 0, "ERROR COUNT");
            LCDPrint(0, 1, "P1:");
            LCDPrint(10, 1, "P2:");
            LCDPrint(0, 2, "C1:");
            LCDPrint(10, 2, "C2:");
            LCDPrint(0, 3, "Ts:");
            LCDPrint(10, 3, "CT:");
          }
          break;
        case vScr4:
          lcd.clear();
          switch (SubScreen) {
            case 0:
              lcd.print("Tm:");
              LCDPrint(10, 0, "Vcc:");
              Pump[0].Enable ? LCDPrint(6, 1, "Pump1") : LCDPrint(6, 1, "-Dis-");
              Pump[1].Enable ? LCDPrint(13, 1, "Pump2") : LCDPrint(13, 1, "-Dis-");
              LCDPrint(1, 2, "Raw:");
              LCDPrint(0, 3, "Curr:");
              break;
            case 1:
              LCDPrint(0, 0, "Cur");
              LCDPrint(4, 0, "RL1");
              LCDPrint(10, 0, "RL2");
              LCDPrint(16, 0, "RL3");
              LCDPrint(0, 1, "S:");
              LCDPrint(0, 2, "C:");
              LCDPrint(0, 3, "E:");
          }
          break;
        case vScr5: //Этот экран добавлен для выводы максимальной длинны строки в LCDPrint'e
          lcd.clear();
          lcd.print(test);
          break;
      }
      break;
    case SysMode:
      switch (SysScreenIndex) {
        case sScr0:
          lcd.clear();
          LCDPrint(0, 0, "SETTINGS");
          LCDPrint(8, 1, "P1");
          LCDPrint(15, 1, "P2");

          LCDPrint(1, 2, "ON:");
          LCDPrint(0, 3, "OFF:");
          break;
        case sScr1:
          lcd.clear();
          LCDPrint(0, 0, "SETLOWBAR  P1   P2");
          LCDPrint(1, 1, "LOW BAR:");
          LCDPrint(0, 2, "CRIT BAR:");
          LCDPrint(0, 3, "TRY TIME:");
          break;
        case sScr2:
          lcd.clear();
          LCDPrint(3, 0, "SETTINGS HEAT");
          LCDPrint(2, 1, "ENABLE:");
          LCDPrint(1, 2, "TEMP ON:");
          LCDPrint(0, 3, "TEMP OFF:");
          break;
        case sScr3:
          lcd.clear();
          LCDPrint(4, 0, "START SYSTEM");
          LCDPrint(1, 1, "PUMP1:");
          LCDPrint(1, 2, "PUMP2:");
          break;
      }
  }
}

void UpdScrDt0(char *str) {
  LCDPrint(1, 0, GetTimeStr(str));
  LCDPrint(8, 1, GetLowBarStr(0, str));
  LCDPrint(9, 1, GetBarFromRawStr(Pump[0].Sens.Raw, str, 4));
  LCDPrint(14, 1, GetLowBarStr(1, str));
  LCDPrint(15, 1, GetBarFromRawStr(Pump[1].Sens.Raw, str, 4));
  if (Pump[0].Error.Code) LCDPrint(9, 2, CorrectLengthStr(strcpy(str, "Err"), 5));
  else LCDPrint(9, 2, Pump[0].Relay.State ? GetCurrentStr(Pump[0].Relay.Curr, str, 5, "A") : CorrectLengthStr(strcpy(str, "Off"), 5));
  if (Pump[1].Error.Code) LCDPrint(15, 2, CorrectLengthStr(strcpy(str, "Err"), 5));
  else LCDPrint(15, 2, Pump[1].Relay.State ? GetCurrentStr(Pump[1].Relay.Curr, str, 5, "A") : CorrectLengthStr(strcpy(str, "Off"), 5));
  LCDPrint(9, 3, IntToStr(Pump[0].Relay.Cnt, str, 4));
  LCDPrint(15, 3, IntToStr(Pump[1].Relay.Cnt, str, 4));
  switch (editParam) {
    case 0:
      LCDPrint(8, 2, " ");
      LCDPrint(14, 2, " ");
      break;
    case 1:
      LCDPrint(8, 2, ">");
      LCDPrint(14, 2, " ");
      break;
    case 2:
      LCDPrint(8, 2, " ");
      LCDPrint(14, 2, ">");
      break;
  }
}

void UpdScrDt1(char *str) {
  LCDPrint(3, 0, GetLowBarStr(0, str));
  LCDPrint(4, 0, GetBarFromRawStr(Pump[0].Sens.Raw, str, 4));
  LCDPrint(3, 1, GetLowBarStr(1, str));
  LCDPrint(4, 1, GetBarFromRawStr(Pump[1].Sens.Raw, str, 4));
  if (Pump[0].Error.Code) LCDPrint(10, 0, CorrectLengthStr(strcpy(str, "Err"), 5));
  else LCDPrint(10, 0, Pump[0].Relay.State ? GetCurrentStr(Pump[0].Relay.Curr, str, 5, "A") : CorrectLengthStr(strcpy(str, "Off"), 5));
  if (Pump[1].Error.Code) LCDPrint(10, 1, CorrectLengthStr(strcpy(str, "Err"), 5));
  else LCDPrint(10, 1, Pump[1].Relay.State ? GetCurrentStr(Pump[1].Relay.Curr, str, 5, "A") : CorrectLengthStr(strcpy(str, "Off"), 5));
  LCDPrint(16, 0, IntToStr(Pump[0].Relay.Cnt, str, 4, "%4d"));
  LCDPrint(16, 1, IntToStr(Pump[1].Relay.Cnt, str, 4, "%4d"));
  LCDPrint(3, 2, GetTempStr(Heat.T, str, 6, "\1C"));
  LCDPrint(10, 2, Heat.Enable ? (Heat.Relay.State ? GetCurrentStr(Heat.Relay.Curr, str, 5, "A") : CorrectLengthStr(strcpy(str, "Off"), 5)) : "Dis");
  LCDPrint(16, 2, IntToStr(Heat.Relay.Cnt, str, 4, "%4d"));
  LCDPrint(1, 3, GetTempStr(Heat.t1, str, 4));
  LCDPrint(6, 3, GetTempStr(Heat.t2, str, 4));
  LCDPrint(11, 3, GetTempStr(Heat.t3, str, 4));
  LCDPrint(16, 3, GetTempStr(Heat.t4, str, 4));
    switch (editParam) {
    case 0:
      LCDPrint(9, 0, " ");
      LCDPrint(9, 1, " ");
      break;
    case 1:
      LCDPrint(9, 0, ">");
      LCDPrint(9, 1, " ");
      break;
    case 2:
      LCDPrint(9, 0, " ");
      LCDPrint(9, 1, ">");
      break;
  }
}

void UpdScrDt2(char *str) {
  if (SubScreen == 0) {
    LCDPrint(7, 1, WorkTimeToStr(Pump[0].Relay.workTimes + Pump[0].Relay.workTime, str));
    LCDPrint(7, 2, WorkTimeToStr(Pump[1].Relay.workTimes + Pump[1].Relay.workTime, str));
    LCDPrint(7, 3, WorkTimeToStr(Heat.Relay.workTimes + Heat.Relay.workTime, str));
  } else {
    LCDPrint(16, 0, IntToStr(ResetDayCount, str, 3, "%3d"));
    LCDPrint(7, 1, WorkTimeToStr(Pump[0].Relay.workTimesAll + Pump[0].Relay.workTimes + Pump[0].Relay.workTime, str));
    LCDPrint(7, 2, WorkTimeToStr(Pump[1].Relay.workTimesAll + Pump[1].Relay.workTimes + Pump[1].Relay.workTime, str));
    LCDPrint(7, 3, WorkTimeToStr(Heat.Relay.workTimesAll + Heat.Relay.workTimes + Heat.Relay.workTime, str));
  }
}

void UpdScrDt3(char *str) {
  if (SubScreen == 0) {
    LCDPrint(7, 1, IntToStr(Pump[0].Error.Code, str, 4));
    LCDPrint(9, 1, CorrectLengthStr(strcpy(str, codeErrStr[Pump[0].Error.Code]), 11));
    LCDPrint(7, 2, IntToStr(Pump[1].Error.Code, str, 4));
    LCDPrint(9, 2, CorrectLengthStr(strcpy(str, codeErrStr[Pump[1].Error.Code]), 11));
    if (Pump[0].Error.Code > 0 || Pump[1].Error.Code > 0)
      LCDPrint(0, 3, "Press Long But Reset");
    else LCDPrint(0, 3, CorrectLengthStr(strcpy(str, " "), 20));
  } else {
    Pump[0].Sens.Err ? LCDPrint(3, 1, "*") : LCDPrint(3, 1, " ");
    LCDPrint(4, 1, IntToStr(Pump[0].Sens.ErrCnt, str, 4));
    Pump[1].Sens.Err ? LCDPrint(13, 1, "*") : LCDPrint(13, 1, " ");
    LCDPrint(14, 1, IntToStr(Pump[1].Sens.ErrCnt, str, 4));
    Pump[0].Relay.Err ? LCDPrint(3, 2, "*") : LCDPrint(3, 2, " ");
    LCDPrint(4, 2, IntToStr(Pump[0].Relay.ErrCnt, str, 4));
    Pump[1].Relay.Err ? LCDPrint(13, 2, "*") : LCDPrint(13, 2, " ");
    LCDPrint(14, 2, IntToStr(Pump[1].Relay.ErrCnt, str, 4));
    Heat.Err ? LCDPrint(3, 3, "*") : LCDPrint(3, 3, " ");
    LCDPrint(4, 3, IntToStr(Heat.ErrCnt, str, 4));
    Heat.Relay.Err ? LCDPrint(13, 3, "*") : LCDPrint(13, 3, " ");
    LCDPrint(14, 3, IntToStr(Heat.Relay.ErrCnt, str, 4));
  }
}

void UpdScrDt4(char *str) {
  switch (SubScreen) {
    case 0:
      LCDPrint(4, 0, GetTimeStr(str));
      lcd.setCursor(15, 0);
      lcd.print(analogRead_VCC());
      lcd.print("v");
      LCDPrint(7, 2, IntToStr(Pump[0].Sens.Raw, str, 3));
      LCDPrint(14, 2, IntToStr(Pump[1].Sens.Raw, str, 3));
      LCDPrint(6, 3, GetCurrentStr(Pump[0].Relay.Curr, str, 5));
      LCDPrint(13, 3, GetCurrentStr(Pump[1].Relay.Curr, str, 5));
      break;
    case 1:
      LCDPrint(3, 1, GetCurrentStr(Pump[0].Relay.StartCurr, str, 5));
      LCDPrint(9, 1, GetCurrentStr(Pump[1].Relay.StartCurr, str, 5));
      LCDPrint(15, 1, GetCurrentStr(Heat.Relay.StartCurr, str, 5));
      LCDPrint(3, 2, GetCurrentStr(Pump[0].Relay.Curr, str, 5));
      LCDPrint(9, 2, GetCurrentStr(Pump[1].Relay.Curr, str, 5));
      LCDPrint(15, 2, GetCurrentStr(Heat.Relay.Curr, str, 5));
      LCDPrint(3, 3, Pump[0].Relay.ErrCnt ? GetCurrentStr(Pump[0].Relay.ErrorCurr, str, 5) : CorrectLengthStr(strcpy(str, "noErr"), 5));
      LCDPrint(9, 3, Pump[1].Relay.ErrCnt ? GetCurrentStr(Pump[1].Relay.ErrorCurr, str, 5) : CorrectLengthStr(strcpy(str, "noErr"), 5));
      LCDPrint(15, 3, Heat.Relay.ErrCnt ? GetCurrentStr(Heat.Relay.ErrorCurr, str, 5) : CorrectLengthStr(strcpy(str, "noErr"), 5));
      break;
  }
}

void UpdateScreenData() {
  switch (modeScreen) {
    char str[20];
    case ViewMode:
      switch (ViewScreenIndex) {
        case vScr0:
          UpdScrDt0(str);
          break;
        case vScr1:
          UpdScrDt1(str);
          break;
        case vScr2:
          UpdScrDt2(str);
          break;
        case vScr3:
          UpdScrDt3(str);
          break;
        case vScr4:
          UpdScrDt4(str);
          break;
      }
      break;
    case SysMode:
      switch (SysScreenIndex) {
        case sScr0:
          LCDPrint(7, 2, editParam == 1 && FlashParam ? "   " : editParam > 0 ? GetBarStr(Pump[0].PBarOnEd, str, 3)
                                                                              : GetBarFromRawStr(Pump[0].PRawOn, str, 3));
          LCDPrint(7, 3, editParam == 2 && FlashParam ? "   " : editParam > 0 ? GetBarStr(Pump[0].PBarOffEd, str, 3)
                                                                              : GetBarFromRawStr(Pump[0].PRawOff, str, 3));
          LCDPrint(15, 2, editParam == 3 && FlashParam ? "   " : editParam > 0 ? GetBarStr(Pump[1].PBarOnEd, str, 3)
                                                                               : GetBarFromRawStr(Pump[1].PRawOn, str, 3));
          LCDPrint(15, 3, editParam == 4 && FlashParam ? "   " : editParam > 0 ? GetBarStr(Pump[1].PBarOffEd, str, 3)
                                                                               : GetBarFromRawStr(Pump[1].PRawOff, str, 3));
          LCDPrint(17, 0, editParam == 5 && FlashParam ? "   " : editParam > 0 ? IntToStr(SecCorMsEd, str, 3, "%+2d")
                                                                               : IntToStr(SecondCorMs, str, 3, "%+2d"));
          lcd.setCursor(10, 0);
          if (editParam < 6) {
            LCDPrint(10, 0, GetTimeStr(str));
          } else {
            if (editParam == 6) {
              if (FlashParam) lcd.print("  ");
              else {
                sprintf(str, "%02d", HourEd);
                lcd.print(str);
              }
              sprintf(str, ":%02d", MinuteEd);
              lcd.print(str);
            }
            if (editParam == 7) {
              sprintf(str, "%02d:", HourEd);
              lcd.print(str);
              if (FlashParam) lcd.print("  ");
              else {
                sprintf(str, "%02d", MinuteEd);
                lcd.print(str);
              }
            }
          }
          break;
        case sScr1:
          LCDPrint(11, 1, editParam == 1 && FlashParam ? "    " : editParam > 0 ? GetBarStr(Pump[0].PLowBarEd, str, 3)
                                                                                : GetBarFromRawStr(Pump[0].PLowRaw, str, 3));
          LCDPrint(11, 2, editParam == 2 && FlashParam ? "    " : editParam > 0 ? GetBarStr(Pump[0].PCritLowBarEd, str, 3)
                                                                                : GetBarFromRawStr(Pump[0].PCritLowRaw, str, 3));
          LCDPrint(11, 3, editParam == 3 && FlashParam ? "    " : editParam > 0 ? IntToStr(Pump[0].TryTimeEd, str, 3)
                                                                                : IntToStr(Pump[0].TryTime, str, 3));
          LCDPrint(16, 1, editParam == 4 && FlashParam ? "    " : editParam > 0 ? GetBarStr(Pump[1].PLowBarEd, str, 3)
                                                                                : GetBarFromRawStr(Pump[1].PLowRaw, str, 3));
          LCDPrint(16, 2, editParam == 5 && FlashParam ? "    " : editParam > 0 ? GetBarStr(Pump[1].PCritLowBarEd, str, 3)
                                                                                : GetBarFromRawStr(Pump[1].PCritLowRaw, str, 3));
          LCDPrint(16, 3, editParam == 6 && FlashParam ? "    " : editParam > 0 ? IntToStr(Pump[1].TryTimeEd, str, 3)
                                                                                : IntToStr(Pump[1].TryTime, str, 3));
          break;
        case sScr2:
          LCDPrint(11, 1, editParam == 1 && FlashParam ? "    " : editParam > 0 ? BoolToStr(Heat.EnableEd, str, 3)
                                                                                : BoolToStr(Heat.Enable, str, 3));
          if (!editParam) LCDPrint(10, 2, !Heat.Enable ? "      " : GetTempStr(Heat.TOn, str, 6, "\1C"));
          else LCDPrint(10, 2, (editParam == 2 && FlashParam) ? "      " : !Heat.EnableEd ? " ---  "
                                                                                          : GetTempStr(Heat.TOnEd, str, 6, "\1C"));
          if (!editParam) LCDPrint(10, 3, !Heat.Enable ? "      " : GetTempStr(Heat.TOff, str, 6, "\1C"));
          else LCDPrint(10, 3, (editParam == 3 && FlashParam) ? "      " : !Heat.EnableEd ? " ---  "
                                                                                          : GetTempStr(Heat.TOffEd, str, 6, "\1C"));
          break;
        case sScr3:
          if (!Pump[0].Error.Code || Pump[0].Error.Code == errCritLowPress) {
            if (!Pump[0].Enable) LCDPrint(8, 1, CorrectLengthStr(strcpy(str, "Disable"), 12));
            else if (Pump[0].isStartLowBar) {
              LCDPrint(8, 1, CorrectLengthStr(strcpy(str, "Starting"), 12));
              sprintf(str, "%2lds", Pump[0].TryTime - Pump[0].Relay.workTime);
              LCDPrint(17, 1, str);
            } else if (Pump[0].isCritLowPress) LCDPrint(8, 1, CorrectLengthStr(strcpy(str, "Start"), 12));
            else if (Pump[0].isLowPress) LCDPrint(8, 1, CorrectLengthStr(strcpy(str, "Low"), 12));
            else LCDPrint(8, 1, CorrectLengthStr(strcpy(str, "Ok"), 12));
          } else LCDPrint(8, 1, CorrectLengthStr(strcpy(str, "(ERROR)"), 12));
          if (!Pump[1].Error.Code || Pump[1].Error.Code == errCritLowPress) {
            if (!Pump[1].Enable) LCDPrint(8, 2, CorrectLengthStr(strcpy(str, "Disable"), 12));
            else if (Pump[1].isStartLowBar) {
              LCDPrint(8, 2, CorrectLengthStr(strcpy(str, "Starting"), 12));
              sprintf(str, "%2lds", Pump[1].TryTime - Pump[1].Relay.workTime);
              LCDPrint(17, 2, str);
            } else if (Pump[1].isCritLowPress) LCDPrint(8, 2, CorrectLengthStr(strcpy(str, "Start"), 12));
            else if (Pump[1].isLowPress) LCDPrint(8, 2, CorrectLengthStr(strcpy(str, "Low"), 12));
            else LCDPrint(8, 2, CorrectLengthStr(strcpy(str, "Ok"), 12));
          } else LCDPrint(8, 2, CorrectLengthStr(strcpy(str, "(ERROR)"), 12));
          if (editParam == 1) {
            LCDPrint(0, 1, ">");
            LCDPrint(0, 2, " ");
            if (Pump[0].isCritLowPress || Pump[0].Error.Code) LCDPrint(1, 3, "Press Long Button");
          } else if (editParam == 2) {
            LCDPrint(0, 1, " ");
            LCDPrint(0, 2, ">");
            if (Pump[1].isCritLowPress || Pump[1].Error.Code) LCDPrint(1, 3, "Press Long Button");
          } else {
            LCDPrint(0, 1, " ");
            LCDPrint(0, 2, " ");
            LCDPrint(1, 3, "                 ");
          }
          break;
      }
      break;
  }
}

Вот собс-но файл, где происходит практически весь вывод на экран. В том числе и этот глючный экран. Вывод, как я и говорил, происходит практически весь функцией LCDPrint которая находится в строках 96-90
В нее сейчас добавил запоминание в переменную максимальную длину строки. Вывод значения этой переменной в специально созданном дополнительном экране в строках 156-159
Пока там на этом экране показывает 20
Но это сейчас в прототипе на столе… Если успею, сегодня залью в устройство и “буду ждать этого глюка”. Потом посмотрю что там будет на этом экране.
Глюк происходит на строках 126-132. Тут выводится статичная часть экрана и именно с ней проблемы отображения. Динамичные данные этого экрана в строках 282-293

ЗЫЖ Залил в устройство, экраны местами тоже поменял. Теперь осталось дождаться этого глюка

А на рабочем устройстве это и не нужно делать. Нужно делать на макете.

Дык там целая система (датчики, реле…) на рабочем… на макетке я этого не смогу повторить. Да и макетка - это получается другой экран 2004. А если это в нем дело? Сомневаюсь я конечно, больше на свой код грешу. Вот сегодня проверил устройство - пока нет глюка (больше суток работает, последний раз глюк через две недели появился). Если в файле, который я приложил выше, опытным вашим взглядом нет грубых ошибок при работе с указателями, то буду смотреть еще раз остальной свой код, но он вроде как не связан с выводом на экран, но может такое быть, что где-то в коде у меня так портится память что вывод на экран литерала LCDPrint(5, 0, “ERROR COUNT”); - выводится только ERROR а COUNT куда-то теряется?

Проработало 3-е суток. Глюк не проявился, макс длинна строки 20.
За это время пересмотрел остальной код и нашел одно место где потенциально мог выйти за границы массива:

} else {
      if (Pump[editParam - 1].Relay.State) {
        PumpOff(editParam - 1);
        editParam = 0;
        UpdateScreenData();
      } else PumpOn(editParam - 1);
    }

где editParam по идеи в этом месте всегда либо 1 либо 2, а массив Pump состоит из двух элементов. Но обратил внимание, что в “особых” случаях все-таки в editParam мог быть - 0. Это нужно извернуться, но это возможно оказалось. Скорее всего это и есть причина глюка (но это не точно :slight_smile:) Вернул код в первоначальный вид, изменив данный участок на:

} else {
      if (editParam) {
        if (Pump[editParam - 1].Relay.State) {
          PumpOff(editParam - 1);
          editParam = 0;
          UpdateScreenData();
        } else PumpOn(editParam - 1);
      }
    }

В общем работает опять три дня уже, …без глюка. Буду надеяться, что косяк исправил. (Ведь и предыдущий код мог работать долгое время нормально)

0х27

Возможно именно так и есть, очень на это надеюсь)))

Значит без буквы А в конце.

ну вы блин даете, а я заказал по ссылке выше,пришел уже, ща принесут))
и че теперь? :rage:

Распаковывать датчик какой новый, или заказывать ))

Я не утверждал что дело в LCD2004, но все может быть… Еще пока не понятно, но скорее всего все таки в коде дело…


не знаю че тами у вас, я дольше ардуиновскую доску искал)

1 лайк

Пока работает без глюка. Уже больше 10 дней непрерывно…
Я тут решил оптимизировать(модернизировать) функцию LCDPrint
Потом переделаю под нее остальной код файла работы с экраном
Вот она (точнее скетч ее теста с ссылкой на вокви):
Скетч немного отличается от того, что по ссылке (там старый)

Спойлер
//https://wokwi.com/projects/394794352265771009

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
enum TAlign {alL, alC, alR};

void LCDPrint(const byte &x, const byte &y, const char * txt,
              byte ln = 0, const TAlign &alg = alL, const char &ch = ' ') {
  if (x > 19 || y > 3) return;
  byte tln = strlen(txt);
  if (!ln) ln = tln;
  if (x + ln > 20) ln = 20 - x;
  char str[ln + 1];

  if (ln == tln) strcpy(str, txt);
  else {
    if (alg == alL) {
      if (tln > ln) {
        strncpy(str, txt, ln);
      }
      if (ln > tln) {
        strcpy(str, txt);
        for (byte n = tln; n < ln; n++) str[n] = ch;
      }
    }
    if (alg == alC) {
      if (tln > ln) {
        strncpy(str, txt + (tln / 2 - ln / 2), ln);
      }
      if (ln > tln) {
        for (byte n = 0; n < ln; n++) str[n] = ch;
        strncpy(str + (ln / 2 - tln / 2), txt, tln);
      }
    }
    if (alg == alR) {
      if (tln > ln) {
        strncpy(str, txt + tln - ln, ln);
      }
      if (ln > tln) {
        for (byte n = 0; n < ln - tln; n++) str[n] = ch;
        strcpy(str + ln - tln, txt);
      }
    }
  }
  lcd.setCursor(x, y);
  str[ln] = 0;
  lcd.print(str);
}

void setup() {
  lcd.init();
  lcd.backlight();
  LCDPrint(7, 0, "12345678901234567890111");
  LCDPrint(10, 1, "77", 7, alR, '0');
  LCDPrint(3, 2, "HRtyX12345TestLongStringUp20", 6, alC);
  LCDPrint(0, 3, "11", 20, alC, '=');
}

void loop() {
}

Вопрос, на сколько я ее сделал не/оптимально? Важна скорость ее работы.
Может кто грамотно подправит эту функцию.
Что она делает: Печатает текст в указанных координатах на LCD2004 с указанием длинны блока и с выравниванием текста в этом блоке
В ИДЕ не запускал, вот только на сайте, поэтому варнигов пока не видел(

Если важна скорость, переписывать нужно LiquidCrystal_I2C в соответствии с рекомендациями, изложенными здесь:

“Из коробки” вывод каждого символа занимает более миллисекунды (несколько десятков тысяч тактов), так что что-то оптимизировать в коде, когда все тормоза происходят из-за библиотеки, вряд ли целесообразно.

Давеча делал студенту метеостанцию. Символы в псевдографике. При выводе, сначала стираем всё, затем выводим. Это из коробки. Нормально ли? “Ну, вопрос, конечно, интересный!”)

Это на несколько литров обсуждения тянет ))

Нет, это Гайвер. Тяп-ляп, куча всего, готово.) Главное побольше, дабы не разобраться.)