How to set the counter properly for sync getData and sendData

So this is my idea, I get the data from mpu every seconds, from dht22 every 5 seconds then sent it via LoRa every 10 seconds, what I want that when dht22 updates twice, it immidiate sent the data, so it must be synchron just like this picture below

however 2 data been skipped cause the send data process itself need around 2 s time excecution due to "String message", but that's not the issue, my problem is with the sent counter, the sent counter automatic start after gives me 3 first data

in this table, i summary my serial monitor

please can anybody check my program? How to set the sent counter properly? My idea only apply for the data after counter 3, can I set the counter starts right after dht been updates twice so I don't have to wait the valid data till counter 3, also I'm confuse where to put function to measure excecution time from void getreadings to void sendreadings, or maybe i should arrange and changing some code, i would appreciate every suggest and corrections from u guys

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#include <SPI.h>             
#include <LoRa.h> 

RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);
Adafruit_SSD1306 display(128, 64, &Wire, -1);

Adafruit_MPU6050 mpu;
DHT_Unified dht(4, DHT22);

//Display and Lora Variable Interval
unsigned long lastdisplay = 0;
static unsigned long lastLoRaSend = 0;
int counter = 0;
int level = 10, sf = 12;
long frequency = 915E6, sbw = 125E3;
DateTime readingTime;
//Battery Variable 
int ADCValue = 0;
float Vin;
//Data Variable
float ax, ay, az; //raw acceleration
float ax_gal, ay_gal, az_gal; //acceleration in GAL unit
float r_gal; //resultan of the acceleration in GAL unit
float tempd, hum; //data from dht22
bool dhtUpdatedFlag;
// unsigned long currentMillisr;
unsigned long startTimer, endTimer, startTimes, endTimes; //r for read data //s for sending data
int batteryPercent;
//LoRa Pin
#define ss 5 
#define rst 14 
#define dio0 2 
// LoRa message variable 
String message;

// Function to get battery percentage based on Vin
int getBatteryPercentage(float Vin) {
  if (Vin >= 4.1) return 100;
  else if (Vin >= 3.8) return 90;
  else if (Vin >= 3.4) return 80;
  else if (Vin >= 2.9) return 70;
  else if (Vin >= 2.5) return 60;
  else if (Vin >= 2.1) return 50;
  else if (Vin >= 1.7) return 40;
  else if (Vin >= 1.3) return 30;
  else if (Vin >= 0.8) return 20;
  else if (Vin >= 0.4) return 10;
  else return 0;
}

// Function to classify r_gal based on the MMI scale
const char* classifyPGA(float r_gal) {
  if (r_gal < 1) return "I";
  else if (r_gal < 2) return "II";
  else if (r_gal < 5) return "III";
  else if (r_gal < 10) return "IV";
  else if (r_gal < 25) return "V";
  else if (r_gal < 50) return "VI";
  else if (r_gal < 100) return "VII";
  else if (r_gal < 250) return "VIII";
  else if (r_gal < 500) return "IX";
  else if (r_gal < 1000) return "X";
  else return "XI+"; // For extreme cases above 1000 Gal
}

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Initialize...");

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(0, 10);
  display.print("Initialize...");
  display.display();

  dht.begin();
  delay(3000); //give dht some time to warm up
  mpu.begin();
  rtc.begin();
  delay(3000); //give lcd some time to display Initialize...
  lcd.clear();
  LoRa.setPins(ss, rst, dio0); 
  Serial.println("Initializing LoRa Transmitter");
  
  LoRa.begin(frequency);
  LoRa.setSyncWord(0xF3);
  LoRa.setTxPower(level);
  LoRa.setSpreadingFactor(sf);
  LoRa.setSignalBandwidth(sbw);

  Serial.println("LoRa Transmitter Initializing OK!");
}

//Declare the void functions manually cause using Platform.io
void batterystatus(float &Vin);
void displayBatteryOnOLED(float Vin, DateTime now);
void convertPga(float ax, float ay, float az);
void resultantPga(float ax_gal, float ay_gal, float az_gal, float &r_gal);
void getReadings();
void sendReadings();

void loop() {
  unsigned long currentMillis = millis();
  // DateTime now = rtc.now();

  if (currentMillis - lastdisplay >= 1000) {
    lastdisplay = currentMillis;
    
    batterystatus(Vin);
    batteryPercent = getBatteryPercentage(Vin); // Get battery percentage

    startTimer = millis();
    getReadings();
    endTimer = millis();

    // Serial Monitor Output
    Serial.printf("Time: %02d:%02d:%02d/Temp: %.2f°C/RH: %.2f%%/Acc_X: %.2f,Y: %.2f,Z: %.2f/PGA_X: %.2f,Y: %.2f,Z: %.2f/PGA_R: %.2f Gal - %s/Battery: %.2fV - %d%%/GetExecTime: %lums\n", 
      readingTime.hour(), readingTime.minute(), readingTime.second(),
      tempd, hum,
      ax, ay, az, 
      ax_gal, ay_gal, az_gal, 
      r_gal, classifyPGA(r_gal), // Adding PGA classification directly
      Vin, batteryPercent,
      endTimer - startTimer); // Execution time for getReadings()
      // endTimes - startTimes); // Execution time for sendReadings() //being commented because too long dan can't excecute since it's inside this if function
    
     // Display on OLED
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.printf("%02d:%02d:%02d\n", readingTime.hour(), readingTime.minute(), readingTime.second()); //to display 2 digits for second
    displayBatteryOnOLED(Vin,readingTime);

    // Display on LCD every seconds
    lcd.setCursor(1, 0);lcd.print("PGA-Gal");
    lcd.setCursor(0,1);lcd.print("X:");lcd.print(ax_gal);
    lcd.setCursor(0,2);lcd.print("Y:");lcd.print(ay_gal);
    lcd.setCursor(0,3);lcd.print("Z:");lcd.print(az_gal);
    lcd.setCursor(9, 0);lcd.print("|");
    lcd.setCursor(9, 1);lcd.print("|");
    lcd.setCursor(9, 2);lcd.print("|");
    lcd.setCursor(9, 3);lcd.print("|");
    lcd.setCursor(10,1);lcd.print("MMI:");lcd.print(classifyPGA(r_gal));
    lcd.setCursor(10, 2); lcd.print("T  :");lcd.print(tempd);lcd.print("C");
    lcd.setCursor(10, 3); lcd.print("RH :");lcd.print(hum);lcd.print("%");
    lcd.setCursor(11, 0);
    lcd.printf("%02d:%02d:%02d", readingTime.hour(), readingTime.minute(), readingTime.second());
  }

  if (dhtUpdatedFlag && (currentMillis - lastLoRaSend >= 10000)) { //Send LoRa in same time every 2 DHT data updates
    lastLoRaSend = currentMillis;
    startTimes = millis();
    sendReadings();
    endTimes = millis();
    Serial.println("SendReadings() Execution Time: " + String(endTimes - startTimes) + "ms");
    // dhtUpdatedFlag = false;  // when un-comment --> LoRa sent every 10 seconds - DHT22 get data every 5 seconds, but they work separately and only synchron in random counter
                                //when comment --> LoRa sent every 10 seconds - DHT22 get data every 5 seconds, but they start become synchron after 2 loops (start from counter 3, LoRa always sent when dht have been update twice -> 10 second)                            
  }
}

// Function to display battery status on OLED
void displayBatteryOnOLED(float Vin, DateTime now) {
  int batteryPercent = getBatteryPercentage(Vin);
  display.setTextSize(1);
  display.setCursor(0, 10);
  display.printf("Battery: %02d%%\n", batteryPercent);
  display.display();
}

// Function convert to PGA (Gal unit)
void convertPga(float ax, float ay, float az) {
  ax_gal=ax*100;
  ay_gal=ay*100;
  az_gal=az*100;  
}

// Function convert to PGA (Gal unit)
void resultantPga(float ax_gal, float ay_gal, float az_gal, float &r_gal) {
  r_gal = sqrt((ax_gal * ax_gal) + (ay_gal * ay_gal) + (az_gal * az_gal));
}

// Function to process battery voltage
void batterystatus(float &Vin) {
  // Read Battery Voltage
  ADCValue = analogRead(34);
  float Vout = ADCValue * (3.3 / 4095.0);
  Vin = Vout * 5;
}

void getReadings() {
  DateTime newTime = rtc.now();
  if (newTime.second() != readingTime.second()) {
    Serial.println("RTC Read OK: " + String(newTime.second()));
  } else {
    Serial.println("RTC Read SAME SECOND: " + String(newTime.second())); //for checking if RTC being freeze when excevute void send readings, (RTC keep working if use --> dhtUpdatedFlag = false; )
  }
  readingTime = newTime;
  
  // Read Temperature and Humidity
  static unsigned long lastDHTRead = 0;
  unsigned long currentMillisr = millis();

  // currentMillis = millis();
  if (currentMillisr - lastDHTRead >= 5000) { //get dht data every 5 second
    lastDHTRead = currentMillisr;
    dhtUpdatedFlag = true; //checking if the data have been update

    sensors_event_t event;
    dht.temperature().getEvent(&event);
    tempd = event.temperature;
    dht.humidity().getEvent(&event);
    hum = event.relative_humidity;
  }
  
  //MPU6050 Data
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  ax = a.acceleration.x;
  ay = a.acceleration.y;
  az = a.acceleration.z;
  convertPga(ax, ay, az);
  resultantPga(ax_gal, ay_gal, az_gal, r_gal); // Compute resultant acceleration
  const char* pga_status = classifyPGA(r_gal); // Classify the PGA value
}

void sendReadings() { 
    message = String(readingTime.hour()) + "!" + String(readingTime.minute()) + "@" + String(readingTime.second()) +
              "#" + String(tempd) + "$" + String(hum) + 
              "%" + String(ax_gal) + "^" + String(ay_gal) + "&" + String(az_gal) + "*" + String(classifyPGA(r_gal));
    LoRa.beginPacket();
    LoRa.print(message);
    LoRa.endPacket();
    counter++;
    Serial.println("Counter: " + String(counter) + " | Sent: " + message);
}

Have you read the specs on the DHT22? The sampling rate is once every 2 seconds. So, how, in two seconds, can you get two different readings?

void batterystatus(float &Vin);
Why? The more usual approach would be to have the function return a flow and take no arguments.

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