Display Problem with UV Light Controller

I am working on a project to control germicidal UV lamps for decontaminating N95 masks. It is supposed to have a display of how long the box has been operating, and eventually it is supposed to have a menu to select different operating intensities. I have been having intermittent issues with the display, where it will scroll out gibberish characters (pictured). If I cycle power the issue usually goes away, but it never clears on its own. Also, the issue begins at startup so if the screen is normal it stays normal.

I have been able to achieve seemingly stable operation by tweaking the code. Since it is an intermittent issue though, I want to understand the cause so I know it will not come back.

A secondary (possibly related) issue I uncovered is I can display the timing variable (unsigned long) twice with different results (pictured). It displays the least significant byte the same, but the upper bytes seem to be scrambled. This seems to be on a bit/byte level, since it happens with DEC (by multiples of 2), HEX, and BIN.

The attached code sometimes generates the gibberish text, and consistently displays the mismatched variable. My hardware is listed below. I would really appreciate some help with this one!

Arduino UNO R3
Newhaven Display NHD-0216K1Z-FSW-FBW-L (16x2 LCD)
DFRobot Relay Shield
Adafruit VEML6070 UV Sensor Breakout
Bourns PEC11R-4020F-S0024-ND Push-button Rotary Encoder

#include <Wire.h>
#include "Adafruit_VEML6070.h"
#include <LiquidCrystal.h>
#include <ClickEncoder.h>
#include <TimerOne.h>

const int rs = 12, en = 11, d4 = 6, d5 = 5, d6 = 4, d7 = 3;
const int relay1 = 2;
const int relay2 = 7;
const int relay3 = 8;
const int relay4 = 10;
const int reedSwitch = 13; //monitors the drawer
unsigned long secondsPassed = 0; //total time since initialization
unsigned long secondsClosed = 0; //time the drawer has been closed
unsigned int uvReading = 0;
unsigned long currentTime = 0;
unsigned long loopTime = 0;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

Adafruit_VEML6070 uv = Adafruit_VEML6070();

ClickEncoder *encoder;
int16_t last, value;

void timerIsr() {
  encoder->service();
}

void setup() {
  delay(100);
  lcd.begin(16, 2);
  delay(100);
  lcd.setCursor(0, 0);
  lcd.print(F("Starting...     "));

  uv.begin(VEML6070_1_T);  // pass in the integration time constant (1T= 125ms)
  
  pinMode(relay1,OUTPUT);
  pinMode(relay2,OUTPUT);
  pinMode(relay3,OUTPUT);
  pinMode(relay4,OUTPUT);
  pinMode(reedSwitch,INPUT_PULLUP);

  Timer1.initialize(50); //Normal 1000, increased frequency for troubleshooting
  Timer1.attachInterrupt(timerIsr); 

  //The relays turn on the UV lamps. Disabled for troubleshooting
  /*digitalWrite(relay1, HIGH);
  delay(100);
  digitalWrite(relay2, HIGH);
  delay(100);
  digitalWrite(relay3, HIGH);
  delay(100);
  digitalWrite(relay4, HIGH);*/
  delay(5000);
  
  last = -1;
  currentTime = millis();
  loopTime = currentTime;
}

void loop() {
  currentTime = millis();
  
  uvReading = uv.readUV();

  if(digitalRead(reedSwitch)){
    lcd.setCursor(0, 0);  //Col, Row
    lcd.print(secondsPassed, HEX);
    lcd.print(F(" seconds on     "));
    lcd.setCursor(0, 1);  //Col, Row
    lcd.print(F("Opened, "));
    lcd.setCursor(8, 1);
    lcd.print(F("UVA: "));
    lcd.print(uvReading);
    lcd.print(F("                "));
    secondsClosed = 0;
  } else {
    lcd.setCursor(0, 0);  //Col, Row
    lcd.print(secondsPassed, BIN); //Normal void, BIN for troubleshooting
    lcd.print(F(" seconds on     "));
    lcd.setCursor(0, 1);
    lcd.print(secondsPassed, BIN); //Normally pass secondsClosed
    lcd.print(F(" s    "));
    lcd.setCursor(16, 1);
    lcd.print(F("UVA: "));
    lcd.print(uvReading);
    lcd.print(F("                "));
  }

  if(currentTime >= (loopTime + 100)) //Normal 1000. Increased speed for troubleshooting
  {
    loopTime = currentTime;
    secondsPassed++;
    secondsClosed++;
  }
  
  delay(2);
}

If anyone is interested, the gibberish characters occurs from the electromagnetic pulse of the UV lamps/ballasts turning on. I am calling LCD.begin() after starting the lamps to clear the issue. I also plan to switch to shielded cable.

The problem of a variable printing the wrong number to the screen seems to be related to the interrupts. Declaring the variable volatile fixed the problem. I'm not completely sure why, since the variable is not manipulated by any of the interrupts. I suppose the data is better protected during the LCD.print() function call, however I do not know the inner workings of volatile...

if(currentTime >= (loopTime + 200)) //Normal 1000. Increased speed for troubleshooting

I have same problem & after so many trials I got solution.

✓ connect bypass capacitor near vcc-gnd pin of lcd.

✓use all 8 data pins instead of 4 only.

✓if all above not work then send lcd.begin(16,2) command every second you never get garbage display.

✓dont forgot to use watch dog timer for ventilator application. Other wise it will heng life of patients due to motor jerk effect on Arduino

Hi,

I had the gibberish characters problem with the LCD on my UV controler and I fixed it with a diode in parallel with the relay (coil).

It's working fine since then (2 weeks)