Code time inaccuracy

Hi, while working on my project I noticed, that even when using millis function code inside it is skipped every 3-4 seconds. I tried to delete many things and nothing helped. There’s pH monitoring, temperature, water flow, distance measuring… etc. I’m using Arduino Mega

#include <NewPing.h>
#include <Wire.h>
#include <SPI.h>
#include <TimerFreeTone.h>
#include "SdFat.h"
#include "Sodaq_DS3231.h"
#include "HX711.h"
#include <OneWire.h>
#include <Nextion.h> 

#define Ka 0.0039083
#define Kb -5.775E-07
#define proud 1679.5
#define spodni 3346.0
#define horni 6016.0
#define privod 0.4

const int pinCidlaDS = 2;
OneWire oneWireDS(pinCidlaDS);
SdFat SD;
#define SD_CS_PIN SS
File Data;
HX711 scale;
NewPing sonar(12, 12, 200);
float spodni_a, horni_a;
int volt, hladinavody = 6;
byte sensorInterrupt = 0;
byte sensorPin       = 2;
float calibrationFactor = 4.5;
volatile byte pulseCount;
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
float celkem_litru;
unsigned long oldTime,oldTime1;
char buffer[100] = {0};
uint32_t number2 = 0;
 
NexButton b3 = NexButton(2, 8, "b3");  
NexButton b4 = NexButton(2, 10, "b4");  
NexSlider h0 = NexSlider(5, 14, "h0"); 

NexTouch *nex_listen_list[] = 
{
  &b3,
  &b4,
  &h0,
  NULL
};
void b3PushCallback(void *ptr)  
{ digitalWrite(23, HIGH);
  digitalWrite(22, LOW);  //
  delay(70000);
  digitalWrite(22, HIGH);
}
void b4PushCallback(void *ptr)  
{ 
  if(digitalRead(23)== HIGH)
  {
    digitalWrite(23,LOW);
    }else{digitalWrite(23,HIGH);}
}
void h0PopCallback(void *ptr)  // Release event for slider
{
   
}
void setup()
{
  Serial.begin(115200);
  pinMode(5,OUTPUT);
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  Wire.begin();
  rtc.begin();
  SD.begin();
  Data = SD.open("Data.txt", FILE_WRITE);
  
  scale.begin(A1, A2, 32);
  b3.attachPush(b3PushCallback); 
  b4.attachPush(b4PushCallback); 
  h0.attachPop(h0PopCallback); 
}

void loop() {
  DateTime now = rtc.now();
    scale.set_gain(32);
    float proud_a = scale.read_average(1) / 1000.0;
    int prumer = int(proud_a);
    float zbytek = proud_a - float(prumer);
    if (zbytek < 0.5) {proud_a = float(prumer);}
    else {proud_a = float(prumer) + 0.5;}
    float podil = proud_a / proud;
    scale.set_gain(64);
    spodni_a = spodni * podil;
    horni_a = horni * podil;
    prumer = int(scale.read_average(1) / 1000.0);
    float x = float(prumer);
    float odpor = (x - spodni_a) * (180.0 - 100.0) / (horni_a - spodni_a) + 100.0 ;
    float teplota  = 1.7 + (( sqrt(Kb * odpor - 100.0 * Kb + 25.0 * pow(Ka, 2)) - 5.0 * Ka) / (10.0 * Kb)) - privod;

  if ((millis() - oldTime) > 1000)   /// Zobrazení a uložení dat na SD kartu každou vteřinu
  { 
    oldTime = millis();
    detachInterrupt(sensorInterrupt);
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    flowMilliLitres = (flowRate / 60) * 1000;
    totalMilliLitres += flowMilliLitres;
    celkem_litru = totalMilliLitres / 1000;
    pulseCount = 0;
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    ///pH
    volt = analogRead(0);
    int measure = analogRead(0);
    double voltage = 4.9 / 1024.0 * measure;
    float Po = 7 + ((593 - measure) / 35.67);
    ///pH
    ///Hladina vody
    hladinavody = sonar.ping_cm();
    ///Hladina vody
    Serial.print("monitoring.pH.txt=\"  " + String(Po) + "\"");
    NextionEndCommand();
    Serial.print("monitoring.teplota.txt=\" " + String(teplota) + " 0C\"");
    NextionEndCommand();
    if (hladinavody < 10) {
      Serial.print("monitoring.t6.txt=\"  " + String(hladinavody) + ".00 cm\"");
    }
    else {
      Serial.print("monitoring.t6.txt=\" " + String(hladinavody) + ".00 cm\"");
    }
    NextionEndCommand();
    Serial.print("monitoring.kondu.txt=\"---.-- uS.m-1\"");
    NextionEndCommand();

    if (celkem_litru < 10) {
      Serial.print("monitoring.c_l.txt=\"  " + String(celkem_litru) + "  l\"");
    }
    else if (celkem_litru < 100) {
      Serial.print("monitoring.c_l.txt=\" " + String(celkem_litru) + "  l\"");
    }
    else {
      Serial.print("monitoring.c_l.txt=\"" + String(celkem_litru) + "  l\"");
    }
    NextionEndCommand();
    Serial.print("monitoring.prutok.txt=\"" + String(flowMilliLitres) + ".00 ml.s-1\"");
     NextionEndCommand();
    if (now.second() < 10 && now.minute() < 10 ) {
      Serial.print("Time.txt=\"" + String(now.date()) + "/" + String(now.month()) + "/" + String(now.year()) + " " + String(now.hour()) + ":0" + String(now.minute()) + ":0" + String(now.second()) + "\"");
    } else if (now.second() < 10 && now.minute() > 10)
    {
      Serial.print("Time.txt=\"" + String(now.date()) + "/" + String(now.month()) + "/" + String(now.year()) + " " + String(now.hour()) + ":" + String(now.minute()) + ":0" + String(now.second()) + "\"");
    }
    else if (now.second() > 10 && now.minute() < 10)
    {
      Serial.print("Time.txt=\"" + String(now.date()) + "/" + String(now.month()) + "/" + String(now.year()) + " " + String(now.hour()) + ":0" + String(now.minute()) + ":" + String(now.second()) + "\"");
    }
    else {
      Serial.print("Time.txt=\"" + String(now.date()) + "/" + String(now.month()) + "/" + String(now.year()) + " " + String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second()) + "\"");
    }
    NextionEndCommand();


  }
  if ( hladinavody <= 4)
  {
    TimerFreeTone(5, 3830, 500);
    digitalWrite(22, LOW);
  } else {
    digitalWrite(22, HIGH);
  }
  
  if ((millis() - oldTime1) > 10)  
  {
    oldTime1 = millis();
   nexLoop(nex_listen_list); 
  }
  
}

void pulseCounter()
{
  pulseCount++;
}
void NextionEndCommand()
{
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

It’s really long code, is it problem with so much commands sent via Serial??? Sorry for not translating it, but it should give you basic idea.
Thank you for any suggestions.

Dragonsired1:
when using millis function code inside it is skipped every 3-4 seconds.

I don’t know what you mean by that?

What is being skipped?

You are using a lot of libraries. Is it possible that some calls to a library take so long that the time for the next interval has passed?

The problem is often in the code that you do not post.

When did the problem emerge during your development of the program? Can you go back to a version that was working faultlessly and then know that it was some of the subsequent code that caused the problem or perhaps made a latent problem visible?

…R

What is being skipped?

Measuring and writing to Serial is skipped. There's data log from sd card where I originally saved all data

10/10/2017/17-36-11;pH:6.19;...
10/10/2017/17-36-12;pH:6.18;...
10/10/2017/17-36-14;pH:6.19;... (13 is missing)
10/10/2017/17-36-16;pH:6.18;...
10/10/2017/17-36-17;pH:6.19;...
10/10/2017/17-36-19;pH:6.16;...(18 is missing)
10/10/2017/17-36-21;pH:6.19;

When did the problem emerge during your development of the program?

Noticed after couple changes.

Can you go back to a version that was working faultlessly

Unfortunately I deleted previous file day ago ... and don't have any backup. I tried to delete several things - including HX711 library because even though there's no 'delay' in code it measures only once in a second. I checked library but never found anything useful.

How often is the data being written to the Serial port?

Sorry to hear you have accidentally deleted the earlier versions. IMHO the only practical step is to strip out enough stuff so you get back to a working version and start over. And make sure to keep back up copies this time.

...R

How often is the data being written to the Serial port?

Every 1 second. That includes writing data to Serial port for Nextion display, then saving all data to SD card (was deleted from code). I don’t understand where the problem is. And I included just necessary things in code, everything there is for some purpose and can’t be deleted. It’s even weird, it sometimes skips printing/saving every 3-4 seconds sometimes every 15-20 seconds. I tried to give it more time so I rised from 1 s to 2s and nothing changed. It’s very important to save and print all data each second and it makes me frustrated I don’t know where can problem be.

There is this…

void b3PushCallback(void *ptr) 
{ digitalWrite(23, HIGH);
  digitalWrite(22, LOW);
  delay(70000);  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  digitalWrite(22, HIGH);
}

I've had a look at and measured such things on a scope on a nano AT328 at 16MHz

1/ The digitalWrite() takes about 6uS as against a direct port write of 62.5nS. 100 times slower. And if you want to change lines simultaneously, no good.

2/the millis() function updates it's count every 1.024mS and takes about 7uS to do it. It doesn't matter whether you use it or not. Hence there is a skip.

3/ The loop() uses about 7uS every time round to perform backgrouind tasks - embed a while(1) if you want to avoid this.

I'm sure there are bits I've missed

Overall a very nice and easy environment to use, but has significant overheads.

Allan

Dragonsired1: I don't understand where the problem is

I know that - otherwise you would not be asking for help.

And because you don't know where the problem is you have to go back to an early development stage of the program to get a working version from which to start building the rest of the project. You can't expect to develop a complex program like that with all of the parts right from the start.

...R

This function is called only when Button on display is pressed…

Overall a very nice and easy environment to use, but has significant overheads.

From your suggestions I sum up, there’s no way to make it precisely every second? It worked before…

you have to go back

Ok so I should make that same code from scratch adding more and more things and when that problem occurs find out what makes this problem… Ok

Dragonsired1: Ok so I should make that same code from scratch adding more and more things and when that problem occurs find out what makes this problem...

Or, comment out sections until the problem disappears. Your code has user interface parts (beep, button handling, display) and "functional" parts. A great place to start would be to comment out the optional user interface parts (like the beep).

...or strip thing out one at a time until you get to the shotest version of the program which demonstrates the error. Then post that complete code here.

This is part of the problem:

if ((millis() - oldTime) > 1000)   /// Zobrazení a uložení dat na SD kartu každou vteřinu
  { 
    oldTime = millis();

This will get you out of sync with the real time. If last time you checked (millis() - oldTime) was 998, then next time you check it will be maybe 1050. The next successful check will be at 2051 (in real time) at least, but most probably it will be at about 2080. Then the next match is at 3100 etc. Sooner or later one full real time second will be skipped. I hope you understand what I mean :) Change to:

if ((millis() - oldTime) > 1000)   /// Zobrazení a uložení dat na SD kartu každou vteřinu
  { 
    oldTime += 1000;
if ((millis() - oldTime) >= 1000)   /// Zobrazení a uložení dat na SD kartu každou vteřinu

:wink:

This will not make a difference to the problem I described, will it?
[EDIT] It will! Thanks for correcting me :slight_smile:

Change to: Code: [Select] if ((millis() - oldTime) >= 1000) /// Zobrazení a uložení dat na SD kartu každou vteřinu { oldTime += 1000;

I changed the code, results are same: https://youtu.be/PU2x_tzO8JI

Even some parts of code are ignored. There's code for changing numbers from 1-9 to 01-09 and it didn't worked.

The change suggested in Reply #11 is a good idea but it is not going to solve to your problem. That change will just prevent accumulated errors of a few millisecs creeping in.

...R

Robin2: The change suggested in Reply #11 is a good idea but it is not going to solve to your problem. That change will just prevent accumulated errors of a few millisecs creeping in.

...R

I want to make one thing clear. Is Arduino Mega capable of doing so many thing at once? Are there any limits? For example if I use all digital pins, all analog pins reading everything at the same time. I know I have many libraries, but I don't have skills to write for e.g. my own or manipulate with PORTs directly.

Dragonsired1: I want to make one thing clear. Is Arduino Mega capable of doing so many thing at once? Are there any limits?

The fact is that it can only do one thing at a time. But it can do things very quickly so it can appear to be doing severla things at a time. Using digitalRead() takes a few microseconds. Using analogRead() takes about 100 µsecs IIRC.

The limits start to emerge if you are asking it to do so many computations that it cannot jump from one task to the next fast enough. And, unfortunately, some of the libraries have been written very carelessly with no thought for minimising the time they take to complete their tasks.

...R

[SOLVED] The problem wasn't surprisingly in code but in hardware part. The issue was discussed here: https://forum.arduino.cc/index.php?topic=236974.15 I just added 10K ohm resistor VCC on HX711 PCB and now I increased SPS from 10 to 80 and there's no second skipping anymore. Thank all of you for providing me help and tips. Really appreciate.

Dragonsired1: [SOLVED] The problem wasn't surprisingly in code but in hardware part. ...

I wonder if the real problem was the way the HX711 library was implemented? Presumably it starts a reading and waits until it finishes. With many of those sensors it is possible to separate the code for starting a reading from the code for collecting the answer so that other stuff can be done by the Arduino while the reading is in progress.

...R