How to use timers inside arduino?

Hello, I've been following the AVRfreaks tutorial on how to use timers. In doing so, I'm setting the timer using direct port access and whatever else detailed at http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106.

Here's my program:

#include <avr/io.h>
#include <avr/interrupt.h>

ISR(TIMER1_COMPA_vect)
{
   PORTB ^= (1 << 3); // Toggle the LED
} 

void setup()                    // run once, when the sketch starts
{
  DDRB |= (1 << 3); // Set LED as output

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

   TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

   sei(); //  Enable global interrupts

   OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64 
}

void loop()                     // run over and over again
{
  
}

Which was directly swiped from the above link from "Part 5: CTC Mode using Interrupts". It's supposed to flip pin PB3 from 1 to 0 every second or so (It's supposed to be a 1 hz signal), but when I measure it using the oscilloscope, the on time is 1 mS and the off time is 1 mS, so that's 500 hz. The example uses an example of 1 mhz crystal, so mine's going to be 16 times faster since I'm using 16 mhz, but it's not exactly that.

Furthermore, when I change the "OCR1A = 15624; " line to a smaller number (to make it shorter), it doesn't do anything. It seems to really love 1 mS for some reason.

So, uhhh.... why isn't this doing what I think it should?

P.S., yes, I know the built-in LED is on digital pin 13(PB5), but that had the same problem too.

Did you set WGM10, WGM11 in TCCR1A accordingly?

They should default to 0, but who knows what the arduino software does to it. TIMER1 is not necessarily in 16bit mode! So your compare match registers might never be reached or get truncated after 8bits...

How does one set timer1 to 16-bit mode? The tutorial implied that was a given. :confused:

TCCR1A doesn't matter, does it, since it belongs to port A? I'm only messing with port B.

As far as WGM10, WGM11... ehhh. I have no clue. Ok, well, I'm looking at the datasheet and it apparently thinks that WGM10,WGM11,WGM12 and WGM13 configure the timer settings, so it does look like WGM10 and WGM11 might need to be configured to 0.

So, let's see, would this do it?

 TCCR1B |= (0 << WGM11);
 TCCR1B |= (0 << WGM10);

Now that I think about it, maybe I want to make sure timer A is turned off. Would...

TCCR1A = 0;

do it?

If you don't want any of the hardware PWM pins (see datasheet) to be 'alive', then setting TCCR1A to 0 should be OK as far as TCCR1A is concerned. All the other bits of TCCR1B must be set as well as you need them. It is not necessarily safe to assume that they have their default settings when using the Arduino software.

If you have a look at 'wiring.c' in the core file directory, you will find that these control registers are manipulated and may contain values you don't need.

I haven't played with timer 1 yet, but:

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

This is not neccesarily a CTC mode, as there are lots of modes including the WGM12 bit (table 13-4, page 136 of atmega 48-88-168-328 datasheet). For instance the OCR1A is not necessarily the one defining the TOP counter value, it can also be ICR1 or some other preset value.
I guess you should set it to

   TCCR1B = (1 << WGM12); // Configure timer 1 for CTC mode

Just a suggestion, I'm no expert in this really.

Also, as far as I can see (and it's not always that far :P), timer 1 is 16 bit, not 8. But it needs to be accessed in a certain way to ensure proper operation. Writing/reading 8 MSB bits to a register TEMP register first, then when accessing the LSB 8 bits of the low part of a timer1 register will update the hole register (or read from it, depending). But I assume the arduino IDE takes care of that when writing 16 bits to e.g. TCCR1B, so no need to write to some TEMPREG (or what it is called) and then TCCR1BL, or whatever register.

Also, something else I just saw in that datasheet about timer1:

The PRTIM1 bit in [ch8221]PRR [ch8211] Power Reduction Register[ch8221] on page 45 must be written to zero to
enable Timer/Counter1 module.

But I guess it is already enabled, so probably no need to mess with that (plus you do seem tohave a 1ms interval on it too).

Also, just in case, there is a really nice tutorial covering timer2 here: Arduino Interrupts – uCHobby

The problem (and I've discussed it with essentially myself on avrfreaks.net) is this:

The Arduino code sets some values in TCCR1A and TCCR1B that are different from the default values. The tutorials on avrfreaks.net assume the default values are there and therefore don't set some bits. Using the Arduino IDE you must do it.

You're right about the correct sequence for reading from (L then H) and writing to (H then L) these special 16bit registers which involve the automatic tempreg magic.

If you don't set the default bits, it happens that timer1 is in 8bit mode, which means that whatever you do TCNT1H (the upper 8 bits) will always be zero, which can be terribly confusing.

See here:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1260712066/5

You guys were totally right. Apparently I need to set timer A to zero, and then set the appropriate WGM10 and WGM11 bits of timer B to zero. After doing that, it works just as I expect it would. Thanks!

:smiley:

(Why does Arduino have to screw with everything? :-?)

Well, I think we are walking on grounds here that were never meant for the typical arduino audience. This is not just cough drops anymore, but using an endoscope.

Yeah, probably. Maybe. I have had the arduino for a year before getting to this point, so I suppose it's something that takes time to learn.

Anyways, the current prescaler apparently multiplies by 64. I think that basically means that every 64/16,000,00 seconds = 40 uS, it increments the timer.

Well, I'm trying to use a prescale value of 1. That means it should increment the timer every .625 uS. Since I'm trying to get a 10 khz signal, I'm looking at a timer value of 100 uS/.625us = 160.

However, I do that, and the thing is switching every .6 mS, not the .1 mS I'm seeking.

I tried setting the prescaler to 1 with the following code:

TCCR1B |= (1 << CS10);//currently set at prescale = 1;
      TCCR1B |= (0 << CS11);
            TCCR1B |= (0 << CS12);

Is there something I'm doing wrong? Is there a way I can get the timer to increment on every clock cycle? (And, I assume the clock is at 16 mhz.)

[Oh yeah, I think I now know why I was seeing 500 hz. It's because 500 hz is the default pwm rate with arduino's built-in pwm functions. Or at least it was with Arduino-14.)

EDIT: I think I did my math wrong. I meant .0625 uS. That definitely doesn't help though because it suggests OCR1A should be ten times higher, which makes my signal ten times longer. I'm looking for something roughly 6 times shorter.

Ok, I think the previous might be a little confusing to read. I'll just give a simple example.

This program:

ISR(TIMER1_COMPA_vect)
{
   PORTB ^= (1 << 3); // Toggle the LED
 
 } 

void setup()                    // run once, when the sketch starts
{
  DDRB |= (1 << 3); // Set LED as output

  TCCR1A = 0;

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
   TCCR1B |= (0 << WGM11);
 TCCR1B |= (0 << WGM10); 

   TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

   sei(); //  Enable global interrupts

   OCR1A   = 160; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

   TCCR1B |= (1 << CS10);//currently set at prescale = 1
      TCCR1B |= (0 << CS11);
            TCCR1B |= (0 << CS12);

}

void loop()                     // run over and over again
{
  
}

shows up as .64 mS = 640 uS on the oscilloscope before it switches. However, since it's 16 mhz, a timer ceiling of 160 should result in a 100 khz signal or each one should last 10 uS.

So it's 64 times longer than it should be....

seems suspicious. :-?

A few things:

  • there is no WGM10 in TCCR1B !
  • TCCR1B |= (0 << CS10); does NOT clear that bit !

clear: TCCR1B &= ~(1 << CS10);
set: TCCR1B |= (1 << CS10);
toggle: TCCR1B ^= (1 << CS10);

I think the timer/prescaler setup is still not quite correct.

You're right again.

I changed the code

TCCR1B |= (1 << CS10);//currently set at prescale = 1;
      TCCR1B |= (0 << CS11);
            TCCR1B |= (0 << CS12);

to

 TCCR1B |= (1 << CS10); 
      TCCR1B &= ~(1 << CS11);
            TCCR1B &= ~(1 << CS12);

and it works! It gives a signal lasting 10 uS long, just like I expected it would. It seems odd that setting a 0 and 1 to a bit would have different syntax. ::slight_smile:

As far as the non-existent wgm10 and wgm11, I guess that code just goes into neverland. So, I take it that wgm10 and wgm11 is set to 0 when I set TCCR1A to zero, and then wgm12 which belongs to B is configured for CTC when it's set to 1. Is that right? So, basically, A's wgm10 and wgm11 control the wgm10 and wgm11 bits as far as mode goes for both A and B?

swbluto:

You might be able to gain some insight on how the various registers control the Timer by looking at this diagram. Go to http://web.alfredstate.edu/weimandn. Scroll down to 'Atmel ATmega Subsystem Diagrams' and click the Reference Diagrams For Programmers link. On the new page scroll down to 'Timer/Counter1 Compare Match B' abd click the PDF Document link. These diagrams are a work in progress and there are still some minor errors, but they should not affect what you are attempting to do.

Don

Thats because an OR is like as addition and one AND is like one multiplication, so 1 OR 0 is 1 and 1 AND 0 is 0.