Help swapping micros() to timer1 on nano mega328p

Hey i wrote this code with some help, to measure the time between events and it seems to run pretty well in first tests.
I would like to measure more precise, as right now its seems to count in 4micros steps when using micros().
I got a hint to use timer1 in a previous post, does someone know how to or can swap micros() in my code to be counted with timer1 ?
Or is this not possible ?
Thanks upfront !
Benni

int diode1 = 2;
int diode2 = 4;
int diode3 = 3;
boolean timingFlag;
boolean timingFlag2;
boolean timingFlag3;


void setup(void) {
  Serial.begin(115200);
  pinMode(diode1, INPUT);
  pinMode(diode2, INPUT);
  pinMode(diode3, INPUT);
  timingFlag = false;
  timingFlag2 = false;
  timingFlag3 = false;
}

void loop(void) {
  static unsigned long Stop1;
  static unsigned long Start1;
  static unsigned long Stop2;
  static unsigned long Start2;
  static unsigned long Stop3;
  static unsigned long Start3;
  digitalRead(diode1);
  digitalRead(diode2);
  digitalRead(diode3);

  
  if (timingFlag == false && digitalRead(diode1) == HIGH ) {
    Start1 = micros();
    timingFlag = true;
  }
  if (timingFlag == true && digitalRead(diode1) == LOW ) {
    Stop1 = micros();
    timingFlag = false;
  }

  
   if (timingFlag2 == false && digitalRead(diode2) == HIGH ) {
    Start2 = micros();
    timingFlag2 = true;
  }
  if (timingFlag2 == true && digitalRead(diode2) == LOW ) {
    Stop2 = micros();
    timingFlag2 = false;
  }
  
  
  if (timingFlag3 == false && digitalRead(diode3) == HIGH ) {
    Start3 = micros();
    timingFlag3 = true;

  }
  if (timingFlag3 == true && digitalRead(diode3) == LOW ) {
    Stop3 = micros();
    unsigned long elapsedMicroseconds = Stop1 - Start1;
    unsigned long elapsedMicroseconds2 = Stop2 - Start2;
    unsigned long elapsedMicroseconds3 = Stop3 - Start3;
    unsigned long laufzeit1 = Start3 - Start1;
    unsigned long laufzeit2 = Stop3 - Stop1;
    Serial.print("Verschlusszeit1 = ");
    Serial.println(elapsedMicroseconds / 1000.0, 3);
    Serial.print("Verschlusszeit2 = ");
    Serial.println(elapsedMicroseconds2 / 1000.0, 3);
    Serial.print("Verschlusszeit3 = ");
    Serial.println(elapsedMicroseconds3 / 1000.0, 3);
    Serial.print("Vorhang1 = ");
    Serial.println(laufzeit1 / 1000.0, 3);
    Serial.print("Vorhang2 = ");
    Serial.println(laufzeit2 / 1000.0, 3);
    timingFlag3 = false;


  }
}

Yes, you can use the hardware timers to get greater resolution than the 4 microsecond increment of micros().

It’s not clear to me that given your timing code based on polling the state of pins with digitalRead() that a higher resolution is actually valuable. How are you using your time interval measurements?

One of the best tutorials on the avr hardware timers is by Nick Gammon.

https://www.gammon.com.au/timers

How long a time period do you wish to measure?

Timer1 is a 16 bit timer, and and normal mode it will count up from 0 to 65535 before it rolls over and starts counting up again.

If you set the prescaler of the timer to 8, each count is .5 microsecond. Measuring a period of up to 32762 microsecond is then very easy and does not involve accounting for the number of roll overs. Simple subtraction of the unsigned integers will give the elapsed period.

You can set up the timer in normal mode with a prescaler =8 like this

TCCR1A = 0; //clear all ide timer presets used to enable analogWrite()
TCCR1B = 0; //clear all ide timer presets used to enable analogWrite()
TCCR1B = 1<< CS11; //set prescaler 8 for .5 microsecond tick

Then everywhere in your code everywhere you use micros() substitute TCNT1 which is the timer count value. Subtract the start values from the stop values and you will have .5 microsecond tick counts.

There are far more accurate techniques which use the input capture features of the timers. They are covered in the Gammon tutorial.

Hey thanks for the reply @cattledog.
It’s for checking the shutter of old cameras with a focal plane shutter.
It has two curtains the first curtain runs from one side to the other opening the window the second closes the window with some delay.
So im measuring the time where each of the three Diode gets light =shutter times at 3 points.
As well as the time the first curtain needs from one side to the other(diode1 gets light -diode3 gets light) and the time the second curtain needs from one side to the other(diode1 turns off - diode 3 turns off)
Im gonna check out the video.
The longest time will be normally around 1000milliseconds, never more then 2000milliseconds.
The shortest time will be around 0,490 milliseconds
That’s for the shuttertimes.
The curtain runtime is around 10-12 milliseconds.
Im using micros as I want 3 numbers behind the comma.
How precise can I get this code with this setup ?
Does the timer work with this times ?
Thanks
Benjamin

The longest time will be normally around 1000milliseconds, never more then 2000milliseconds.
The shortest time will be around 0,490 milliseconds
That's for the shuttertimes.
The curtain runtime is around 10-12 milliseconds.
Im using micros as I want 3 numbers behind the comma.
How precise can I get this code with this setup ?
Does the timer work with this times ?

If the shutter times are longer than approximately 32 milliseconds you will need to count timer overflows, and that complicates the code. Doable, but more complex.
There are examples in the Gammon tutorial of counting the timer overflows and adding the value into the counts.

The prescaler of 8 sets the precision to .5 microsecond. That's what limits the timer run without overflow to the 32 millisecond period. If you slow the timer down with a prescaler of 64 you get the same 4 microsecond resolution of the micros() function.

Even with very short shutter times of 490 microseconds, are you certain that the 4 microsecond resolution of micros() i.e. approximately 1% is a problem for what you are trying to check?

Alright, the 1% at 1/2000 is actually precise enough.
I just thought if it’s easy to do it would be worth it, but this way it seems it’s not worth the hustle.
Thank you for the help

It should be simple for the shorter shutter times. Why not give it a try? You will feel good about the half microsecond resolution even if it doesn't mean anything :slight_smile:

// Fast Timer
// Returns the current time in 16th of a microsecond.
// Overflows every 268.435456 seconds.


// Note: Since this uses Timer1, Pin 9 and Pin 10 can't be used for
// analogWrite().


void setup()
{
  Serial.begin(300);
  while (!Serial);
  StartFastTimer();
}


void StartFastTimer()
{
  noInterrupts ();  // protected code
  // Reset Timer 1 to WGM 0, no PWM, and no clock
  TCCR1A = 0;
  TCCR1B = 0;


  TCNT1 = 0;  // Reset the counter
  TIMSK1 = 0; // Turn off all Timer1 interrupts


  // Clear the Timer1 Overflow Flag (yes, by writing 1 to it)
  // so we don't get an immediate interrupt when we enable it.
  TIFR1 = _BV(TOV1);


  TCCR1B = _BV(CS10); // start Timer 1, no prescale
  // Note: For longer intervals you could use a prescale of 8
  // to get 8 times the duration at 1/8th the resolution (1/2
  // microsecond intervals).  Set '_BV(CS11)' instead.


  TIMSK1 = _BV(TOIE1); // Timer 1 Overflow Interrupt Enable
  interrupts ();
}


volatile uint16_t Overflows = 0;


ISR(TIMER1_OVF_vect)
{
  Overflows++;
}


unsigned long FastTimer()
{
  unsigned long currentTime;
  uint16_t overflows;


  noInterrupts();
  overflows = Overflows;  // Make a local copy


  // If an overflow happened but has not been handled yet
  // and the timer count was close to zero, count the
  // overflow as part of this time.
  if ((TIFR1 & _BV(TOV1)) && (TCNT1 < 1024))
    overflows++;


  currentTime = overflows; // Upper 16 bits
  currentTime = (currentTime << 16) | TCNT1;
  interrupts();


  return currentTime;
}


void loop()
{
  static unsigned long previousTime = 0;
  static unsigned long currentTime = FastTimer();


  Serial.println(currentTime - previousTime);
  previousTime = currentTime;
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.