简体   繁体   中英

Arduino Programming adding milliseconds delay

So I'm trying to create an energy meter device which will read power every minute and then send it every 5 minutes through a LoRa server, using an MKR 1300 arduino. The problem is that as of now the hardware is removing a few milliseconds on the delay and so the time in the server ends up being pe:

10:50:30

10:50:30

10:50:30

... 2 hours later

10:50:29

10:50:29

...

10:49:59

The code looks like this:

#include <MKRWAN.h>
#include "EmonLib.h"
LoRaModem modem;

String appEui = "1234567891011121";
String appKey = "ffffffffffffffffffffffffffffffff";

EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;

double totalWatt;
int time_running;
int sending;
int totalKW;
int DELAY = 60000; // millis

void setup() {
  Serial.begin(115200);
  if (!modem.begin(EU868)) {
    Serial.println("Failed to start module");
    while (1) {}
  };
  Serial.print("Your module version is: ");
  Serial.println(modem.version());
  Serial.print("Your device EUI is: ");
  Serial.println(modem.deviceEUI());

  Serial.println("Connecting");
  int connected = modem.joinOTAA(appEui, appKey);
  if (!connected) {
    Serial.println("Something went wrong; are you indoor? Move near a window and retry");
    while (1) {}
  }
  Serial.println("Connected");

  modem.minPollInterval(60);

  analogReadResolution(9);
  emon1.current(1, 53);
  emon2.current(2, 53);
  emon3.current(3, 53);
  time_running = 0;

  randomSeed(analogRead(A4));

}

void loop() {
  unsigned long StartTime = millis();

  totalWatt = 0;
  unsigned long delay_send = 0;
  int sending = 0;

  double Irms1 = emon1.calcIrms(600);
  if (Irms1 < 0.3) Irms1 = 0;
  double Watt1 = Irms1 * 230;

  double Irms2 = emon2.calcIrms(600);
  if (Irms2 < 0.3) Irms2 = 0;
  double Watt2 = Irms2 * 230;

  double Irms3 = emon3.calcIrms(600);
  if (Irms3 < 0.3) Irms3 = 0;
  double Watt3 = Irms3 * 230;

  totalWatt = Watt1 + Watt2 + Watt3;
  totalKW = totalKW + totalWatt/1000;


  if (time_running == 5) { //15 para 15 mins
    double IrmsTotal = Irms1 +Irms2 + Irms3;
    String msg = "{\"id\":\"avac_aud1\",\"kW\":"+String(totalKW)+", \"current\":"+String(IrmsTotal)+"}";
    int err;
    modem.beginPacket();
    modem.print(msg);
    err = modem.endPacket(true);
    if (err > 0) { 
      //message sent correctly
      time_running = 0;
      totalKW = 0;
    } else {
      Serial.println("ERR");
      time_running = 0;
    }
  }

 time_running = time_running + 1;

 if ((millis() - StartTime) > DELAY){
    delay(10);
    return;
 } else{
    delay(DELAY-(millis() - StartTime));
    return;
 } 
}

I tried adding a variable ARD_DELAY (not shown above) to the code that in that last delay would subtract 7 to 8 milliseconds to try and fix this, but apparently, it only made it worse (now it removes 1 second every 1 hours instead of 2 hours) so today I'll try to add those 7 to 8 millis and see if it works, but I would really like to know why the heck this is happening because from what I can see from my code the delay should always account for the processed time including the data sending time.

Question is, how precise is your clock at all...

Still, I personally would rather go with the following approach:

#define DELAY (5UL * 60UL * 1000UL) // or whatever is appropriate...

static unsigned long timestamp = millis();
if(millis() - timestamp > DELAY)
{
    // adding a fix constant will prevent accumulating deviations over time
    timestamp += DELAY;
    // run the every-5-min task...
}

Edit: combined 1-min and 5-min task:

Variant 1:

#define DELAY_SHORT (1UL * 60UL * 1000UL)
#define DELAY_LONG  (5UL * 60UL * 1000UL)

static unsigned long timestampS = millis();
static unsigned long timestampL = timestampS;
if(millis() - timestampS > DELAY_SHORT)
{
    timestamp += DELAY_SHORT;
    // run the every-1-min task...
}
if(millis() - timestampL > DELAY_LONG)
{
    timestamp += DELAY_LONG;
    // run the every-5-min task...
}

Variant 2:

#define DELAY_1M (1UL * 60UL * 1000UL)

static unsigned long timestamp = millis();
if(millis() - timestamp > DELAY)
{
    // adding a fix constant will prevent accumulating deviations over time
    timestamp += DELAY;
    // run the every-1-min task...

    static unsigned int counter = 0;
    if(++counter == 5)
    {
        counter = 0;
        // run the every-5-min task...
    }
}

Instead of trying to measure a start time and adding delay depending on that, you could keep track of the timing for your next cycle.

unsigned long next_cycle = DELAY;

...

void loop() {
    ...

    delay( next_cycle - millis() );
    next_cycle += DELAY;
}

If you also want to adjust for any time the program spends on initialization or similar, you can next_cycle = millis() + DELAY; before you enter your loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM