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);
}

