LCD screen problems

Basic / Standard Reef Angel hardware
Post Reply
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

LCD screen problems

Post by gaberosenfield »

In the last week, my LCD screen (gen 7) keeps losing all or part of the information it normally displays. If I restart the controller, the screen looks as it should. But after 15-60 mins the screen stops working properly. It is still backlit, but sometimes it only displays the bottom half of the screen (no graph or title), sometimes it displays noise on the bottom half and the the bottom half of the displayed info is shifted up to the top half of the screen. Most often it displays nothing but backlight. The controller still seems to be working properly, so I think the problem is limited to the screen.

Maybe I just need another new screen (I got this one as a replacement for a broken one early this year), but before I order another, I'd really appreciate it if an expert could check my code for possible software reasons this is happening.
The board is an RA+ and I'm using the 2e3f279 libraries.

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <ReefAngel.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RA_CustomLabels.h>
#include <RA_CustomSettings.h>
#include <PH.h>
#include <avr/pgmspace.h>

//Ports assignment:
//First relay box is for the reef system.
//Port1 - Metal Halide Daylights.
#define lights Port1
//Port2 - AWC drain pump.
#define AWCdrain Port2
//Port3 - AWC fill pump.
#define AWCfill Port3
//Port4 - Carbon-dosing pump.
#define carbon Port4
//Port5 - Clockwise circulation pumps.
#define clockCirc Port5
//Port6 - Counterclockwise circulation pumps.
#define countCirc Port6
//Port7 - ATO pump.
#define ATOPump Port7
//Port8 - Empty.
#define lastPort Port8
/*After a circulation pump leaked current into the tank, triggering the 10 amp breaker in the relay box to shut off
  all power the tank and cause the deaths of most Acros, a peppermint shrimp, and a yellow tang, I decided to move some
  devices to a separate circuit that isn't controlled by the RA. These devices include:
  1) Return pump
  2) Skimmer pump
  3) Chiller
  4) Chiller feed pump
  5) Cabinet fans
  These devices will be on 24/7 and the RA will have no control over them.*/

//Change these values as needed. They are the threshold values for the low and high temperatures, respectively.
int lowTempWarning = 250; //low temp warning below 25.0C.
int highTempWarning = 275; //high temp warning above 27.5C.
static time_t overheatTimer; //Used to automatically reset the overheat flag.
int overheatTimeOut = 1800; //Used to automatically reset the overheat flag after 30 mins of temps below highTempWarning.
boolean overheatCheck = false;

//These vairable are used to control the ATO system.
static time_t ATOTimer;
int ATOTimeOut = 100;
boolean ATOdisabled = false;
static time_t ATOdisabledTimer;

//The following variables control when automatic water changes occur.
int AWCHour = 12;
int AWCMinute = 0;
char AWCChar[] = "AWC Scheduled: 1200"; //This string will be printed to the display until an AWC is attempted each day.

//These variables will be used to keep track of the progress of an AWC.
int AWCCheck = 0;
boolean AWCFail = false;
boolean drained = false;

//This variable will trigger an AWC().
boolean AWC = false;

//This variable will be set to true if a water change has been done since the last midnight and will be set to false at midnight.
boolean AWCToday = false;

//This vairable will store the current time for comparisons on when to initialize an AWC.
time_t AWCt;

//This variable will be a backup timer for AWC.
static time_t AWCTimer;

//These variables will control how long the AWC pumps should be on (in seconds) in case of float switch failure.
int AWCDrainSecs = 150;
int AWCFillSecs = 150;

//This function will check to make sure the water level in the sump is at the high float before initiating an AWC.
int AWCATOCheck()
{
  /*if (!ReefAngel.Relay.Status(returnPump))  //If the return pump is not on, don't run an AWC and return 0 (false).
    return 0; //Returning zero here is the only way for AWCCheck to equal 0 while AWC equals true. This will cause the AWC process to pause until the return pump is on again.*/
 
  if (!ReefAngel.HighATO.IsActive()) //If the water level is not at the maximum normal level, run the ATO.
  {
    ATOTimer = now();
    ReefAngel.Relay.On(ATOPump);  //Fill the return section to the high float with RODI.
    AWCToday = true;
    return 2;
  }
  else
  {
    AWCToday = true;
    return 1;
  }
}

//Custom Menu Code
const unsigned char menu1_label[] PROGMEM = "Feed for 5 Mins";
const unsigned char menu2_label[] PROGMEM = "Start AWC";
const unsigned char menu3_label[] PROGMEM = "Clear Alerts & Vars";
//const unsigned char menu4_label[] PROGMEM = "pH Calibration";
const unsigned char menu4_label[] PROGMEM = "Disable ATO for 4h";
const unsigned char menu5_label[] PROGMEM = "Set Date & Time";
const unsigned char menu6_label[] PROGMEM = "Toggle Port8";
const unsigned char menu7_label[] PROGMEM = "Version";
PROGMEM const char * const menu_items[] = {
menu1_label, menu2_label, menu3_label, menu4_label, menu5_label, menu6_label, menu7_label
};
void MenuEntry1()
{
  ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
  AWCToday = false;
  AWC = true;
  ReefAngel.DisplayMenuEntry("AWC Starting");
}
void MenuEntry3()
{
  //Clear portal variables.
  //ReefAngel.CustomVar[Var_AWCCountTotal] = 0;
  //ReefAngel.CustomVar[Var_AWCCountToday] = 0;
  //ReefAngel.CustomVar[Var_AWCDrainFail] = 0;
  //ReefAngel.CustomVar[Var_AWCFillFail] = 0;
  //ReefAngel.CustomVar[Var_AWCATOFail] = 0;

  //Clear overheat status:
  ReefAngel.OverheatClear();
 
  //Clear AWC control variables:
  AWC = false;
  AWCToday = false;
  AWCFail = false;
  AWCCheck = 0;
 
  //Clear ATO timeout:
  ReefAngel.ATOClear();
  
  ReefAngel.DisplayMenuEntry("ATO, AWC, & Overheat Vars Reset");
}
void MenuEntry4()
{
  //ReefAngel.StartSetupCalibrateChoicePH();
  //ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
  ATOdisabled = true;
  ATOdisabledTimer = now();
  ReefAngel.DisplayMenuEntry("ATO disabled for 4 hours");
}
void MenuEntry5()
{
  ReefAngel.SetupDateTime();
  //ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry6()
{
  //ReefAngel.WaterChangeModeStart();
  //ReefAngel.DisplayMenuEntry("Return & skimmer pumps off");
  ReefAngel.Relay.Toggle(lastPort);
}
void MenuEntry7()
{
ReefAngel.DisplayVersion();
}

void DrawCustomMain()
{
  // the graph is drawn/updated when we exit the main menu & when the parameters are saved
  ReefAngel.LCD.DrawDate(6, 120);

  pingSerial();

  //T2 probe is main temp sensor, while T1 probe is cabinet temp sensor.
  byte mainTempColor;
  //To make changes for each temp sensor, change the value of tempColor to be the appropriate color
  if ( ReefAngel.Params.Temp[T2_PROBE] < lowTempWarning ) { mainTempColor = COLOR_CYAN; }
  else if ( ReefAngel.Params.Temp[T2_PROBE] > highTempWarning ) { mainTempColor = COLOR_RED; }
  else { mainTempColor = COLOR_SEAGREEN; }
  //Display the T2 Main System temperature
  int T2y = 66; //Y-position of T2 probe reading.
  ReefAngel.LCD.DrawText(mainTempColor, DefaultBGColor, 5, T2y, "Tank Temp: ");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], mainTempColor, 65, T2y, 10);
 
  //Display the T1 Room temperature
  int T1y = 75; //Y-position of T1 probe reading.
  ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 5, T1y, "Cabinet Temp: ");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 85, T1y, 10);

  /*byte pHColor;
  //Depending upon the pH, change the value of pHColor to be the appropriate color
  if ( ReefAngel.Params.PH < 790 ) { pHColor = COLOR_YELLOW; }
  else if ( ReefAngel.Params.PH > 810 ) { pHColor = COLOR_MAGENTA; }
  else { pHColor = COLOR_SEAGREEN; }
  //Display the pH starting at 88, 74
  ReefAngel.LCD.DrawText(pHColor, DefaultBGColor, 5, 80, "pH: ");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.PH, pHColor, 30, 80, 100);*/
 
  //Display whether the ATO/AWC high float switch is active (purple highlight, float away from wires) or inactive (green highlight, float close to wires):
  byte floatColor; //Text color for ATO reading.
  int ATOy = 84; //Y-position for ATO reading.
  ReefAngel.LCD.Clear(DefaultBGColor, 0,ATOy, 128,ATOy+7); //Default font size is 5 pixels wide by 8 pixels high.
  if (ReefAngel.HighATO.IsActive() && !ReefAngel.isATOTimeOut())
  {
    floatColor = COLOR_MEDIUMORCHID;
    ReefAngel.LCD.DrawText(COLOR_WHITE, floatColor, 5, ATOy, "High Float");
  }
  else if (!ReefAngel.HighATO.IsActive() && !ReefAngel.isATOTimeOut())
  {
    floatColor = COLOR_SEAGREEN;
    ReefAngel.LCD.DrawText(COLOR_WHITE, floatColor, 5, ATOy, "High Float");
  }
  else {ReefAngel.LCD.DrawText(COLOR_WHITE, COLOR_RED, 5, ATOy, "ATO Fail");}

  //Display whether the AWC low float switch is active (purple highlight, float away from wires) or inactive (green highlight, float close to wires):
  if (ReefAngel.LowATO.IsActive())
  {
    floatColor = COLOR_MEDIUMORCHID;
    ReefAngel.LCD.DrawText(COLOR_WHITE, floatColor, 70, ATOy, "Low Float");
  }
  else
  {
    floatColor = COLOR_SEAGREEN;
    ReefAngel.LCD.DrawText(COLOR_WHITE, floatColor, 70, ATOy, "Low Float");
  }

  //Display whether an AWC has occurred today, or when today's AWC is scheduled, 
  //or that an AWC is in progress, or that an AWC failure has occurred:
  //byte AWCColor; //Text color for AWC info.
  int AWCy = 95; //Y-position for AWC info.
  ReefAngel.LCD.Clear(DefaultBGColor, 0,AWCy, 128,AWCy+7); //Default font size is 5 pixels wide by 8 pixels high.
  if (AWCFail)
  {
    ReefAngel.LCD.DrawText(COLOR_WHITE, COLOR_RED, 2, AWCy, "AWC Failure");
  }
  else
  {
    if (AWC)
    {
      ReefAngel.LCD.DrawText(COLOR_BLACK, COLOR_YELLOW, 2, AWCy, "AWC In Progress");
    }
    else if (AWCToday)
    {
      ReefAngel.LCD.DrawText(COLOR_GREEN, COLOR_WHITE, 2, AWCy, "AWC Completed Today");
    }
    else {ReefAngel.LCD.DrawText(COLOR_BLUE, COLOR_WHITE, 2, AWCy, AWCChar);}
  }

  //Display relay box 1 ports with status at 12,105
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 105, TempRelay);
}

void DrawCustomGraph()
{
  //Print "Pringle Lab Reef" at the top of the screen
  ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 18, 2, "Pringle Lab Reef");
  ReefAngel.LCD.DrawGraph(5,13);
}
////// Place global variable code above here


void setup()
{
  InternalMemory.LCDID_write(1);
  ReefAngel.Init();
  ReefAngel.SetTemperatureUnit(Celsius); //Set to celsius Temperature units.
  for (int a=0;a<SIZE(menu_items);a++)
  {
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[a])),a);
  }
  ReefAngel.UseFlexiblePhCalibration();
  ReefAngel.FeedingModePorts = Port5Bit | Port6Bit; // Turn off Ports 5 & 6 (circulation pumps) when Feeding Mode is activated.
  //ReefAngel.WaterChangePorts = Port8Bit;  // Turn off port 8 (return & skimmer pumps) when Water Change Mode is activated
  ReefAngel.OverheatShutoffPorts = Port1Bit; // Turn off lights if overheat condition.
  ReefAngel.OverheatProbe = T2_PROBE; // Use T2 probe (tank temperature) for overheat functions.
  InternalMemory.OverheatTemp_write(highTempWarning); // Set the overheat temperature to the highTempWarning value.
  //Initialize portal variables.
  //ReefAngel.CustomVar[Var_AWCCountTotal] = 0;
  //ReefAngel.CustomVar[Var_AWCCountToday] = 0;
  //ReefAngel.CustomVar[Var_AWCFillFail] = 0;
  //ReefAngel.CustomVar[Var_AWCDrainFail] = 0;
  //ReefAngel.CustomVar[Var_AWCATOFail] = 0;
  //startupTimer = now();
}

void loop()
{
  //Start an AWC once per day at AWCHour:AWCMinute if an AWC hasn't happened since midnight and there hasn't been an ATO timeout.
  AWCt = now();
  if (!AWCFail && (hour(AWCt) == AWCHour) && (minute(AWCt) == AWCMinute) && !AWCToday && !AWC && !ReefAngel.isATOTimeOut())
  {
    AWC = true;  //Sets the AWC control variable to true.
  }
   
  //Reset the automatic water change variable and AWC and dosing counts every day at midnight.  Also add the day's AWC count to the total AWC count.
  if (hour(AWCt) == 0 && minute(AWCt) == 0 && AWCToday)
  {
    AWCToday = false;
    //ReefAngel.CustomVar[Var_AWCCountTotal] += ReefAngel.CustomVar[Var_AWCCountToday];
    //ReefAngel.CustomVar[Var_AWCCountToday] = 0;
  }
   
  //Start the chain of AWC functions.
  if (AWC && !AWCToday && AWCCheck == 0)
  {
    AWCCheck = AWCATOCheck(); //If AWCATOCheck returns non-zero, it will also set AWCToday to true.
  }
 
  if (AWCCheck == 2) // Fill return section of sump with ATO pump to the high mark:
  {
    if (!ReefAngel.HighATO.IsActive())
    {
      ReefAngel.Relay.Off(ATOPump);
      AWCCheck = 1;
    }
   
    if ((now() - ATOTimer) >= ATOTimeOut)
    {
      ReefAngel.Relay.Off(ATOPump);
      bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag);  //Trigger ATO timeout flag.
      AWCFail = true;
      //ReefAngel.CustomVar[Var_AWCATOFail] = 1;
      AWCCheck = 0;
      AWC = false;
    }
  }

  if (AWCCheck == 1 && !ReefAngel.Relay.Status(AWCdrain) && !drained) // Drain the return section of sump to the low mark:
  {
    AWCTimer = now();
    ReefAngel.Relay.On(AWCdrain);
  }
   
  if (ReefAngel.Relay.Status(AWCdrain))
  {
    if (ReefAngel.LowATO.IsActive())
    {
      ReefAngel.Relay.Off(AWCdrain);
      drained = true;
    }
   
    if (now()-AWCTimer >= AWCDrainSecs)
    {
      ReefAngel.Relay.Off(AWCdrain);
      AWCFail = true;
      //ReefAngel.CustomVar[Var_AWCDrainFail] = 1;
      AWCCheck = 0;
      AWC = false;
      ReefAngel.ATOClear();
    }
  }

  if (drained)
  {
    if (!ReefAngel.Relay.Status(AWCfill)) // Fill the return section of the sump to the high mark with fresh ASW.
    {
      AWCTimer = now();
      ReefAngel.Relay.On(AWCfill);
    }

    if (ReefAngel.Relay.Status(AWCfill))
    {
      if (!ReefAngel.HighATO.IsActive())
      {
        ReefAngel.Relay.Off(AWCfill);
        drained = false;
        AWC = false;
        AWCCheck = 0;
        ReefAngel.ATOClear();
        //ReefAngel.CustomVar[Var_AWCCountToday] += 1;
      }

      if (now()-AWCTimer >= AWCFillSecs)
      {
        ReefAngel.Relay.Off(AWCfill);
        drained = false;
        AWCFail = true;
        //ReefAngel.CustomVar[Var_AWCFillFail] = 1;
        AWCCheck = 0;
        AWC = false;
        ReefAngel.ATOClear();
      }
    }
  }
 
  //Light Control:
  ReefAngel.StandardLights(lights, 8,00, 18,00); //Lights on at 8 am and off at 6 pm.
 
  //Temp control is handled by the chiller:
  /*Turn off chiller if the temp gets too low.
  if (ReefAngel.Params.Temp[T2_PROBE] <= lowTempWarning && ReefAngel.Relay.Status(chiller))
  {
    ReefAngel.Relay.Off(chiller);
  } else if (!ReefAngel.Relay.Status(chiller) && ReefAngel.Params.Temp[T2_PROBE] >= (lowTempWarning + highTempWarning)/2) {
    ReefAngel.Relay.On(chiller); //Turn chiller back on if the temp rises to the mean of lowTempWarning & highTempWarning.
  }*/
  //Overheat staus will be cleared if the temperature drops below highTempWarning and stays there for at least 30 minutes:
  if (bitRead(ReefAngel.AlertFlags, OverheatFlag) && !overheatCheck && ReefAngel.Params.Temp[T2_PROBE] < highTempWarning)
  {
    overheatCheck = true;
    overheatTimer = now();
  }
  if (overheatCheck && bitRead(ReefAngel.AlertFlags, OverheatFlag))
  {
    if (ReefAngel.Params.Temp[T2_PROBE] >= highTempWarning)
    {
      overheatCheck = false; //Reset the overheatCheck flag if the temp rises to or above highTempWarning.
    } else if (now()-overheatTimer >= overheatTimeOut)
    {
      ReefAngel.OverheatClear(); //Clear overheat status and overheatCheck flag if the temp stays below highTempWarning for at least 30 mins.
      overheatCheck = false;
    }
  }
   
  //Wavemaker control
  ReefAngel.WavemakerRandom(clockCirc, 30, 300); // Turn clockwise circulation pumps on/off random cycles that lasts from 30 to 300 secs.
  ReefAngel.Relay.Set(countCirc, !ReefAngel.Relay.Status(clockCirc)); // Turn counterclockwise circulation pumps on/off on opposite cycle from clockwise circulation pumps.
   
  //ATO
  if (!AWC && !ATOdisabled) {
    ReefAngel.SingleATO(false, ATOPump, ATOTimeOut, 1); // Use single high float switch (false = high) for reef ATO with 100 second timeout. Runs at most once per hour.
  } else {ReefAngel.Relay.Off(ATOPump);}
  if (ATOdisabled && (now()-ATOdisabledTimer >= (4*60*60))) {ATOdisabled = false;} // If ATO is manually disabled, re-enable it after 4 hours.

  //Carbon dosing
  ReefAngel.DosingPumpRepeat(carbon, 60, 720, 10); //Turn on carbon dosing pump for 10 seconds every 12 hours (at 1am & 1pm).
 
  ReefAngel.ShowInterface();
}
I don't know why this would be relevant, but the button actuated by a joystick push is also broken. However the button stopped working months before the screen issue started and I wired in a separate button to bypass the broken one, which works fine. Again, no timing correlation between button and screen issues.

I really appreciate any help/advice you can offer me.

Thanks,
Gabe
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: LCD screen problems

Post by rimai »

Sounds like a hardware problem.
Roberto.
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

Re: LCD screen problems

Post by gaberosenfield »

I confirmed it is a problem with the screen by swapping the gen 4 (sorry for saying gen 7 in my OP: it has "7.1" printed on the board above the screen) with a gen 1 screen from my RA (which is controlling another tank). That screen works perfectly on the RA+. So I guess I somehow got a faulty screen. I'll order another.

Thanks,
Gabe
Post Reply