Go Down

### Topic: Timer1 - how do you set a 1 minute timer? (Read 17675 times)previous topic - next topic

#### boylesg

##### Aug 20, 2016, 10:16 pm
It is apparently not as simple as Timer1.initialize((uint32_t)60000000); because this does not seem to work.

The interval is more like 10s or so and increasing the value of the parameter further has no effect.

Do you have to mess with the clock dividers to get it to work?

I can't seem to find an example of this sort of long period to follow.

#### Robin2

#1
##### Aug 20, 2016, 10:38 pm
I don't understand why you want to use a hardware Timer for a period as long as 1 minute? Why not just use millis()?

The demo Several Things at a Time illustrates the use of millis() to manage timing.

I don't know if Timer1 can deal with a period as long as 1 minute but you would certainly need to "mess with the clock dividers". All the details are in the relevant Atmel datasheet - you don't say which Arduino you are using.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

#### AWOL

#2
##### Aug 20, 2016, 10:43 pm
Quote
The interval is more like 10s

#### Ps991

#3
##### Aug 20, 2016, 10:46 pm
First of all, PLEASE read the How To Use This Forum thread before you post. I had to do alot of googling, which most people WILL NOT DO, simply because you failed to tell us basic things about your problem, such as:
The library you were using, and
Your code, which would have showed me the library you were using

Anyway, here is what I found in the library I ASSUME you are using...
Code: [Select]
` long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal... //removed because irrelevant  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum`

RESOLUTION is set to 65536 because Timer1 is a 16bit timer.
cycles = (16,000,000 / 2,000,000) * 60,000,000 = 480,000,000
So, cycles is NOT less than RESOLUTION - 1, therefore it was more than maximum

This code sets the prescaler to 1024, as slow as you can get.
A prescaler of 1024 allows for a maximum time of 8388.608mS or ~8.3 seconds
Code: [Select]
`clockSelectBits = _BV(CS12) | _BV(CS10);`
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

#### Ps991

#4
##### Aug 20, 2016, 11:14 pmLast Edit: Aug 20, 2016, 11:17 pm by Ps991
Here is a slightly modified program I made to easily set up timed interrupts. I tested its accuracy and it works consistently down to the microsecond.

The interrupt gets called every 1 second and adds 1 to 'seconds'. Simply check if 'seconds' is 60 or whatever, if it is, then execute your code. This program toggles an LED.

Code: [Select]
`void setup() {  int frequency = 1; // in hz  //Interupt Service Routine and timer setup  noInterrupts();// kill interrupts until everybody is set up  //We use Timer 1 b/c it's the only 16 bit timer  TCCR1A = B00000000;//Register A all 0's since we're not toggling any pins    // TCCR1B clock prescalers    // 0 0 1 clkI/O /1 (No prescaling)    // 0 1 0 clkI/O /8 (From prescaler)    // 0 1 1 clkI/O /64 (From prescaler)    // 1 0 0 clkI/O /256 (From prescaler)    // 1 0 1 clkI/O /1024 (From prescaler)  TCCR1B = B00001100;//bit 3 set for CTC mode, will call interrupt on counter match, bit 2 set to divide clock by 256, so 16MHz/256=62.5KHz  TIMSK1 = B00000010;//bit 1 set to call the interrupt on an OCR1A match  OCR1A  = (unsigned long)((62500UL / frequency) - 1UL);//our clock runs at 62.5kHz, which is 1/62.5kHz = 16us  interrupts();//restart interrupts  Serial.begin(115200);  pinMode(13, OUTPUT);}volatile int seconds = 0; //make it volatile because it is used inside the interruptvoid loop() {  }ISR(TIMER1_COMPA_vect){ //Interrupt Service Routine, Timer/Counter1 Compare Match A  seconds++;  if(seconds >= 1) { //set to however many seconds you want    Serial.println(micros());           // This code is what happens    seconds = 0;                        // after 'x' seconds    digitalWrite(13, !digitalRead(13)); //  }}`
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

#### MorganS

#5
##### Aug 21, 2016, 12:31 am
...which is EXACTLY what millis() does, except it uses milliseconds as the unit instead of seconds. You have replaced one problem by exactly the same problem except you have used another precious timer which now cannot be used for PWM or servos.
"The problem is in the code you didn't post."

#### Ps991

#6
##### Aug 21, 2016, 01:50 amLast Edit: Aug 21, 2016, 01:54 am by Ps991
Ok, then please give him an alternative that executes code at exactly 1 minute, which is what I was showing them how to do, because...
Code: [Select]
`if(millis() - lastTime >= 60000) {  lastTime = millis();   ...}`
does not guarantee execution after 1 minute because other code may take a long time to execute.
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

#### larryd

#7
##### Aug 21, 2016, 01:56 am
As Robin2 said, use millis() techniques.

Or, is there a reason why the OP cannot?

.
No technical PMs.
If you need clarification, ask for help.

#### larryd

#8
##### Aug 21, 2016, 02:01 amLast Edit: Aug 21, 2016, 02:02 am by LarryD
Having a hard time thinking what can be so important to happen at 1 uS after a minute.

.
No technical PMs.
If you need clarification, ask for help.

#### Ps991

#9
##### Aug 21, 2016, 02:19 am
I provided a proof of concept using an interrupt, the same timer that OP was attempting to use. I answered their question using their method.

However, OP did not specify whether or not perfect timing was critical. 1 or 2 uS or even mS may not be important, but if they have alot of blocking code and 1 minute is fairly important, then interrupts are the way to go. OP will decide what is right for their code.
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

#### saximus

#10
##### Aug 21, 2016, 02:53 am
If he/she is after simplicity and still wants to use interrupts, would the Timer1 library not be easier?

#### boylesg

#11
##### Aug 21, 2016, 03:21 am
I don't understand why you want to use a hardware Timer for a period as long as 1 minute? Why not just use millis()?

The demo Several Things at a Time illustrates the use of millis() to manage timing.

I don't know if Timer1 can deal with a period as long as 1 minute but you would certainly need to "mess with the clock dividers". All the details are in the relevant Atmel datasheet - you don't say which Arduino you are using.

...R
Because if I did it that way I would be continuously polling for a few different things in my loop() and it may start degrading performance.
If I use a 1 minute interrupt then I am only polling for some of those things in my loop function once per minute as necessary.

#### Ps991

#12
##### Aug 21, 2016, 03:25 am
If he/she is after simplicity and still wants to use interrupts, would the Timer1 library not be easier?
It would be easier, if only it worked past 10 seconds. The Timer1 library is the same library the OP is having problems with. And this, OP, is why you show us your code in the first post.
If you can't write your program in plain english where anyone could understand it then you have no hope of writing code for it.  -Delta_G

#### boylesg

#13
##### Aug 21, 2016, 03:36 am
Ok, then please give him an alternative that executes code at exactly 1 minute, which is what I was showing them how to do, because...
Code: [Select]
`if(millis() - lastTime >= 60000) {  lastTime = millis();   ...}`
does not guarantee execution after 1 minute because other code may take a long time to execute.
It would seem I don't have a choice but to do it this way.

The problem I was having was that the too rapid interrupt was interfering with the web server part of my loop()

I was trying to poll for a couple of different things only every minute and the above is effectively polling too.

But hopefully the above code wont slow down my loop() such that it interferes with my web server.

I suppose I could stick my bluetooth polling inside the above check as well, because I don't really need to poll for incoming bluetooth data every X microseconds.

I have never mucked around with the pre-scalers before so I had no clear idea how they work, how to use them or their limitations. Apparently I chose the wrong key words in my google search on how to set long interrupts.

#### boylesg

#14
##### Aug 21, 2016, 03:40 am
Roughly how long does

Code: [Select]
`if(millis() - lastTime >= 60000) {  lastTime = millis();`

take to execute in loop() compared to just

Code: [Select]
`if (boolean flag)` in the case of an interrupt?

Go Up