How to get arduino to print something excatly once every milisecond?

Hi. I’m trying to measure some data from rotary encoder. I’ve done it with interrupts, but the problem is that when the encoder blade is rought half covering the sensor, I get false counts. I was thinking of using analog measurements and make a while loop that checks if millis is big enough to run the code. The problem that occurs is that sometimes it takes more than a millisecond to preform the code, even though when I haven’t gave it any conditioning, it performed roughly 8 times per milisecond.

So, my question is, how do i make arduino do the task excatly once every ms (or any other period that I choose). Thanks in advance!

int voltage;
int table[400];
int time[400];
int n;
bool finish;
int ttime;


void setup() {
  pinMode(9, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  digitalWrite(5, HIGH);
  Serial.begin(115200);
  digitalWrite(3, 0);
  analogWrite(9, 90);
  n = 0;
  finish = 0;
  ctime = 0;
}

void loop() {
  if (n < 400) {
    if (millis() - time >= 1) {
      voltage = analogRead(A0);
      table[n] = voltage;
      time[n] = millis();
      n++;
      ttime = millis();
    }
  }
  else if (!finish) {
    finish = true;
    analogWrite(9, 0);
    for (n = 0; n < 400; n++)
    {
      Serial.print(time[n]); Serial.print("\t"); Serial.println(table[n]);
    }

  }
}

ggggggg.jpg

This time:

if (millis() - time >= 1) {

Isn't the same as this one:

      ttime = millis();

and ttime should be declared uint32_t (aka unsigned long)

Pete

int table[400];
unsigned long time[400];

These are very large arrays. Which Arduino board are you using ?

el_supremo:
This time:

if (millis() - time >= 1) {

Isn't the same as this one:

      ttime = millis();

and ttime should be declared uint32_t (aka unsigned long)

Pete

thanks!

As I was translating this code from my language to english, one 'time' must have slipped!

UKHeliBot, I'm using UNO. It says, that I use 87% of dynamic memory. I lowered array size to 200, and the problem still occurs.

Did you change the data type of the time array to unsigned long ?

You can't Serial.print every millisecond.
You need at least 6 millisecond to Serial.print something in most arduino boards.

UKHeliBob, yes I changed it.

GrOnThOs, I'm saving values into array and then print whole array at the end.

If there any other possible workaround? For instance to to add some kind of buffer zone to digitalRead (similar to how flip-flop works), so that it has to reach some low value, before being able to change position? I'm using Pololu optical encoder Pololu - Optical Encoder Pair Kit for Micro Metal Gearmotors, 5V.

UKHeliBob, yes I changed it.

So how are the arrays declared now ?

bwenox:
GrOnThOs, I'm saving values into array and then print whole array at the end.

Then perhaps you should edit the subject to say "How to get arduino to save something excatly once every milisecond?"

UKHeliBob:
So how are the arrays declared now ?

int voltage;
int table[200];
int timee[200];
int n;
bool finish;
unsigned long ttimee;

void setup() {
  pinMode(9, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  digitalWrite(5, HIGH);
  Serial.begin(115200);
  digitalWrite(3, 0);
  analogWrite(9, 90);
  n = 0;
  finish = 0;
  ttimee = 0;
}

void loop() {
  if (n < 200) {
    if (millis() - ttimee >= 1) {
      voltage = analogRead(A0);
      table[n] = voltage;
      timee[n] = millis();
      n++;
      ttimee = millis();
    }
  }
  else if (!finish) {
    finish = true;
    analogWrite(9, 0);
    for (n = 0; n < 200; n++)
    {
      Serial.print(timee[n]); Serial.print("\t"); Serial.println(table[n]);
    }

  }
}

The normal millis() counter actually increments every 1024 microseconds; slightly longer than a millisecond. What that means is is that trying to do something every millisecond will be slightly slow, and every 50ms or so, you'll skip a millisecond (millis() result will increment by 2 instead of 1)

If that's not acceptable, you can probably use one of the "timer2" libraries to get interrupts that show up exactly every millisecond (at the expense of losing two PWM outputs.)

westfw:
If that's not acceptable, you can probably use one of the "timer2" libraries to get interrupts that show up exactly every millisecond (at the expense of losing two PWM outputs.)

Or use micros() rather than millis() ?

...R

Robin2, if I use micros(), it takes 223 ms to finish writing an array, compared to 204 ms with millis. Don't know why though.

Possible solution:
Instead of defining a new variable ttimee, I did it like this: When printing out an array, it says it prints it out every ms, so I guess it's all good?

    if (millis()  >= n) {
      voltage = analogRead(A0);
      table[n] = voltage;
      timee[n] = millis();
      n++;
    }

The array where you save the value of millis() must be declared as unsigned long

bwenox:
Robin2, if I use micros(), it takes 223 ms to finish writing an array, compared to 204 ms with millis. Don’t know why though.

I wonder which is correct?

…R

The normal millis() counter actually increments every 1024 microseconds; slightly longer than a millisecond.

Is this number always the same or depends of arduino board environment temperature?

GrOnThOs:
Is this number always the same or depends of arduino board environment temperature?

The count won't change with temperature but the speed of the oscillator probably will.

By the way I'm not convinced that it divides by 1024. I think it divides by 1000. I see this code in the file wiring.c

#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)

...R

UKHeliBob, changed to array to unsigned long, but I get the same result.

bwenox:
UKHeliBob, changed to array to unsigned long, but I get the same result.

I have lost track of the problem with your current code.

Please explain the current problem and post your complete current code so that we can try it for ourselves.

UKHeliBob:
I have lost track of the problem with your current code.

Please explain the current problem and post your complete current code so that we can try it for ourselves.

Sorry about that.

I’m trying to make Arduino to save some value of rotaryencoder once every 1 ms (or some other time I choose - 3, 5 … ms)

Problem:
My current code

int voltage;
int table[200];
unsigned long timee[200];
int n;
bool finish;
unsigned long ttimee;


void setup() {
  pinMode(9, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  digitalWrite(5, HIGH);
  Serial.begin(115200);
  digitalWrite(3, 0);
  analogWrite(9, 90);
  n = 0;
  finish = 0;
  ttimee = 0;
}

void loop() {
  if (n < 200) {
    if (millis() - ttimee >= 1) {
      voltage = analogRead(A0);
      table[n] = voltage;
      timee[n] = millis();
      n++;
      ttimee = millis();
    }
  }
  else if (!finish) {
    finish = true;
    analogWrite(9, 0);
    for (n = 0; n < 200; n++)
    {
      Serial.print(timee[n]); Serial.print("\t"); Serial.println(table[n]);
    }

  }
}

skips a ms sometimes.