Timer1 interrupt exactly one second on 16 Mhz

Hi,
I’am little confused with Timer1 and prescalers etc.
What I need is to setup a Timer which execute a function every one second (exactly one second)
ISR(TIMER1_OVF_vect)

I have a Atmega2560 / 16 Mhz…

Can someone explain me how to properly setup values for timer1_counter?

void setup() {

  Serial.begin(9600);       // inicializacija serijskega porta
  noInterrupts();           // disable all interrupts
 
  pinMode(interruptPinTemp, INPUT_PULLUP);
  pinMode(interruptPinSlanost, INPUT_PULLUP);

 
  TCCR1A = 0;
  TCCR1B = 0;
  timer1_counter = 31250; //34286;   // preload timer 65536-16MHz/256/2Hz

  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt

  interrupts();             // enable all interrupts
  
}


ISR(TIMER1_OVF_vect)        // interrupt service routine every one second
{
    
       TCNT1 = timer1_counter;   // preload timer   
}

How exact do you want your second to be? An Arduino's oscillator does not run at precisely 16MHz so it cannot keep time like a clock. If you need precision then you need a Real Time Clock (RTC) module.

If the Arduino is precise enough, then for a long interval such as 1 second why not just use millis() or even micros(). Much simpler than working with a Hardware Timer.

To use a Timer you need a combination of pre-scaler (to slow down the rate at which the Timer counts) and a count value so that the number of counts at that rate give you the duration you require, I find that the Atmel datasheet starts to make sense after the 14th reading.

...R

What I want is to get a frequency… each second I would like to read a counter value which is incremented when a signal is present on pin 2 (attach interrupt)…

I don’t know what I’am doing wrong but instead od 1000 counts I get 1006 or 1007 counts the code is here (just for sample)

const byte interruptPinTemp = 2;
int cnt = 0; //initial value of counter

void setup() {

Serial.begin(9600); // inicializacija serijskega porta
noInterrupts(); // disable all interrupts

pinMode(interruptPinTemp, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(interruptPinTemp), beriTemperatura, CHANGE);

TCCR1A = 0;
TCCR1B = 0;
timer1_counter = 34286; // preload timer 65536-16MHz/256/2Hz

TCNT1 = timer1_counter; // preload timer
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt

interrupts(); // enable all interrupts

}

//Timer interrupt na 1 sekundo
ISR(TIMER1_OVF_vect) // interrupt service routine
{

cnt1 = cnt ; // copy value to some other variable
bData = true; // set a flag
cnt = 0; // reset counter value
TCNT1 = timer1_counter; // preload timer
}

void loop() {
// if flag is true then the frequency is displayed on serial monitor
if (bData == true)
{
bData = false;
Serial.println(cnt1);

}

}

void beriTemperatura(){
cnt++;
}

t instead od 1000 counts I get 1006 or 1007 counts

0.6% error would be within the expected accuracy of the Arduino clock (barely?)
The logic looks OK; I mean, it could be off by one tick, or a couple cycles worth of reload time, but 8ms seems unlikely. Do you have a high-accuracy frequency counter that you could use to measure the arduino clock?

peterv6i:
Hi,
I'am little confused with Timer1 and prescalers etc.
What I need is to setup a Timer which execute a function every one second (exactly one second)

If you neeed a very accurate 1 Hz pulse, get yourself a DS3231 RTC module, connect it to I2C and activate the 1Hz square wave output on the DS3231!

westfw:
0.6% error would be within the expected accuracy of the Arduino clock (barely?)
The logic looks OK; I mean, it could be off by one tick, or a couple cycles worth of reload time, but 8ms seems unlikely. Do you have a high-accuracy frequency counter that you could use to measure the arduino clock?

I have a Rigol DG1022 frequency generator (http://www.rigol.eu/products/waveform-generators/dg1000/dg1022/)

each second I would like to read a counter value which is incremented when a signal is present on pin 2

What is providing the signal to pin 2 which is supposed to be 1000 counts/second?

  TCCR1A = 0;
  TCCR1B = 0;
  timer1_counter = 34286;   // preload timer 65536-16MHz/256/2Hz

  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt

I think you have set up the overflow for .5 second not 1 second.
By your calulation 65536 - 34286 = 31250 .0625256 = .5

The factor of 2 is only relevant when you are using the timer in a mode where it counts up and down.
When you initialize the registers you have Normal Mode (WGM13:WGM10 =0) which only counts up to OxFFFF and resets.

The way to use the counter for a non-power-of-2 is to select one of the modes that counts upto a
register value, and preset that register, typically the ICR1 register.

  TCCR1A = 0x00 ;
  TCCR1B = 0x00 ;
  TCNT1 = 0x0000 ;
  TCCR1A = 0xA2 ; // fast 16 bit PWM
  TCCR1B = 0x1C ; // prescale /256
  ICR1 = 62500-1 ; // 62500 * 256 = 16x10^6
  TIMSK1 |= 0x01 ;  // overflow int

cattledog:
What is providing the signal to pin 2 which is supposed to be 1000 counts/second?

I have a 2 channel function/counter generator a square wave of 1 KHz (for test). Function generator is RIGOL DG1022 (http://www.batronix.com/shop/waveform-generator/Rigol-DG1022.html)

In this case I have a opamp comparator so I convert sin wave to square pulses (this works fine because with second channel I can exactly count the same frequency)

Here are measured values (1006 or 1007 Hz instead of 1000)

[quote author=cattledog

  TCCR1A = 0;
  TCCR1B = 0;
  timer1_counter = 34286;   // preload timer 65536-16MHz/256/2Hz

  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt

I think you have set up the overflow for .5 second not 1 second.
By your calulation 65536 - 34286 = 31250 .0625256 = .5

The factor of 2 is only relevant when you are using the timer in a mode where it counts up and down.
When you initialize the registers you have Normal Mode (WGM13:WGM10 =0) which only counts up to OxFFFF and resets.

[/quote]

So in my case I have wrong value for timer1_counter? As I say… when a freq is 1000 Hz I count 1006-1007 pulses. When the frequency is 5000 Hz then I count

cattledog:

  TCCR1A = 0;

TCCR1B = 0;
  timer1_counter = 34286;  // preload timer 65536-16MHz/256/2Hz

TCNT1 = timer1_counter;  // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);  // enable timer overflow interrupt





I think you have set up the overflow for .5 second not 1 second. 
By your calulation 65536 - 34286 = 31250 *.0625*256 = .5

The factor of 2 is only relevant when you are using the timer in a mode where it counts up and down. 
When you initialize the registers you have Normal Mode (WGM13:WGM10 =0) which only counts up to OxFFFF and resets.

Will try with this wizzard (ICC AVR) to correctly setup a interrupt (what do you think)?

Timer wizzard:

Generated code:

//TIMER1 initialize - prescale:256
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value: 1,000Sec (0,0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x0B; //setup
TCNT1L = 0xDC;
OCR1AH = 0xF4;
OCR1AL = 0x24;
OCR1BH = 0xF4;
OCR1BL = 0x24;
OCR1CH = 0x00;
OCR1CL = 0x00;
ICR1H = 0xF4;
ICR1L = 0x24;
TCCR1A = 0x00;
TCCR1C = 0x00;
TCCR1B = 0x04; //start Timer
}

#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
//TIMER1 has overflowed
TCNT1H = 0x0B; //reload counter high value
TCNT1L = 0xDC; //reload counter low value
}

Can you please start using code tags?

How to use this forum

This might help you: Gammon Forum : Electronics : Microprocessors : Timers and counters

Thank you!

peterv6i:
So in my case I have wrong value for timer1_counter?

Cattledog is correct. You are only timing 0.5 seconds.

As I say.. when a freq is 1000 Hz I count 1006-1007 pulses.

This is because your "count" interrupt occurs at a rate of 2kHz (twice per cycle of your waveform generator) due to the interrupt mode of "change" (that is, both rising and falling edges).

You are only timing 0.5 seconds.

0.5s between pin inversions is a 1Hz square wave, right? I don't know if that's what you want, but perhaps it explains where the "timer wizard" is getting it's numbers from.
(although, that makes it even stranger that you're seeing ~1008 counts from your frequency generator!)

westfw:
0.5s between pin inversions is a 1Hz square wave, right? I don't know if that's what you want, but perhaps it explains where the "timer wizard" is getting it's numbers from.
(although, that makes it even stranger that you're seeing ~1008 counts from your frequency generator!)

I just want to count frequency in one seccond (pulses in one seccond).
My test frequency is 1000 Hz square wave.. What I want is to get the "same" value in my arduino (counting interrupts on pin 2)..

stewart0:
This is because your "count" interrupt occurs at a rate of 2kHz (twice per cycle of your waveform generator) due to the interrupt mode of "change" (that is, both rising and falling edges).

do you mean this?

attachInterrupt(digitalPinToInterrupt(2), beriTemperatura, CHANGE);

to change like

attachInterrupt(digitalPinToInterrupt(2), beriTemperatura, RISING );

thank you for your help.

peterv6i:
do you mean this?

attachInterrupt(digitalPinToInterrupt(2), beriTemperatura, CHANGE);

to change like

attachInterrupt(digitalPinToInterrupt(2), beriTemperatura, RISING );

Yes. Do that and then your cnt variable will increment only once per cycle of your waveform generator. :slight_smile:

Anyway, that explains why you were getting approx 1000 counts in only 0.5 seconds, but it still doesn't explain your 0.6% clock discrepancy. The clock discrepancy on my UNO board appears to be only about 0.01 to 0.02 percent.

Modern official Uno boards have ceramic resonators, good to 0.3% or so (mores the pity). Is your board a
rare one with a crystal?
Or a clone?

stuart0:
Yes. Do that and then your cnt variable will increment only once per cycle of your waveform generator. :slight_smile:

Anyway, that explains why you were getting approx 1000 counts in only 0.5 seconds, but it still doesn't explain your 0.6% clock discrepancy. The clock discrepancy on my UNO board appears to be only about 0.01 to 0.02 percent.

I have a chinese Dcduino 2560 clone / 16MHz.. :wink:

will try now at home to change code..

stuart0:
Yes. Do that and then your cnt variable will increment only once per cycle of your waveform generator. :slight_smile:

Have changed the code now I get as you say 503 / 504 value

#include <SPI.h>
#include <Ethernet.h>
#include <Math.h>

#define LEDPIN 13


const byte interruptPinTemp = 2;

volatile int cnt = 0;
volatile int cnt1 = 0;


int timer1_counter;
boolean bData = false;

void beriTemperatura(){
  cnt++;
}


void setup() {

  Serial.begin(9600);       // inicializacija serijskega porta
  noInterrupts();           // disable all interrupts
  
  pinMode(interruptPinTemp, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(interruptPinTemp), beriTemperatura, RISING );

  
  TCCR1A = 0;
  TCCR1B = 0;
  timer1_counter = 34286;   // preload timer 65536-16MHz/256/2Hz

  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
  
}

//Timer interrupt na 1 sekundo
ISR(TIMER1_OVF_vect)        // interrupt service routine
{
    
   cnt1 = cnt ;               // prepisemo vrednost v cnt1
   bData = true;             // postavimo flag
   cnt = 0;  // resetiramo counter
   
   TCNT1 = timer1_counter;
}


void loop() {
  // če je postavljen flag, da so podatki jih izpišemo ali naredimo karkoli drugega
  if (bData == true)
  {
    bData = false;
    Serial.println(cnt1);
    
  }
 
}