Help with oled display code optimization

Hello, got a rather basic noob question.

I am using the particle oled display featherwing with the code below to cycle through the display of several sensor data points. This is my loop.

I read somewhere that too many delays in the loop can can cause issues with cloud connectivity? ( blocking ?).

Is what I have the best way to do this? With several delays between the display? Is there a better way to set this up?

        oled.clearDisplay();   
        oled.setTextSize(1);
        oled.setTextColor(WHITE);
        oled.setCursor(0, 0);

        oled.clearDisplay(); 
        oled.setCursor(0, 0);
        oled.print("Time: ");
        oled.setCursor(0, 20);
        Time.zone(-5);
        oled.println(Time.format(Time.now(), "%a %b, %e %l:%M %p"));
        oled.display();
        delay(4000);
        
        oled.clearDisplay();
        oled.setCursor(0, 0);
        oled.print("Temp/Humidity: ");
        oled.setCursor(0, 20);
        snprintf(buf, sizeof(buf), "%.1f ", tempF);  // temperature
        oled.print("Temp "); oled.println(buf);
        oled.setCursor(67, 20);
        snprintf(buf, sizeof(buf), "%.1f ", sample.humidity);  // humidity
        oled.print("RH "); oled.println(buf);
        oled.display();
        delay(4000);

        oled.clearDisplay();
        oled.setCursor(0, 0);
        oled.print("Gases: ");
        oled.setCursor(0, 20);
        snprintf(buf, sizeof(buf), "%.1f ", sample.co2);  // CO2
        oled.print("CO2 "); oled.println(buf);
        oled.setCursor(67, 20);
        snprintf(buf, sizeof(buf), "%.1f ", sample.voc);  // VOC
        oled.print("VOC "); oled.println(buf);
        oled.display();
        delay(4000);

        oled.clearDisplay();
        oled.setCursor(0, 0);
        oled.print("Dust Levels: ");
        oled.setCursor(0, 20);
        snprintf(buf, sizeof(buf), "%.1f ", sample.MassPM2);  // PM2.5
        oled.print("PM2.5 "); oled.println(buf);
        oled.setCursor(67, 20);
        snprintf(buf, sizeof(buf), "%.1f ", sample.MassPM10);  // PM10
        oled.print("PM10 "); oled.println(buf);
        oled.display();
       
        delay(4000);

@vacquah, here is some (untested) code which makes use of two concepts:

  1. A non-blocking millis() timer which “fires” every 4000 milliseconds
  2. A simple state machine which treats each display “page” as a state or “step”

Every time the timer fires, the switch()/case statement will run the code for the current step number then change the step number to the next step before completing. The final step then sets the step number to the first step or beginning and the whole cycle starts again. Here is the code:

// These are globally declared variables
int step;		// This is the step (aka state) counter
unsigned int step_timer;	// This is the millis() based step timer 

// this code goes in setup()
oled.clearDisplay();   
oled.setTextSize(1);
oled.setTextColor(WHITE);
oled.setCursor(0, 0);
Time.zone(-5);				// This only needs to be done once in setup()

// this code goes in loop()
if (millis() - step_timer > 4000)		// When the step_timer has run for 4000ms, execute a step
{
	step_timer = millis();
	
	// This code is common to all steps
	oled.clearDisplay();
	oled.setCursor(0, 0);

	switch(step) {		// Run the current "step"
		case 0:
			oled.print("Time: ");
			oled.setCursor(0, 20);
			oled.println(Time.format(Time.now(), "%a %b, %e %l:%M %p"));
			step = 1;		// Change "step" to the next step
			break;

		case 1:
			oled.print("Temp/Humidity: ");
			oled.setCursor(0, 20);
			snprintf(buf, sizeof(buf), "%.1f ", tempF);  // temperature
			oled.print("Temp "); oled.println(buf);
			oled.setCursor(67, 20);
			snprintf(buf, sizeof(buf), "%.1f ", sample.humidity);  // humidity
			oled.print("RH "); oled.println(buf);
			step = 2;		// Change "step" to the next step
			break

		case 2:
			oled.print("Gases: ");
			oled.setCursor(0, 20);
			snprintf(buf, sizeof(buf), "%.1f ", sample.co2);  // CO2
			oled.print("CO2 "); oled.println(buf);
			oled.setCursor(67, 20);
			snprintf(buf, sizeof(buf), "%.1f ", sample.voc);  // VOC
			oled.print("VOC "); oled.println(buf);
			step = 3;		// Change "step" to the next step

		case 3:
			oled.print("Dust Levels: ");
			oled.setCursor(0, 20);
			snprintf(buf, sizeof(buf), "%.1f ", sample.MassPM2);  // PM2.5
			oled.print("PM2.5 "); oled.println(buf);
			oled.setCursor(67, 20);
			snprintf(buf, sizeof(buf), "%.1f ", sample.MassPM10);  // PM10
			oled.print("PM10 "); oled.println(buf);
			step = 0;		// Reset "step" to the first step to start over
			break;
		}

	// This code is common to all steps
	oled.display();
}
6 Likes

@peekay123 I applied it but it seems not to work. It does compile ok but the oled screen never comes on. It works if I remove the if statement and just run the original code without the switch statement.

Also, if I modify your code just slightly like below ( to simplify things) , the screen comes on just once - during the flashing process, and cycles though the screens or pages, then goes off again.

int step;		// outside of the loop.
unsigned long step_timer = 0; 

// in setup ()
  oled.setup();  // your suggestion abaove doesnt have this
  oled.clearDisplay();   
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
  oled.setCursor(0, 0);
  Time.zone(-5);

// in loop()
if (millis() - step_timer > 4000) {
  step_timer = millis();

    oled.clearDisplay();
    oled.setCursor(0, 0);

    switch(step) {
      case 0:
        oled.setCursor(0, 0);
        oled.println(Time.format(Time.now(), "%a %b,%e"));
        oled.setCursor(0, 18);
        oled.println(Time.format(Time.now(), "%l:%M %p"));
      step = 1;	
      break;

      case 1:
        oled.setCursor(0,10);
        snprintf(buf, sizeof(buf), "%.1f ", tempF);  // temperature
        oled.print("Temp "); oled.println(buf);
      step = 2;
      break;

      case 2:
        oled.setCursor(0,10);
        snprintf(buf, sizeof(buf), "%.1f ", RH);  // humidity
        oled.print("RH "); oled.println(buf);
      step = 3;  
      break;

      }
    oled.display();
  }   

Do you have unsigned int step_timer as a global variable as the comment demands?
If you hadn’t that could explain the wrong behaviour.

Hi, @vacquah I’m not sure but try to Assign a value to your global step
int step = 0;
as right now nobody knows which value is in your step :slight_smile:

@ScruffR looks like I missed your reply before modifying my last post. I had the step_timer in my global variables as unsigned int step_timer; It didnt work, so changed it to unsigned long step_timer = 0;

please see my modified post above.

you mean this? unsigned long step_timer = 0; please see my modifed code above

no this :slight_smile:
int step = 0;

Ah - apologies. Missed that. Here is what I have now in my global. It runs only once during initial flash then goes off.

int step = 0;		// for oled setup
unsigned long step_timer = 0; 

change step to 0 can't be 3 as will newer reset and start over

1 Like

@dreamER thats exactly what it was - working now! Thanks to you all.

So just to clarify, this wont hold up the publishing event? I started looking at optimizing this because my devices seem to loose cloud connectivity regularly ( fast blinking blue) and is only restored with a reboot. I am assuming all the delays on the loop was the cause.

i’m not sure what was blocking in your code as per documentation:

> Particle.process() is called automatically after every loop() and during delays.

But for sure the code provided by @peekay123 will never block and should work with no issue

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.