previousMicros - currentMicros losing few miliseconds

I have I gues code problem with Arduino Micro. After I do mouse.move command I start counting “micros” until “val” returns true from A0 pin, then “lag” counts how much time passed, but I get different results when “wait” changes. Like example default “wait” is 250,000 arduino returns “lag” result of 83ms, but when I change “wait” to 3,000,000 it returns 87ms. What is happening? I made input latency tester, but if it returns different when using different intervals between samples it is no good.

if (state == 1 && s <= samples) {
          wait = 250000 * t;
          sevseg.setNumber(s);
          state = 2;
          previousMicros = currentMicros;
        }
        if (currentMicros - previousMicros >= wait && state == 2) {
          Mouse.move(distance, 0, 0);
          digitalWrite(ledPin, HIGH);
          previousMicros = currentMicros;
          state = 3;
        }
        if (val <= 980 && state == 3) {
          lag = currentMicros - previousMicros;
          digitalWrite(ledPin, LOW);
          Mouse.move(-distance, 0, 0);
          previousMicros = currentMicros;
          s = s + 1;
          PC = 1;
          state = 4;

        }
        if (state == 4) {
          if (lag >= 1000000) {
            lag2 = lag / 1000;
            sevseg.setNumber(lag2);

Full code: Input Latency eeprom - Pastebin.com

Please post your complete code we should not have to go to some other site to review it.

Sorry. Here it is:

#include <EEPROM.h>
#include <AnalogMultiButton.h>
#include <Mouse.h>
#include <SevSeg.h>
SevSeg sevseg; //Instantiate a seven segment object

const int BUTTONS_PIN = A1;
const int BUTTONS_TOTAL = 4;
const int BUTTONS_VALUES[BUTTONS_TOTAL] = {0, 318, 486, 589};
const int BUTTON_MODE = 0;
const int BUTTON_MINUS = 1;
const int BUTTON_PLUS = 2;
const int BUTTON_START = 3;


unsigned long previousMicros = 0;
unsigned long previousMicros2 = 0;
const int ledPin = 13;

int analogPin = 0;
int val = 0;

unsigned long lag = 0;
unsigned long lag2;
unsigned long wait;
int state = 0;
unsigned long var2 = 0;
int refresh = 1;
int s;
int samples;
int setSamples;
int t;
int lcd = 1;
int location = 0;
int8_t distance;
int mode = 1;
int i = 101;
int PC = 0;
int addressDistance = 0;
int addressInterval = 1;
int addressSamples = 2;
float skaicius;
float skaicius2;

AnalogMultiButton buttons(BUTTONS_PIN, BUTTONS_TOTAL, BUTTONS_VALUES);

void setup() {
  Mouse.begin();
  byte numDigits = 4;
  byte digitPins[] = {1, 4, 5, 7};
  byte segmentPins[] = {2, 6, 9, 11, 12, 3, 8, 10};
  bool resistorsOnSegments = true; // 'false' means resistors are on digit pins
  byte hardwareConfig = COMMON_CATHODE; // See README.md for options
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);

  pinMode(ledPin, OUTPUT);
  setSamples = EEPROM.read(addressSamples);
  distance = EEPROM.read(addressDistance);
  t = EEPROM.read(addressInterval);

  Serial.begin(9600);
}
void loop() {
  unsigned long currentMicros = micros();
  val = analogRead(analogPin);
  buttons.update();

  if (buttons.isPressedAfter(BUTTON_MODE, 3000)) {
    setSamples = 50;
    EEPROM.write(addressSamples, setSamples);
    distance = 50;
    EEPROM.write(addressDistance, distance);
    t = 1;
    EEPROM.write(addressInterval, t);
  }

  switch (mode)
  {
    case 1:
      {
        if (lcd == 1) {
          sevseg.setNumber(1);
          samples = setSamples;
        }
        if (state == 1 && s <= samples) {
          wait = 250000 * t;
          sevseg.setNumber(s);
          state = 2;
          previousMicros = currentMicros;
        }
        if (currentMicros - previousMicros >= wait && state == 2) {
          Mouse.move(distance, 0, 0);
          digitalWrite(ledPin, HIGH);
          previousMicros = currentMicros;
          state = 3;
        }
        if (val <= 980 && state == 3) {
          lag = currentMicros - previousMicros;
          digitalWrite(ledPin, LOW);
          Mouse.move(-distance, 0, 0);
          previousMicros = currentMicros;
          s = s + 1;
          PC = 1;
          state = 4;

        }
        if (state == 4) {
          if (lag >= 1000000) {
            lag2 = lag / 1000;
            sevseg.setNumber(lag2);

          } else {
            lag2 = lag / 100;
            sevseg.setNumber(lag2, 1);

          }
          if (PC == 1) {
            skaicius2 = lag;
            skaicius = skaicius2 / 1000;
            Serial.println(skaicius);
            PC = 0;
          }
          if (currentMicros - previousMicros >= wait && PC == 0) {
            state = 1;
          }
        }
        if (buttons.onPress(BUTTON_START))
        {
          state = 1;
          s = 1;
          lcd = 10;
        }
        else if (buttons.onPress(BUTTON_MODE))
        {
          mode = 2; // Switch to mode 2
          lcd = mode;
          state = 5;
        }
        break;
      }
    case 2:
      {
        if (lcd == 2) {
          sevseg.setNumber(2);
        }
        if (refresh == 1) {
          previousMicros = currentMicros;
          refresh = 0;
        }
        if (lcd == 21 && currentMicros - previousMicros >= 200000) {
          sevseg.setNumber(val);
          refresh = 1;
        }
        if (val <= 980) {
          digitalWrite(ledPin, HIGH);
        } else {
          digitalWrite(ledPin, LOW);
        }
        if (buttons.onPress(BUTTON_START))
        {
          if (location == 0) {
            Mouse.move(distance, 0, 0);
            location = 1;
          } else {
            Mouse.move(-distance, 0, 0);
            location = 0;
          }
          lcd = 21;
        }
        else if (buttons.onPress(BUTTON_MODE))
        {
          mode = 3; // Switch to mode 3
          lcd = mode;
          if (location == 1) {
            Mouse.move(-distance, 0, 0);
            location = 0;
          }
        }
        break;
      }
    case 3:
      {
        if (lcd == 3) {
          sevseg.setNumber(3);
        }
        if (refresh == 1) {
          previousMicros = currentMicros;
          refresh = 0;
        }
        if (lcd == 31 && currentMicros - previousMicros >= 200000) {
          sevseg.setNumber(val);
          refresh = 1;
        }
        if (currentMicros - previousMicros2 >= 1000000 && lcd == 30) {
          lcd = 31;
        }
        if (val <= 980) {
          digitalWrite(ledPin, HIGH);
        } else {
          digitalWrite(ledPin, LOW);
        }
        if (buttons.onPress(BUTTON_PLUS))
        {
          if (location == 0) {
            Mouse.move(distance, 0, 0);
            location = 3;
          }
          else if (location == 3 && distance <= 120) {
            Mouse.move(5, 0, 0);
            distance = distance + 5;
            EEPROM.update(addressDistance, distance);
          }
          sevseg.setNumber(distance);
          lcd = 30;
          previousMicros2 = currentMicros;
        }
        else if (buttons.onPress(BUTTON_MINUS))
        {
          if (location == 0) {
            Mouse.move(distance, 0, 0);
            location = 3;
          }
          else if (location == 3 && distance >= -120) {
            Mouse.move(-5, 0, 0);
            distance = distance - 5;
            EEPROM.update(addressDistance, distance);
          }
          sevseg.setNumber(distance);
          lcd = 30;
          previousMicros2 = currentMicros;
        }
        else if (buttons.onPress(BUTTON_START))
        {
          if (location == 0) {
            Mouse.move(distance, 0, 0);
            location = 3;
          } else {
            Mouse.move(-distance, 0, 0);
            location = 0;
          }
          lcd = 31;
        }
        else if (buttons.onPress(BUTTON_MODE))
        {
          mode = 4; // Switch to mode 4
          lcd = mode;
          if (location == 3) {
            Mouse.move(-distance, 0, 0);
            location = 0;
          }
        }
        break;
      }
    case 4:
      {
        if (lcd == 4) {
          sevseg.setNumber(4);
        }
        if (buttons.onPress(BUTTON_PLUS))
        {
          if (lcd == 4) {
            sevseg.setNumber(t * 5, 1);
            lcd = 40;
          } else if (t <= 19) {
            t = t + 1;
            EEPROM.update(addressInterval, t);
            sevseg.setNumber(t * 5, 1);
          }
        }
        else if (buttons.onPress(BUTTON_MINUS))
        {
          if (lcd == 4) {
            sevseg.setNumber(t * 5, 1);
            lcd = 40;
          } else if (t >= 2) {
            t = t - 1;
            EEPROM.update(addressInterval, t);
            sevseg.setNumber(t * 5, 1);
          }
        }
        else if (buttons.onPress(BUTTON_MODE))
        {
          mode = 5; // Switch to mode 5
          lcd = mode;
        }
        break;
      }
    case 5:
      {
        if (lcd == 5) {
          sevseg.setNumber(5);
        }
        if (buttons.onPress(BUTTON_PLUS))
        {
          if (lcd == 5) {
            sevseg.setNumber(setSamples);
            lcd = 50;
          } else if (setSamples <= 240) {
            setSamples = setSamples + 10;
            EEPROM.update(addressSamples, setSamples);
            sevseg.setNumber(setSamples);
          }
        }
        else if (buttons.onPress(BUTTON_MINUS))
        {
          if (lcd == 5) {
            sevseg.setNumber(setSamples);
            lcd = 50;
          } else if (setSamples >= 10) {
            setSamples = setSamples - 10;
            EEPROM.update(addressSamples, setSamples);
            sevseg.setNumber(setSamples);
          }
        }
        else if (buttons.onPress(BUTTON_MODE))
        {
          mode = 1; // Switch to mode 1
          lcd = mode;
        }
        break;
      }
  }
  sevseg.refreshDisplay();
}

My WAG tells me you should be reading the analog pin closer to where the return value is used.

In lieu of hardware / project details I suspect that's the best answer you are going to get.

Like that? The next line checks for value, but problem persists.

if (currentMicros - previousMicros >= wait && state == 2) {
         Mouse.move(distance, 0, 0);
         digitalWrite(ledPin, HIGH);
         previousMicros = currentMicros;
         state = 3;
       }
       val = analogRead(analogPin);
       if (val <= 980 && state == 3) {
         lag = currentMicros - previousMicros;
         digitalWrite(ledPin, LOW);
         Mouse.move(-distance, 0, 0);
         previousMicros = currentMicros;
         s = s + 1;
         PC = 1;
         state = 4;

       }

Stipa:
Like that?

Yup.

Stipa:
The next line checks for value, but problem persists.

Bummer.

Moved photo transistor from monitor display and put it on arduinos ledPin, results are consistent no mater what "wait" time i set, always getting measurement of 0.54ms. So could it be that mouse.move() command is influenced by micros() counting?
Edit: tried millis() instead of micros(), same result.

Stipa:
Edit: tried millis() instead of micros(), same result.

It is impossible to measure 0.54 ms using the return value from millis.

Stipa:
Moved photo transistor from monitor display and put it on arduinos ledPin...

A tiny hint about the hardware. A baby step in the right direction.

Stipa:
So could it be that mouse.move() command is influenced by micros() counting?

Could be. There are some short delays and busy loops in the USB code.

I'm lost in this. Strange things happening. In my understanding every time I send command mouse.move() after 0.5s delay, I should get different results, but I always get same results of 83ms +-0.5ms. Even after relaunching game, reconnecting arduino. If I set delay to 4s I get constant results of 77ms +- 0.5ms. Why there isn't randomization included to scatter results between frametime like example at monitor refresh rate of 60Hz results should vary at least in range of 77-93ms (1000ms/60Hz equals to 16ms). Does arduino somehow synchronizes its clock or does that HID interface only sends commands to a specific timestamps on PC? I even overclocked Arduino Micro to 1000Hz polling rate but same results I get.
P.S. Could moderators move topic to appropriate section where I could get answer?

This is the most appropriate section.

You have still not provided a description of the project.

From the reference pages.
If doing math with integers, at least one of the numbers must be followed by an L, forcing it to be a long. See the Integer Constants page for details.
So..

wait = 250000 * t;

I wonder what would happen if it was written as

wait = 3000000L * t;

I'm making input latency tester for PC using Arduino Micro and photo transistor to test various games/GPU drivers functions. Arduino Micro is connected to PC via USB cable and photo transistor is mounted on monitors screen. Idea is to move mouse that image on the screen, where photo transistor is located, changes from dark to bright thus detecting "output" while mouse movement is "input". Calculated results between output and input is displayed on 4-digit 7-segment display and serial monitor from where it is copied to spreadsheet by hand.
Some game/GPU drivers functions require time to rest, so for that I want to introduce changeable delay before making mouse to move.

Slumpert:
From the reference pages.
If doing math with integers, at least one of the numbers must be followed by an L, forcing it to be a long. See the Integer Constants page for details.
So..

wait = 250000 * t;

I wonder what would happen if it was written as

wait = 3000000L * t;

Same thing, problem remains.

I suggest changing this

previousMicros = currentMicros;

to

previousMicros = micros()

Your present approach would be fine if you were using millis() because millis() updates 1000 times slower.

...R

Robin2:
I suggest changing this

previousMicros = currentMicros;

to

previousMicros = micros()

Your present approach would be fine if you were using millis() because millis() updates 1000 times slower.

...R

Same. Even tried with millis() and problem repeats itself.

Stipa:
Same. Even tried with millis() and problem repeats itself.

You need to post the updated version of the program.

If your project needs to use micros() I can't imagine how you could use millis() in its place.

If this was my problem I would try simplifying the program (taking out chunks of code) to try to identify the cause of the problem.

...R

Robin2:
You need to post the updated version of the program.

If your project needs to use micros() I can’t imagine how you could use millis() in its place.

If this was my problem I would try simplifying the program (taking out chunks of code) to try to identify the cause of the problem.

…R

It doesn’t matter what to use, micros () or millis(). I’m just making changes accordingly to what I use.
Cut out code chunks as you suggested but results are the same.
Just forgot to mention that first sample I take after pressing START button returns randomized result as it should do but consequent samples return approximately the same numbers:

5 seconds delay, results in microseconds 1st run:
88912
86976
86976
86984
86728
86988
86984
86732
86736
86976

2nd run:
79752
86972
86976
86976
86968
86744
86984
86748
86744
86736

0.5 second delay:
80472
83120
83120
83128
83128
83128
83368
83132
83128
83120

Code used:

#include <AnalogMultiButton.h>
#include <Mouse.h>

const int BUTTONS_PIN = A1;
const int BUTTONS_TOTAL = 4;
const int BUTTONS_VALUES[BUTTONS_TOTAL] = {0, 318, 486, 589};
const int BUTTON_MODE = 0;
const int BUTTON_MINUS = 1;
const int BUTTON_PLUS = 2;
const int BUTTON_START = 3;

int analogPin = 0;
int val = 0;

unsigned long previousMicros = 0;
unsigned long lag = 0;
unsigned long wait;
int state = 0;
int s;
unsigned long t = 1;

AnalogMultiButton buttons(BUTTONS_PIN, BUTTONS_TOTAL, BUTTONS_VALUES);

void setup() {
  Mouse.begin();
  Serial.begin(9600);
}
void loop() {
  unsigned long currentMicros = micros();
  val = analogRead(analogPin);
  buttons.update();

  if (buttons.onPress(BUTTON_START))
  {
    wait = 500000L * t; //time delay to start
    state = 1;
    s = 1;
  }

  if (state == 1 && s <= 10) {
    previousMicros = currentMicros;
    state = 2;
  }

  if (currentMicros - previousMicros >= wait && state == 2) { //delay time till start of mouse.move
    previousMicros = currentMicros;
    Mouse.move(50, 0, 0); //move mouse to bright spot on monitor
    state = 3;
  }

  if (val <= 980 && state == 3) { //wait for response from photo transistor mounted on monitor
    lag = currentMicros - previousMicros;
    previousMicros = currentMicros;
    Mouse.move(-50, 0, 0); //move mouse back to dark spot on monitor
    s = s + 1;
    Serial.println(lag);
    state = 1;
  }

  if (buttons.onPress(BUTTON_PLUS)) {
    t = 10;
  }
  if (buttons.onPress(BUTTON_MINUS)) {
    t = 1;
  }
}

I could get rid of buttons, but already tried that few days ago, it doesn’t influence results.

Millis() version:

#include <AnalogMultiButton.h>
#include <Mouse.h>

const int BUTTONS_PIN = A1;
const int BUTTONS_TOTAL = 4;
const int BUTTONS_VALUES[BUTTONS_TOTAL] = {0, 318, 486, 589};
const int BUTTON_MODE = 0;
const int BUTTON_MINUS = 1;
const int BUTTON_PLUS = 2;
const int BUTTON_START = 3;

int analogPin = 0;
int val = 0;

unsigned long previousMillis = 0;
unsigned long lag = 0;
unsigned long wait;
int state = 0;
int s;
unsigned long t = 1;

AnalogMultiButton buttons(BUTTONS_PIN, BUTTONS_TOTAL, BUTTONS_VALUES);

void setup() {
  Mouse.begin();
  Serial.begin(9600);
}
void loop() {
  unsigned long currentMillis = millis();
  val = analogRead(analogPin);
  buttons.update();

  if (buttons.onPress(BUTTON_START))
  {
    wait = 500L * t; //time delay to start
    state = 1;
    s = 1;
  }

  if (state == 1 && s <= 10) {
    previousMillis = currentMillis;
    state = 2;
  }

  if (currentMillis - previousMillis >= wait && state == 2) { //delay time till start of mouse.move
    previousMillis = currentMillis;
    Mouse.move(50, 0, 0); //move mouse to bright spot on monitor
    state = 3;
  }

  if (val <= 980 && state == 3) { //wait for response from photo transistor mounted on monitor
    lag = currentMillis - previousMillis;
    previousMillis = currentMillis;
    Mouse.move(-50, 0, 0); //move mouse back to dark spot on monitor
    s = s + 1;
    Serial.println(lag);
    state = 1;
  }

  if (buttons.onPress(BUTTON_PLUS)) {
    t = 10;
  }
  if (buttons.onPress(BUTTON_MINUS)) {
    t = 1;
  }
}

Stipa:
Code used:

The first program in Reply #16 is not using the suggestion I made in Reply #13.

It would also be a big help if you would describe the problem afresh by reference to that new program.

...R

Robin2:
The first program in Reply #16 is not using the suggestion I made in Reply #13.

It would also be a big help if you would describe the problem afresh by reference to that new program.

…R

Ok, I did what you suggested in Reply #13, but that had no influence on results.
I will try to describe problem referencing to new program pasted bellow. When I use “wait” value of 500,000 and forth “if (val <= 980 && state == 3)” statement goes TRUE, “lag” calculates result of ~83000 microseconds for all 10 repeats except first until “s<=10”. But when “wait” value is set at 5,000,000 “lag” returns ~86700 microseconds for all 10 repeats except first. First “lag” result seems to work fine except other 9. In my mind “lag” results shouldn’t be influenced by “wait” value. In my understanding all results should be scattered in 16.6ms frametime (1000ms/60Hz monitors refresh rate = 16.6ms frametime), unless Arduinos HID input works in different way than I’m expecting.

#include <AnalogMultiButton.h>
#include <Mouse.h>

const int BUTTONS_PIN = A1;
const int BUTTONS_TOTAL = 4;
const int BUTTONS_VALUES[BUTTONS_TOTAL] = {0, 318, 486, 589};
const int BUTTON_MODE = 0;
const int BUTTON_MINUS = 1;
const int BUTTON_PLUS = 2;
const int BUTTON_START = 3;

int analogPin = 0;
int val = 0;

unsigned long previousMicros = 0;
unsigned long lag = 0;
unsigned long wait;
int state = 0;
int s;
unsigned long t;

AnalogMultiButton buttons(BUTTONS_PIN, BUTTONS_TOTAL, BUTTONS_VALUES);

void setup() {
  Mouse.begin();
  Serial.begin(9600);
}
void loop() {
  val = analogRead(analogPin);
  buttons.update();

  if (buttons.onPress(BUTTON_START))
  {
    wait = 500000L * t; //time delay to start
    state = 1;
    s = 1;
  }

  if (state == 1 && s <= 10) {
    previousMicros = micros();
    state = 2;
  }

  if (micros() - previousMicros >= wait && state == 2) { //delay time till start of mouse.move
    previousMicros = micros();
    Mouse.move(50, 0, 0); //move mouse to bright spot on monitor
    state = 3;
  }

  if (val <= 980 && state == 3) { //wait for response from photo transistor mounted on monitor
    lag = micros() - previousMicros;
    previousMicros = micros;
    Mouse.move(-50, 0, 0); //move mouse back to dark spot on monitor
    s = s + 1;
    Serial.println(lag);
    state = 1;
  }

  if (buttons.onPress(BUTTON_PLUS)) {
    t = 10;
  }
  if (buttons.onPress(BUTTON_MINUS)) {
    t = 1;
  }
}

Thanks for the further explanation.

However I'm afraid I can't see what your program is supposed to be doing.

It seems to start with s =1 and state = 1 which puts the value of micros() into previousMicros and sets state = 2

If state = 2 and 500,000 micros have elapsed then forget the earlier value of previousMicros and replace it with micros(). Change state to 3

Then if state = 3 and there is some value from analogRead() calculate the time since previousMicros was set in the state=2 section

As far as I can see from all of that the value in the variable wait is completely irrelevant. But it would not be the first time I was wrong.

Perhaps you can provide a better description of the process you have created?

It would also help if you explain what exactly you are trying to measure. Maybe there is a better way.

...R