I have a sparkfun 16x2 lcd kit. I want to display 2 screens of data before looping. To do this I just use a delay and then print the second screen.
This works but I’m on a mission to remove as many delays as possible from my code as its not looping fast enough to get better than about 50second full loop.
So any ideas to do what im doing without a delay would be great.
// Display on LCD
//Display first screen
led.empty();
led.at(1,3,"Air Temp: ");
led.at(1,13,(int)temp_f);
led.at(2,1,"CO2:");
led.at(2,5,CO2LevelValue);
led.at(2,10,"Hum:");
led.at(2,14,(int)humidity);
delay(5000); //I dont like this delay. must be a better way
//Display second screen
led.empty();
led.at(1,3,"H2O Temp: ");
led.at(1,13,(int)watertempinf);
led.at(2,1,"PPM:");
led.at(2,5,(int)TDSValue);
led.at(2,10,"PH:");
led.at(2,13,intValue);
led.at(2,14,".");
led.at(2,15,(anotherIntValue,2));
delay(5000);
Look at the blink without delay example. Each time that code is reached, see if it is time to display screen one. If it is, do so. If not, see if it is time to display screen two. If it is, do so. If not, move on.
Each time you display a screen, record when, so you know when it is time to display the next one.
I see some double code in your app (e.g. logging into the router) => make a separate function of that.
Furthermore I should redesign void loop()
* add conditional timing (some things don't need to be done every loop
* splt the making of the measurements and displaying them
#define FETCHLEVELTIMEOUT (5 * 60 * 1000L) // five minutes
unsigned long lastFetchLevels = 0;
#define DISPLAYTIMEOUT 1000 // every second
unsigned long lastDisplay = 0;
int screenID = 0;
void loop()
{
if (millis() - lastFetchLevels > FETCHLEVELTIMEOUT)
{
lastFetchLevels = millis();
getMaxLevels(); //ask PHP for Max levels and create global variables only run me every 1 to 5 minutes.
}
doSensorcheck()
doSomethingAboutIt(); // Compare Max levels to current levels and do something about it.
if (millis() - lastDisplay > DISPLAYTIMEOUT )
{
lastDisplay = millis();
doDisplay()
}
}
void doDisplay()
{
screenID = constrain(screenID, 0,2);
switch(screenID)
{
case 0 : Serial.println("this is screen 0"); // etc
break;
case 1 : Serial.println("this is screen 1");
break;
case 2 : Serial.println("this is screen 2");
break;
default: // should not happen => reset screenID
screenID = 0;
break;
}
screenID++;
}
This way you update the max levels every 5 minutes, and you update the display every second. The measurements and actions are executed as fast as possible.
furthermore in getMaxLevels() you expect that when Serial.Available > 0 you have all the data in your buffer. This is not always the case
Better write the routine in such a way that you first fill the buffer until you got the delimiter # and then start parsing
bool bufferComplete = false;
while (! bufferComplete )
{
if (Serial.available())
{
ch = Serial.read();
if (ch == '
Hopes this helps
Rob) { pos = 0; continue; }
if (ch == '#') { bufferComplete = true; continue; }
string[pos++] = ch;
if (pos == 31) pos = 0; // safeguard missing #
}
}
string[pos] = 0; // not needed after every char
```
awesome, thanks rob. My next step actually is removing a bunch of delays and starting towards cleaning things up. This will help a bunch. You are right, i dont need to check max levels every loop. I also dont need to post the results to php to log every loop either. It sucks up gigs a day in mysql.
ok I made a good bit of progress. Got alot of stuff moved to functions. Its starting to run much smoother now without all the delays and its easier to read with the functions.
Having trouble with the display on lcd function though. On start it runs through case 0,1,2 correctly. But then it just gets stuck on case 2. It blinks like it is clearing the lcd and displaying case 2 over and over.
void doDisplay()
{
int intValue = (int)PHValue; // convert float PHValue to tricky int combination
float diffValue = PHValue - (float)intValue;
int anotherIntValue = (int)(diffValue * 1000.0);
screenID = constrain(screenID, 0,2);
switch(screenID)
{
case 0 :
// Display on LCD
//Display first screen
led.empty();
led.at(1,3,"Air Temp: ");
led.at(1,13,(int)temp_f);
led.at(2,1,"CO2:");
led.at(2,5,CO2LevelValue);
led.at(2,10,"Hum:");
led.at(2,14,(int)humidity);
break;
case 1 : //Display second screen
led.empty();
led.at(1,3,"H2O Temp: ");
led.at(1,13,(int)watertempinf);
led.at(2,1,"PPM:");
led.at(2,5,(int)TDSValue);
led.at(2,10,"PH:");
led.at(2,13,intValue);
led.at(2,14,".");
led.at(2,15,(anotherIntValue,2));
break;
case 2 :
led.empty();
led.at(1,3,"Some other");
led.at(2,1,"awesomeness");
// screenID = 0;
break;
default: // should not happen => reset screenID
screenID = 0;
break;
}
screenID++;
} //End of doDisplay
ok. correct me if I'm wrong but the constrain actually doesnt make it loop it just says anything under 0 will return 0 and anything above 2 will return 2.
so screenID++; was counting up to infinity but the constrain was just keeping it at 2.
So I seem to have fixed it by adding screenID = -1; in the case 2 statement. which cause it screen++ to equal 0 and start the loop over.
screenID = constrain(screenID, 0,2);
switch(screenID)
{
case 0 :
// Display on LCD
//Display first screen
led.empty();
led.at(1,3,"Air Temp: ");
led.at(1,13,(int)temp_f);
led.at(2,1,"CO2:");
led.at(2,5,CO2LevelValue);
led.at(2,10,"Hum:");
led.at(2,14,(int)humidity);
break;
case 1 : //Display second screen
led.empty();
led.at(1,3,"H2O Temp: ");
led.at(1,13,(int)watertempinf);
led.at(2,1,"PPM:");
led.at(2,5,(int)TDSValue);
led.at(2,10,"PH:");
led.at(2,13,intValue);
led.at(2,14,".");
led.at(2,15,(anotherIntValue,2));
break;
case 2 :
led.empty();
led.at(1,3,"Some other");
led.at(2,1,"awesomeness");
screenID = -1;
break;
default: // should not happen => reset screenID
screenID = 0;
break;
}
screenID++;
Or you could write screenID = (screenID + 1) % 3; instead of screenID++;
which will keep cycling 0, 1, 2, 0, 1, 2 etc.
Or you could set up the next phase of screenID in each of the "case"s.