How to using millis() instead of delay() in a trend calculation code

I want to calculate the trend of temperature, pressure and humidity. But the original code executes very slowly and Stuck.
Here's original code:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme;
int  t_interval = 5000;
float p_ave = 0;
float t_ave = 0;
float h_ave = 0;
int count5 = 60; //60 * 5 sec in 5 min assuming t_interval = 5000msec
//ring buffer to allow trend detection
const int length=30; //size of buffer: 36 places allows a time interval of 36 * 5 min = 3 hours
float data[length]; //buffer array
int put_index=0; //index to array
float t_now, t_was;
float p_now, p_was;//current pressure and old pressure
float h_now, h_was;
float temperature, humidity, pressure, change_P, change_T, change_H;

void setup() {
//initialise array values to zero
  for(put_index=0; put_index<length; put_index++){
    data[put_index]=0;
  }
  put_index=0; //reset ready for data entry
  int change = 0;
  delay(100);

Serial.begin(9600);

if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while(1);
  }
  bme.setSampling(Adafruit_BME280::MODE_NORMAL,
                  Adafruit_BME280::SAMPLING_X16,  // temperature
                  Adafruit_BME280::SAMPLING_X16, // pressure
                  Adafruit_BME280::SAMPLING_X16,  // humidity
                  Adafruit_BME280::FILTER_X16,
                  //Adafruit_BME280::STANDBY_MS_0_5 );
                  Adafruit_BME280::STANDBY_MS_250 ); //standby to 250msec
}

void loop() {
for (int i = 0; i < count5; i++) {
    
    temperature = bme.readTemperature();
    pressure = bme.readPressure() / 100.0F; //bme280
    humidity = bme.readHumidity();

    delay(t_interval);
    
    t_ave += temperature; 
    p_ave += pressure;
    h_ave += humidity;
  }
  t_ave /= count5;
  p_ave /= count5;
  h_ave /= count5;
  t_was = put(t_ave);
  p_was = put(p_ave);
  h_was = put(h_ave);
  change_T = t_ave - t_was; //change reading
  change_P = p_ave - p_was; //change reading
  change_H = h_ave - h_was; //change reading
  t_ave = 0; //reset ready for next calculation
  p_ave = 0; //reset ready for next calculation
  h_ave = 0; //reset ready for next calculation

 }

float put(float value){
  Serial.print("T-now = ");
  Serial.print(value, 2);
  data[put_index] = value;
  put_index=(put_index+1)% length;
  value=data[put_index];  
  Serial.print(":  T-was = ");
  Serial.println(value, 2);
  
  Serial.print("P-now = ");
  Serial.print(value, 2);
  data[put_index] = value;
  put_index=(put_index+1)% length;
  value=data[put_index];  
  Serial.print(":  P-was = ");
  Serial.println(value, 2);

  Serial.print("H-now = ");
  Serial.print(value, 2);
  data[put_index] = value;
  put_index=(put_index+1)% length;
  value=data[put_index];  
  Serial.print(":  H-was = ");
  Serial.println(value, 2);

  Serial.print("Change_T = ");
  Serial.println(change_T);
  Serial.print("Change_P = ");
  Serial.println(change_P);
  Serial.print("Change_H = ");
  Serial.println(change_H);
  
  return(value);
}

Can i replace "delay(t_interval) with millis()? how?
Thanks for your help in advance.

Yes you can.

I would ask why? There is no advantage at all in rewriting the delay function to use millis(). It will do the same thing, that is will block any running of any other code until it is finished.
It will not speed up anything. Temperature, pressure and humidity don't change very quickly so five seconds is a sensible rate, if you want it faster then just put a smaller number in the declaration of t_interval.

People use millis to write code that appears to multitask.
An illustration of that is in the blink without delay function under the examples menu of the IDE.

Or look here for my take on the topic

http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html

1 Like

i favor a running avg using leaky integration
avg += (samp - avg) / N;

a running avg would allow updating the output every sample period instead of waiting for 60 5 sec sampling periods

1 Like

Then why use

where the wait time is

which is 5 seconds?

Why is a 5 seconds delay required and what is the purpose of waiting 5 seconds?

Here I collect 60 pressure readings. The pressure readings are collected once every 2 hours and a graph is displayed on a e-ink display. A trend line.

void fProcessAirPressure ( void *pvParemeters )
{
  int   Ticks     = 118; // Tick counter
  bool  Filled    = false; // array has been filled before?
  float *ptr      = CollectionPressure; // pointer to the array
  const int ticksTrigger = 120; // triggered at 1 minute intervals
  for (;;)
  {
    //triggered by BME which is triggered by the 1 minute hardware timer.
    xEventGroupWaitBits (eg, evtStoreAirPressure, pdTRUE, pdTRUE, portMAX_DELAY );
    xSemaphoreTake( sema_CollectPressure, portMAX_DELAY );
    xSemaphoreTake ( sema_eData, portMAX_DELAY );
    if ( !Filled )
    {
      //if array has not been filled before, fill array with the same base value
      for ( int j = 0; j < BufferCount; j++ )
      {
        *( ptr + j ) = x_eData.oPressure;
      }
      Filled = true;// array has been initially filled
    } else {
      if ( Ticks == ticksTrigger )
      {
        //when tick counter reaches the trigger level
        //shift contents left and insert new value at the end
        for ( int i = 0; i <= BufferCount - 2; i++ )
        {
          *( ptr + i ) = *( ptr + (i + 1) );
        }
      }
      *( ptr + (BufferCount - 1) ) = x_eData.oPressure;//new value to be inserted
    }
    // find and store highest and lowest value
    if ( x_eData.oPressure > x_eData.PressureH )
    {
      x_eData.PressureH = x_eData.oPressure;
    }
    if ( x_eData.oPressure < x_eData.PressureL )
    {
      x_eData.PressureL = x_eData.oPressure;
    }
    Ticks++;
    if ( Ticks > ticksTrigger )
    {
      Ticks = 1;
    }
    //log_i( "ticks %d" , Ticks );
    x_eData.cngPress = CalculatePressureFactors(  *( ptr + 57), *( ptr + 59) ); // going back 4 hours
    xSemaphoreGive( sema_eData );
    xSemaphoreGive( sema_CollectPressure );
    //
    //log_i( " high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
  } //for (;;)
  vTaskDelete( NULL );
} //void fStoreAirPressure ( void *pvParemeters )
////

code used to display air pressure trend line.

    int BaseLine = (int) * ptr;
    int offsetX = 0;
    for ( int j = 0; j < BufferCount; j++ )
    {
      if ( *(ptr + j) != 0.0f )
      {
        int yAdj = BaseLine - (int) * (ptr + j);
        display.setCursor( CurrentX + offsetX, CurrentY + yAdj );
        display.print( "-" );
        offsetX += 5;
        // log_i( "pressure %f item %d", CollectionPressure[j], j );
      }
    }

But if you just want a running average use suggestion from post#3.

1 Like

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