Go Down

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

boylesg

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

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

Quote
The interval is more like 10s
About 10.176 seconds. IIRC.

Ps991

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 pm Last 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 interrupt

void 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

...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 am Last 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

As Robin2 said, use millis() techniques.

Or, is there a reason why the OP cannot?


.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

larryd

#8
Aug 21, 2016, 02:01 am Last 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 are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

Ps991

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

If he/she is after simplicity and still wants to use interrupts, would the Timer1 library not be easier?

boylesg

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

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

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

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