Arduino timer interrupt

Hello,
I am a bit new to programing for Arduino, I am trying to write a timer that starts counting at rising edge of a signal (from one of the analog pins) and then stop and store the value somewhere whenever it sees the next rising edge. Basically I want to find the period of the input signal as precise as possible. Perhaps using Timer 1 with prescale of 1 should help ?!
I appreciate if anyone could guide me on this.
Best Regards,

This might be interesting: http://forum.arduino.cc/index.php/topic,17450.0.html or Timer1 interrupt debuging - #15 by JChristensen - Programming Questions - Arduino Forum

Yeah, this is the perfect application for the Input Capture Unit. Timestamps, baby!

Many thanks for you replies. They really helped me.

Here is my code, when I run it and press on the Serial Monitor, I get an error saying "Serial 'COM5' not found. Did you select the right one from the tools > Serial Port menu" ? I compiled and uploaded the file using COM5 and it uploads the file but now that I want to see the results, it is not working. Aside from this, does the code looks working to you guys ? (This is my first try of programming in Arduino)

What I am expecting the code do is to measure the period of a signal (ie. for a square shape signal, length between a rising edge to its next rising edge).

#define icpPin 8 //

volatile unsigned int Pulses[2000]; // array holding number of ticks
volatile unsigned int over_flow_array[2000];
volatile uint8_t over_flow_count;
volatile uint8_t PulseCount; // number of pulses received in current frame

ISR(TIMER1_CAPT_vect)
{
if(bit_is_set(TCCR1B ,ICES1)==1) // If rising edge is detected
{
TCNT1 = 0; // reset the counter - 16 bit counter
if (ICR1=65536) //2^16
{
over_flow_count=over_flow_count+1;
over_flow_array[++PulseCount]=over_flow_count;
ICR1=0;
}
else
{
Pulses[++PulseCount] = ICR1;
}

}
else // falling edge was detected
{
}
}

void setup()
{
Serial.begin(9600);
pinMode(icpPin,INPUT);
PulseCount = 0;
over_flow_count=0;
//over_flow_array=;
TCCR1A = 0x00;
TCCR1B = 0x01; // No prescaler (prescaler=1)
TIMSK1 = _BV(ICIE1); // enable input capture interrupt for timer 1
}

void loop()
{

Serial.print("Overflow=");
Serial.println(over_flow_array[PulseCount]);
Serial.println("count=");
Serial.print(Pulses[PulseCount]);

}

This won't work:

     if (ICR1=65536)  //2^16

If you really want to compare ICR1, you need to use the == operator. Besides, 65536 is too big. It would wrap to 0.

However, I'm not sure that would be the best way to do it. You'll get minor inaccuracies if you reset the timer when the interrupt hits. More accurate would be to just let it run and cycle around, and use differences. That way you don't care if the ISR gets executed immediately, or if you happen to be servicing another interrupt and it takes a few cycles to get there.

There is a library: http://interface.khm.de/index.php/lab/experiments/frequency-measurement-library/
Just hack it, or use it as it's

Magician:
... or use it as it's

Many thanks for providing the link, I am trying to compile this but I get tons of errors. I imported the library and made a sketch file from the cpp file but it doesn't compile.

If appreciate if you could let me know what should I do ?

Best,

If appreciate if you could let me know what should I do ?

Some people have magic dances that they perform. Others post the code and the error messages.

One method gets results. The other gets tired muscles. Your choice.

smd_10:
Many thanks for providing the link, I am trying to compile this but I get tons of errors. I imported the library and made a sketch file from the cpp file but it doesn't compile.

How to use this forum

Post your code, inside code tags. Post your errors, inside code tags.

This is the main .cpp file:

#include <Arduino.h>
#include <FreqPeriod.h>
//#include <wiring.h>
//#include <pins_arduino.h>

volatile unsigned char FreqPeriod::f_capt;
volatile unsigned int FreqPeriod::capta;
volatile unsigned long int FreqPeriod::captd;
volatile int FreqPeriod::ocnt;

void FreqPeriod::begin(){

#if defined (AVR_ATmega168) || defined (AVR_ATmega48) || defined (AVR_ATmega88) || defined (AVR_ATmega328P) || (AVR_ATmega1280)

pinMode(5,OUTPUT);

TCCR1A =0;
TCCR1B =0;

ADCSRB &= ~(1<<ACME);
ACSR &= ~(1<<ACD) ; // Analog Comparator disable off
// ACSR |= (1<<ACBG); // Analog Comparator Bandgap reference on
ACSR |= (1<<ACIE); // Analog Comparator Interrupt enable
ACSR |= (1<<ACIC);

ACSR &= ~(1<<ACIS0); // comparator detection edge
ACSR |= (1<<ACIS1); // comparator detection edge

TCCR1B |= (1<<CS10); // set prescaler to 16 MHz
TCCR1B &= ~(0<<CS11);
TCCR1B &= ~(0<<CS12);

TCCR1B |= (1<<ICNC1); // input noise canceler on
TCCR1B &= ~(1<<ICES1); // input capture edge select =0

DIDR1 |= (1<< AIN0D); // disable digital input buffer AIN0/1
DIDR1 |= (1<< AIN1D);

TIMSK1 |= (1<<TOIE1); // Timer/Counter1, Overflow Interrupt Enable

// TIMSK0 &= ~(1<<TOIE0); // Timer/Counter0, Overflow Interrupt disable

#endif

}
//***************************************************************************
unsigned long int FreqPeriod::getPeriod() {
unsigned long int rr= 0;
if ( FreqPeriod::f_capt){
FreqPeriod::f_capt=0;
rr= FreqPeriod::captd;
}
return(rr);
}

//***************************************************************************
// Timer1 Overflow Interrupt Service
ISR(TIMER1_OVF_vect ) {
FreqPeriod::ocnt++; // count number of timer1 overflows
}
//***************************************************************************
// Analog Comparator Interrupt Service
ISR(ANALOG_COMP_vect ) {

if (!(ACSR & (1<<ACIS0))) { // comparator falling edge
digitalWrite(5,0); // reduce comparator threshold level on AIN0
ACSR |= (1<<ACIS0); // next comparator detection on rising edge

// compute period length timer1 capture value , account timer1 numer of overflows
FreqPeriod::captd= ICR1 + FreqPeriod::ocnt* 0x10000;

// compute period difference
FreqPeriod::captd=FreqPeriod::captd-FreqPeriod::capta;

FreqPeriod::capta=ICR1; // store capture value
FreqPeriod::ocnt=0; // reset number of timer1 overflows
FreqPeriod::f_capt=1; // measure ready flag
}
else {
ACSR &= ~(1<<ACIS0); // next comparator detection on falling edge
digitalWrite(5,1); // elevate comparator threshold level on AIN0
}
}

And here is the .h file:

#ifndef FreqPeriod_h
#define FreqPeriod_h

#include <avr/interrupt.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class MLX90316
{
public:
// constructor
MLX90316();
// attach
void attach(int pin1, int pin2, int pin3);
// read sensor angle value

int readAngle();

// private:

int _pinSCK;
int _pinSS;
int _pinMOSI;
uint8_t _spiByte(uint8_t tx);

};

namespace FreqPeriod {

extern volatile unsigned char f_capt;
extern volatile unsigned int capta;
extern volatile unsigned long captd;
extern volatile int ocnt;

void begin();
unsigned long int getPeriod();

}

#endif

And here are the errors:

FreqPeriod\FreqPeriod.cpp.o: In function FreqPeriod::begin()': C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:100: multiple definition of FreqPeriod::begin()'
FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:51: first defined here
FreqPeriod\FreqPeriod.cpp.o: In function FreqPeriod::getPeriod()': C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:104: multiple definition of FreqPeriod::getPeriod()'
FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:55: first defined here
FreqPeriod\FreqPeriod.cpp.o:C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:100: multiple definition of FreqPeriod::f_capt' FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:51: first defined here FreqPeriod\FreqPeriod.cpp.o:C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:100: multiple definition of FreqPeriod::captd'
FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:51: first defined here
FreqPeriod\FreqPeriod.cpp.o: In function __vector_20': C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:114: multiple definition of __vector_20'
FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:65: first defined here
FreqPeriod\FreqPeriod.cpp.o:C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:100: multiple definition of FreqPeriod::ocnt' FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:51: first defined here FreqPeriod\FreqPeriod.cpp.o: In function __vector_28':
C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:119: multiple definition of __vector_28' FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:70: first defined here FreqPeriod\FreqPeriod.cpp.o:C:\Users\SM\Documents\Arduino\libraries\FreqPeriod/FreqPeriod.cpp:100: multiple definition of FreqPeriod::capta'
FreqPeriod.cpp.o:C:\Program Files (x86)\Arduino/FreqPeriod.ino:51: first defined here
core.a(main.cpp.o): In function main': C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino/main.cpp:11: undefined reference to setup'
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino/main.cpp:14: undefined reference to `loop'

And your sketch?

The cpp code is what I have used in the arduino file (is that wrong?)

Does it work?
The supplied sketch compiles...

/* Frequency & Period Measurement for Audio
 * connect pin 5,6,7 to input circuit
 *
 *
 *
 * KHM 2010 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
 */

#include "FreqPeriod.h"

double lfrq;
long int pp;

void setup() {
  Serial.begin(115200);
  FreqPeriod::begin();
  Serial.println("FreqPeriod Library Test");
}

void loop() {

  pp=FreqPeriod::getPeriod();
  if (pp ){

    Serial.print("period: ");
    Serial.print(pp);
    Serial.print(" 1/16us  /  frequency: ");

    lfrq= 16000400.0 / pp;
    printDouble(lfrq,6);
    Serial.print(" Hz");

    Serial.println("  ");
  }

}

//***************************************************************************
void printDouble( double val, byte precision){
  // prints val with number of decimal places determine by precision
  // precision is a number from 0 to 6 indicating the desired decimial places
  // example: lcdPrintDouble( 3.1415, 2); // prints 3.14 (two decimal places)

  if(val < 0.0){
    Serial.print('-');
    val = -val;
  }

  Serial.print (int(val));  //prints the int part
  if( precision > 0) {
    Serial.print("."); // print the decimal point
    unsigned long frac;
    unsigned long mult = 1;
    byte padding = precision -1;
    while(precision--)
      mult *=10;

    if(val >= 0)
      frac = (val - int(val)) * mult;
    else
      frac = (int(val)- val ) * mult;
    unsigned long frac1 = frac;
    while( frac1 /= 10 )
      padding--;
    while(  padding--)
      Serial.print("0");
    Serial.print(frac,DEC) ;
  }
}

Binary sketch size: 4,862 bytes (of a 32,256 byte maximum)

Estimated used SRAM memory: 280 bytes (of a 2048 byte maximum)

This compiled with ver 1.05... I copied the supplied sketch and downloaded the library, Installed both in their proper locations... Under Win 7 64 bit Users...\My Documents\Arduino\libraries and My Documents\Arduino\Freq_Cntr.ino I attached the file I compiled...
It looks a nice addition to my Arduino file collection.

Doc

Freq_Cntr.ino (1.58 KB)

Some people have magic dances that they perform. Others post the code and the error messages.

One method gets results. The other gets tired muscles. Your choice.

Yeah, but which one is more fun?

smd_10:
This is the main .cpp file:

#include <Arduino.h>
#include <FreqPeriod.h>
...

Code tags, not quote tags. How many times?

Don't use the "Copy for Forum" feature. It is unhelpful. Some code gets corrupted by it.

PaulS:
Some people have magic dances that they perform.

Link to the appropriate YouTube video?