Arduino Freezes after working for about a day!

I'm receiving some serial data over UART at a baud rate of 2400 bits/sec and displaying it in an I2C backpacked 16x2 LCD after some data manipulations. I'm posting my complete code below.

#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

int ra[7*4];                    // Stores fields in 8 bit data format [177,3,0,0,51,2,0,0,...]                   --> loop()
int rf = 0;                     // Receive Flag (Initially Set to "0")                                           --> loop()
int a,i=0;                      // Receive Variables                                                             --> loop()
int bin_array[7*32];            // Stores Binary Info of ra | Number of fields being sent * Size of Each Field   --> loop()
int dec_array[7];               // Stores Decimal Fields                                                         --> loop()

int c[8];                       // Array to store binary equivalent                                              --> bin_func()

int mode123,op_volt,freq,ip_volt,batv,fault,op_i;

const int buttonPin = 2;        // Scroll Interrupt Variables
volatile int buttonState = 0;
int count_value = 0;
long lastDebounceTime = 0; 
long debounceDelay = 250;

int d = 0;                      // Display Count Variables
int disp = 0;

int y=0;                        // RTC Flag Variables
int flag = 1;
int hour123;

byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b10001,
  0b01110,
  0b00000,
  0b00000
};

byte sad[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b01110,
  0b10001,
  0b00000,
  0b00000
};

void bin_func(int a)
{ 
  for(int i=0;i<8;i++)
  {
    if(a%2 == 0 || a%2 == 1 && a/2>=0)
    {
      if(a%2 == 1)
      {
        c[i] = 1;
        a = a/2;
      }
      else
      {
        c[i] = 0;
        a = a/2;
      }
    }
    else
    {
      c[i] = 0;
    }
  }
}

long power(int x, int y)
{
  long z=1;
  while(y>0)
  {
    z=x*z;
    y--;
  }
  return z;
}

void lcd_display()
{
  if(count_value==0)
  {
    lcd.setCursor(0,1);
    lcd.print("O/P V: "+String(op_volt/10.0)+"   ");
  }
  else if(count_value==1)
  {
    lcd.setCursor(0,1);
    lcd.print("Freq: "+String(freq/10.0)+"    ");
  }
  else if(count_value==2)
  {
    lcd.setCursor(0,1);
    lcd.print("BV: "+String(batv/10.0)+"    ");
  }
  else if(count_value==3)
  {
    lcd.setCursor(0,1);
    if(mode123==4 || mode123==6)
      lcd.print("I/P V: 000.0  ");
    else
      lcd.print("I/P V: "+String(ip_volt/10.0)+"  ");
  }
  else if(count_value==4)
  {
    lcd.setCursor(0,1);
    lcd.print("O/P I: "+String(op_i/10.0)+"    ");
  }
}

void update_fields()
{
  int ba_index = 0, sum=0, l=0;
  for(int j=0; j<28; j++)
  {
    bin_func(ra[j]);
    for(int k=0; k<8; k++)
    {
      bin_array[ba_index] = c[k];
      ba_index++;
    }
  }
  int k=0;
  for(int j=0; j<ba_index; j++)
  {
    sum+=bin_array[j]*power(2,k);
    k++;
    if((j+1)%32==0)
    {
      dec_array[l] = sum;
      l++;
      sum=0;
      k=0;
    }
  }
  mode123 = dec_array[0];
  op_volt = dec_array[1];
  freq = dec_array[2];
  ip_volt = dec_array[3];
  batv = dec_array[4];
  fault = dec_array[5];
  op_i = dec_array[6];
}

void setup() 
{
  lcd.begin();
  lcd.backlight();
  pinMode(buttonPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), pin_ISR, RISING);
  lcd.createChar(4, smiley);
  lcd.createChar(5, sad);
  pinMode(A0,OUTPUT);
  pinMode(A1,OUTPUT);
  pinMode(A2,OUTPUT);
  pinMode(A3,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  digitalWrite(7, HIGH);
  
  lcd.setCursor(0,0);
  lcd.print("   FRONTLINE    ");
  lcd.setCursor(0,1);
  lcd.print(" FSS Online UPS ");
  delay(2000);
  for(int i=0;i<16;i++)
  {
    lcd.setCursor(i,0);
    lcd.write(byte(4));
    delay(100);
  }
  for(int i=15;i>=0;i--)
  {
    lcd.setCursor(i,1);
    lcd.write(byte(4));
    delay(100);
  }
  //delay(1000);
  
  lcd.clear();
  lcd.begin();
  lcd.begin();
  Serial.begin(2400);
}

void loop() 
{
  tmElements_t tm;
  
  if(Serial.available())
  { 
    a=Serial.read();
    if(a==38)
    {
      rf = 1;
      i = 0;
    }
    else if(a==33)
    {
      rf = 0;
      i = 0;
    }
    if(rf==1 && a!=38)
    {
      ra[i] = a;
      i+=1;
    }
  }
  else
  {
    update_fields();
    if(fault==0)
    {
      if(mode123==0)
      {
        lcd.setCursor(0,0);
        lcd.print("Standby Mode   ");
        lcd.write(byte(4));
        lcd.setCursor(0,1);
        lcd.print("                ");
        digitalWrite(A0,LOW);
        digitalWrite(A1,LOW);
        digitalWrite(A2,LOW);
        digitalWrite(A3,LOW);
        digitalWrite(10,LOW);
        digitalWrite(11,LOW);
        digitalWrite(12,LOW);
        digitalWrite(13,LOW);
      }
      else if(mode123==1)
      {
        lcd.setCursor(0,0);
        lcd.print("Starting UPS   ");
        lcd.write(byte(4));
        if(d>100)
          digitalWrite(A3,HIGH);
        else if(d>200)
        {
          digitalWrite(A3,LOW);
          d=0;
        }
      }
      else if(mode123==3)
      {
        lcd.setCursor(0,0);
        lcd.print("Economy Mode   ");
        lcd.write(byte(4));
        if(disp>15)
        {
          lcd_display();
          disp=0;
        }
        digitalWrite(A0,LOW);
        digitalWrite(A1,HIGH);
        digitalWrite(A2,HIGH);
        digitalWrite(A3,HIGH);
        digitalWrite(10,LOW);
        digitalWrite(11,LOW);
        digitalWrite(12,LOW);
        digitalWrite(13,LOW);
      }
      else if(mode123==5)
      {
        lcd.setCursor(0,0);
        lcd.print("Online Mode    ");
        lcd.write(byte(4));
        if(disp>15)
        {
          lcd_display();
          disp=0;
        }
        digitalWrite(A0,LOW);
        digitalWrite(A1,HIGH);
        digitalWrite(A2,LOW);
        digitalWrite(A3,HIGH);
        digitalWrite(10,LOW);
        digitalWrite(11,LOW);
        digitalWrite(12,LOW);
        digitalWrite(13,HIGH);
      }
      else if(mode123==4)
      {
        lcd.setCursor(0,0);
        lcd.print("Battery Mode!  ");
        lcd.write(byte(4));
        if(d>10)
          digitalWrite(A0,LOW);
        if(d>100)
        {
          digitalWrite(A0,HIGH);
          d=0;
        }
        if(disp>15)
        {
          lcd_display();
          disp=0;
        }
        digitalWrite(A1,HIGH);
        digitalWrite(A2,LOW);
        digitalWrite(A3,LOW);
        digitalWrite(10,LOW);
        digitalWrite(11,HIGH);
        digitalWrite(12,LOW);
        digitalWrite(13,HIGH);
      }
      else if(mode123==2)
      {
        lcd.setCursor(0,0);
        lcd.print("Battery Mode   ");
        lcd.write(byte(4));
        lcd.setCursor(0,1);
        lcd.print("Starting UPS    ");
        digitalWrite(A0,LOW);
        digitalWrite(A2,LOW);
        digitalWrite(A3,HIGH);
        digitalWrite(10,LOW);
        digitalWrite(11,LOW);
        digitalWrite(12,LOW);
        digitalWrite(13,LOW);
        if(d>10)
          digitalWrite(A1,HIGH);
        else if(d>20)
        {
          digitalWrite(A1,LOW);
          d=0;
        }
      }
      else if(mode123==6)
      {
        lcd.setCursor(0,0);
        lcd.print("Battery Mode!  ");
        lcd.write(byte(4));
        if(d>10)
          digitalWrite(A0,LOW);
        if(d>100)
        {
          digitalWrite(A0,HIGH);
          d=0;
        }
        if(disp>15)
        {
          lcd_display();
          disp=0;
        }
        digitalWrite(A1,HIGH);
        digitalWrite(A2,LOW);
        digitalWrite(A3,LOW);
        digitalWrite(10,LOW);
        digitalWrite(11,HIGH);
        digitalWrite(12,LOW);
        digitalWrite(13,HIGH);
      }
      d=d+1;
      disp=disp+1;
    }
    else if(fault==1)
    { 
      digitalWrite(A0,HIGH);
      lcd.setCursor(0,0);
      lcd.print("Bus OV Trip    ");
      lcd.write(byte(5));
      lcd.setCursor(0,1);
      lcd.print("Reset UPS for NO");
      digitalWrite(A1,LOW);
      digitalWrite(A2,HIGH);
      digitalWrite(A3,LOW);
      digitalWrite(10,HIGH);
      digitalWrite(11,LOW);
      digitalWrite(12,LOW);
      digitalWrite(13,LOW);
      digitalWrite(A0,LOW);
    }
    else if(fault==2)
    {
      digitalWrite(A0,HIGH);
      lcd.setCursor(0,0);
      lcd.print("OV-Current Trip");
      lcd.write(byte(5));
      lcd.setCursor(0,1);
      lcd.print("Reset UPS for NO");
      digitalWrite(A1,LOW);
      digitalWrite(A2,HIGH);
      digitalWrite(A3,LOW);
      digitalWrite(10,HIGH);
      digitalWrite(11,LOW);
      digitalWrite(12,LOW);
      digitalWrite(13,LOW);
      digitalWrite(A0,LOW);
    }
    else if(fault==3)
    {
      digitalWrite(A0,HIGH);
      lcd.setCursor(0,0);
      lcd.print("Battery Low!   ");
      lcd.write(byte(5));
      lcd.setCursor(0,1);
      lcd.print("Reset UPS for NO");
      digitalWrite(A1,LOW);
      digitalWrite(A2,HIGH);
      digitalWrite(A3,LOW);
      digitalWrite(10,HIGH);
      digitalWrite(11,LOW);
      digitalWrite(12,LOW);
      digitalWrite(13,LOW);
      digitalWrite(A0,LOW);     
    }
    else if(fault==4)
    {
      digitalWrite(A0,HIGH);
      lcd.setCursor(0,0);
      lcd.print("OV-Temperature ");
      lcd.write(byte(5));
      lcd.setCursor(0,1);
      lcd.print("Reset UPS for NO");
      digitalWrite(A1,LOW);
      digitalWrite(A2,HIGH);
      digitalWrite(A3,LOW);
      digitalWrite(10,HIGH);
      digitalWrite(11,LOW);
      digitalWrite(12,LOW);
      digitalWrite(13,LOW);
      digitalWrite(A0,LOW);
    }
  }
  if(RTC.read(tm)) 
  { 
    hour123 = (int)tm.Minute;
    if(hour123%5==0 && flag==1)
    {
      if(y==1)
      {
        digitalWrite(7, HIGH);
        y=0;
      }
      else if(y==0)
      {
        digitalWrite(7, LOW);
        y=1;
      }
      flag=0;
    }
    else if(hour123%5!=0)
      flag=1;
  }
}

void pin_ISR()
{
  if ( (millis() - lastDebounceTime) > debounceDelay)
  {
    buttonState = digitalRead(buttonPin);
    if (buttonState == HIGH) 
    {
      count_value++;
      if(count_value==5)
        count_value=0;  
      lastDebounceTime=millis();  
    } 
  }
}

Also, I've interfaced a Real-Time Clock module(DS1307) . Upon, reaching a preset time, I'm triggering a relay from my Arduino Nano.

I've also attached the complete circuit below:

The entire setup seems to work fine for a day or so. After that, it freezes, neither my Arduino runs nor my LCD. The LCD keeps displaying the last shown value. The RTC and relay setup that I try to control with my Nano do not work.

Any help would be appreciated!
Thanks in advance!!

I don't know the cause but one obvious thing is you have 5V connected to Vin, you should connect 5V to the 5V pin.

Your LEDs must be very dim with 10kOhm resistors, something like 220Ohms or anything up to about 1kOhms would be reasonable.

It would be helpful if you supplied more information; the exact parts you are using and photos of how you have it wired up. For example what is the real time clock module you have? You say it is a DS1307 but a DS1307 is not a module, it is an IC, which is probably on the module you have.

Can't find anything amiss with the code. (Not that I wouldn't miss something myself.)

-jim lee

From connector J3, I get 12V and GND. This is then converted to +5V using a 7805 Voltage Regulator. This +5V powers the NANO, hence it goes to the VIN pin.

I've actually used 330 Ohms for the LED's. Sorry about that, I forgot to update the schematic.

And, this is the RTC Module that I'm using:

Regarding wiring, all of these connections are done in a Double-sided PCB. I'm attaching a photo below:

That's wrong, 5V should go in the the 5V pin. The Vin pin feeds the Nano's own internal regulator. By feeding 5V to the Vin pin you are powering the Nano off some lower voltage, don't know what, maybe 3V. That might even be the cause of the problem, don't know.

The problem with that is it then makes us wonder what else in the schematic is wrong. Please check your schematic carefully and post a corrected version.

I don't see any code that does bounds checks for the ra array and the use of the "i" single letter global variable that is also used as a local variable name makes it impossible to do a search.
Your code should be able to handle unexpected input and not go beyond the limits of any array.

Not a bug, but writing the same information to a LCD character display once per loop (hundreds or thousands of times per second) is kind of pointless and steals CPU time from your code that is needed for checking the serial input. Generally speaking you would only update the display when the text you need to display has changed.

I would speculate that the code spends so much time updating the LCD display that it sometimes misses the serial start and end of frame characters hence the i variable doesn't get reset to zero so you end up writing past the end of the ra array.

Does the relat coil have a kick back diode?

Yeah, I understand. I will do this right away.

Meanwhile, here's the updated schematic:

This is the relay module that I've been using.

I'm guessing this has that free-wheeling diode inbuilt.

I strongly concur. I've had a very similar problem. The library I used took ages to write to the display (up to 100ms sometimes, although I'm not saying yours is as bad) and it caused various tricky-to-debug problems with data overflows and the like.

I strongly urge that you amend to code to write to the LCD only when something has changed.

Yes, relay modules use to have kick backs onboard.

The following code snippet is present in the main program as well.

The "disp" variable is incremented at the end of the loop and this way, the display updates once the "disp" crosses 15. This value tantamount to about 500ms(by observation). Hence, the data update is done once in 400-500ms.

Yes, you're correct. Sometimes it may miss the start and end of frame characters.
I've taken care of this by using the "rf" variable. Let's say, I've received data previously correctly, then my "rf" is set to "0" after I've received by end character(33). The next time, if I miss my start character, the array "ra" doesn't get updated because "rf" is 0.

Suffice it to say that I've tested out this part in the serial monitor and it seemed to work fine. Every time I printed the "ra" array, it printed correctly.

Thanks for pointing out this. I will add the following snippet:

if(rf==1 && a!=38 && i<=30)
    {
      ra[i] = a;
      i+=1;
    }

And I've ensured this on the transmitter side as well, in sense, I've restricted the maximum length of data to be sent as 30.

I would also suggest using while(Serial.available()) instead of if(Serial.available()) so that you can process all the outstanding characters in the Arduino's Rx buffer instead of just one each time you go round the main loop.

Also when faced with a display with a slow interface one trick it is to only paint one character per main loop.
To do this you have a char array called oldMessage with a copy of the last text message you sent to the display.
You also have a char array called newMessage that holds the new message. Each time you go through the main loop you compare a single character at position n in both arrays. If they are different then you send the new character to the display. On the next loop you increment n and so on. For a 16 character display the worst case scenario is that it takes 16 loops to repaint all the characters. Once you have done all the characters you overwrite the oldMessage with data from newMessage so that newMessage can be reused for the next new message.