Button implementation within a long delay loop

Hello, I am building an air quality sensor using an arduino uno r3, an scd40 co2 sensor and an i2c oled screen.
I am using the default code from the sensor manufacturer which polls the sensor every 5 seconds to save power.


void loop() { 

	// Slow down the sampling to 0.2Hz.
    	//
    	delay(5000);
	.
	.
	sensor.readMeasurement(co2Concentration)
	.
	.
	display.print(co2Concentration);
	.
	.
}

So far so good, everything works fine. Now I would like to implement a button that upon pressing changes the brightness.
After reading about button state changes and debouncing, I understand that the 5 seconds delay in the main loop might be problematic.
How could I implement the above given that both in and out button state changes could very well take place within the 5 seconds of the main loop delay and be missed?

  • delay(. . .) stops normal code execution for that delay time.
  • Look at the examples in the IDE for making non blocking delay TIMERs.

https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay

use a timer to invoke that code every 5 seconds instead of usign delay().

Use a button library to handle the button and see post 2 and 3.

After you complete the timed event, you might want a clean way to update the new data. Clearing the display (display.clearDisplay()) requires updating all the information (even static data, like an outline, heading or image) on the display, which may cause "flickering."

What I like to use is... before the next sensor reading, position the cursor, change the text color to black, and write the old data.

    // erase old data
    display.setCursor(20, 10); // position cursor
    display.setTextColor(BLACK);
    display.print(co2Concentration); // left over from previous reading
    display.display(); // display the buffer

Then take a new sensor reading...

    // read new data
    sensor.readMeasurement(co2Concentration)

Then position the cursor, change text color to white, and print it.

    // display new data
    display.setCursor(20, 10); // position cursor
    display.setTextColor(WHITE);
    display.print(co2Concentration);
    display.display();

This millis timer works for me.

void loop()
{ // start loop
  static unsigned long timer = millis();
  const unsigned long interval = 5000;
  
  if(millis() - timer > interval) // timer expired
  { // start timed display
    timer += interval; // restart timer
    sensor.readMeasurement(co2Concentration);
    display.print(co2Concentration);
  } // end timed display
  
  // button and brightnes code here
  //
  //
  //
  //
  //
  //
   
} // end loop

I have seen that way, with adding the interval to timer. I use a similar method... without addition...

unsigned long timer, samplerate = 5000; // ms for timer
void setup() {
  // setup stuff
}

void loop() {
  // loop stuff
  if (millis() - timer > samplerate) { // has samplerate time expired?
    timer = millis(); // reset timer
.
.
}

Versus

Versus

while ( millis() - timer > interval )
{
  timer = timer + interval;
}  



This is an interesting discussion: