Pages: [1]   Go Down
Author Topic: Arduino drops time with interrupt time measurement  (Read 679 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi ,
I used a Arduino Duemilanove to generate a 5V trigger signal to be measured by itself through an interrupt (So the microcontroller feeds the trigger is the same as the one measuring it). This is my code

Code:
int pin = 13;
volatile int state = LOW;
const int ledPin =  12;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 100;           // interval at which to blink (milliseconds)

int trigger = 13;     // Trigger Ausgnag
unsigned long microshigh1;  //Microsekunden wenn der Trigger auf HIGH geht- vorheriger  Trigger
unsigned long microshigh2;  //Microsekunden wenn der Trigger auf HIGH geht- aktueller Trigger
unsigned long deltamicros;  //Abstand zweier high Flanken


void setup()
{
  //Wie werden die Arduino ÜPins benutzt?
  Serial.begin(115200);
  pinMode(pin, OUTPUT);
  attachInterrupt(0, ignite, CHANGE);  //put interrupt on pin 2--->  Triggereingang
  pinMode(ledPin, OUTPUT);// Virtueller trigger

}
void loop()

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}


void ignite()
{
  state = !state;
  digitalWrite(pin, state);
  digitalWrite(10, LOW);
  microshigh2 = micros();

  deltamicros= microshigh2-microshigh1;
  Serial.println(deltamicros);
  microshigh1=  microshigh2;
}

The result is the following received by the serial out:

Measured
   time   Variation
101396   
101376   -20
100352   -1024
101376   1024
101372   -4
100356   -1016
101372   1016
101384   12
100344   -1040
101380   1036
100356   -1024
101372   1016

As you see there is pretty much of a variation although I used and interrupt. is that normal and I should not expect a better result?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 197
Posts: 12744
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Wrong datatypes; they are supposed to be unsigned long...

unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long interval = 100;           // interval at which to blink (milliseconds)




  attachInterrupt(0, ignite, CHANGE);  //put interrupt on pin 2--->  Triggereingang

+

void ignite()
{
  Serial.println(deltamicros);
}


=

Bad idea.
« Last Edit: July 28, 2012, 02:01:37 am by Coding Badly » Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're right. I changed it. Is that the root cause of the timing variation...?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 197
Posts: 12744
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Very likely.
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tried the changed code. Is the modification what you have meant?


First the results in microseconds:
101372   
100356   -1016
101372   1016
101380   8
100348   -1032
101380   1032
101372   -8
100356   -1016
101372   1016
100352   -1020
101376   1024
101380   4
100352   -1028
101376   1024
101372   -4
100352   -1020
101376   1024
101380   4
101372   -8


This is the code

Code:
int pin = 13;
volatile int state = LOW;
const int ledPin =  12;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long interval = 100;           // interval at which to blink (milliseconds)

int trigger = 13;     // Trigger Ausgnag
unsigned long microshigh1;  //Microsekunden wenn der Trigger auf HIGH geht- vorheriger  Trigger
unsigned long microshigh2;  //Microsekunden wenn der Trigger auf HIGH geht- aktueller Trigger
unsigned long deltamicros;  //Abstand zweier high Flanken


void setup()
{
  //Wie werden die Arduino ÜPins benutzt?
  Serial.begin(115200);
  pinMode(pin, OUTPUT);
  attachInterrupt(0, ignite, CHANGE);  //put interrupt on pin 2--->  Triggereingang
  pinMode(ledPin, OUTPUT);// Virtueller trigger

}
void loop()

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

void ignite()
{
  state = !state;
  digitalWrite(pin, state);
  digitalWrite(10, LOW);
  microshigh2 = micros();
  deltamicros= microshigh2-microshigh1;
 Serial.println(deltamicros);
  microshigh1=  microshigh2;
}

This wasn't the root cause. I tried to put the microshigh1 and 2 into volatile memory state improving speed...no success as well
Logged

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11672
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Don't do serial I/O in an interrupt routine - its takes forever, keep interrupt routine lean as its blocking other interrupts until it returns.
Logged

[ I won't respond to messages, use the forum please ]

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

MarkT,
in general I do agree, but
- I need to know if the interrupt is working with a minimum (or at least a defined) delay
- the code shows an intervall of 100mS at 115200baud which should be quick enough to submit the data
- the serial data submission is after the interrupt work...shouldn't lead to a delay

But anyhow I do agree that this is not optimum, but I do not know any other way to control function accuracy and I do not have a oscilloscope
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This wasn't the root cause. I tried to put the microshigh1 and 2 into volatile memory state improving speed...no success as well

Volatile memory?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

MarkT,
in general I do agree, but

Don't do Serial.print inside your ISR. Then get back to us about your problems.
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ahh- I misunderstood all of you not using SerialPrint at all. Sorry! Now I changed the code and put the command in the loop

Code:
void loop()

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
 Serial.println(deltamicros);
  }
}

I decreased the speed of blinking to give more time for SerialPrintThe result remains unchanged. Still 1mS variation:

1001504
1001468
1000448
1001476
1000448
1001468
1000448
1001472
1000448

Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Now I changed the code
And posted only part of it...
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
int pin = 13;
volatile int state = LOW;
const int ledPin =  12;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long interval = 1000;           // interval at which to blink (milliseconds)

int trigger = 13;     // Trigger Ausgnag
unsigned long microshigh1;  //Microsekunden wenn der Trigger auf HIGH geht- vorheriger  Trigger
unsigned long microshigh2;  //Microsekunden wenn der Trigger auf HIGH geht- aktueller Trigger
unsigned long deltamicros;  //Abstand zweier high Flanken


void setup()
{
  //Wie werden die Arduino ÜPins benutzt?
  Serial.begin(115200);
  pinMode(pin, OUTPUT);
  attachInterrupt(0, ignite, CHANGE);  //put interrupt on pin 2--->  Triggereingang
  pinMode(ledPin, OUTPUT);// Virtueller trigger

}
void loop()

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
 Serial.println(deltamicros);
  }
}


void ignite()
{
 
  digitalWrite(pin, state);
  digitalWrite(10, LOW);
  microshigh2 = micros();
  deltamicros= microshigh2-microshigh1;
 
  microshigh1=  microshigh2;
 state = !state;
}
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
unsigned long deltamicros;  //Abstand zweier high Flanken
Used by loop() and the ISR. Should, therefore, by volatile.

The deltamicros variable takes time to convert to a string, and to shift the bytes to the serial port. An interrupt can occur while that is happening. You need to copy the valuable to another location, and output the copy.

Even during a copy operation, while 4 bytes are copied, an interrupt can occur. So, you need to disable interrupts before the copy starts. and then enable them again as soon as the copy completes.

What is generating the external interrupt? Are you sure that it is consistently happening exactly one second apart?
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dear all,
I have found the issue. The code for blinking the trigger is based on mS and the ISR is based on microseconds. So I changed the code to the following:

Code:
int pin = 13;
volatile int state = LOW;
const int ledPin =  12;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long interval = 1000;           // interval at which to blink (milliseconds)

int trigger = 13;     // Trigger Ausgnag
volatile unsigned long microshigh1;  //Microsekunden wenn der Trigger auf HIGH geht- vorheriger  Trigger
volatile unsigned long microshigh2;  //Microsekunden wenn der Trigger auf HIGH geht- aktueller Trigger
volatile unsigned long deltamicros;  //Abstand zweier high Flanken


void setup()
{
  //Wie werden die Arduino ÜPins benutzt?
  Serial.begin(115200);
  pinMode(pin, OUTPUT);
  attachInterrupt(0, ignite, CHANGE);  //put interrupt on pin 2--->  Triggereingang
  pinMode(ledPin, OUTPUT);// Virtueller trigger

}
void loop()

  unsigned long currentMillis = micros();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
 Serial.println(deltamicros);
  }
}


void ignite()
{
 
  digitalWrite(pin, state);
  digitalWrite(10, LOW);
  microshigh2 = micros();
  deltamicros= microshigh2-microshigh1;
 
  microshigh1=  microshigh2;
 state = !state;
}

And the result with 1000microseconds is reasonable good including SerialPrint:

Deltamicros   Difference
100000   
100012   12
100004   -8
100000   -4
100012   12
100004   -8
100012   8
100000   -12
100004   4
100012   8
100000   -12
100004   4
100012   8
100004   -8
100004   0
100008   4
100000   -8
100008   8
100008   0
100012   4


Thank you all for your support!
Logged

Pages: [1]   Go Up
Jump to: