[TUT] [C] Newbie's Guide to AVR Timers

Go To Last Post
482 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have successfully worked on this Timer Tutorial from Part One till Four. When trying to work with Part Five, I face problem in compiling as displayed below :-

int main(void)
{
} // <=== missed this hence error in ISR ! ! !
ISR(TIMER1_COMPA_vect)
{
	PORTB ^= (1<<0);   // Toggle the LED PB0
}

Compiler Report :-

> "make.exe" all
-------- begin --------
avr-gcc (GCC) 4.1.2 (WinAVR 20070525)
<<<...>>>
Compiling: main_5a.c
avr-gcc -c -mmcu=atmega16 -I.
<<<...>>>
main_5a.c: In function 'main':
main_5a.c:28: error: static declaration of '__vector_6' follows non-static declaration
main_5a.c:27: error: previous declaration of '__vector_6' was here
main_5a.c:30: error: expected declaration or statement at end of input
make.exe: *** [main_5a.o] Error 1
> Process Exit Code: 2
> Time Taken: 00:00

I have verified I am using avr-gcc (GCC) 4.1.2 (WinAVR 20070525). The TIMER1_COMPA_vect is defined in the table under ISR. Any body can indicate if I have missed something.
- India_AVR

Corrected - Sorry error corrected - Why is it that we spot our mistake the moment we post our querry and till then for hours we are not able to spot our mistake ?
- India_AVR

-----------------------------------------
Wonderful world of "0"s & "1"s
-----------------------------------------

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean, Great Work!!

I'm a few month AVR newbie and this is the best timer explanation I have read.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean, Are you planning to cover using a timer with an external crystal? like a watch crystal to have an accurate 1hz timer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Dean, Are you planning to cover using a timer with an external crystal? like a watch crystal to have an accurate 1hz timer.

Hmmm, thought I already covered that -- apparently not. Added to TODO list.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot, Dean!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Polish version of this tutorial :).
for egzample:
http://www.wkretak.pl/?page_id=71

here is the info about author and avrfreak.net
http://www.wkretak.pl/?page_id=71

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wrote a little program to calculate "target timer cycles" for all prescalers. I hope it could be usefull.

http://www.wkretak.pl/upload/tim... 9kb

To run the program you will need Microsoft .Net Framework installed on your PC. URL in readme file.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I wrote a little program to calculate "target timer cycles" for all prescalers

Are you aware of http://www.avrfreaks.net/index.p... ?

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello folks,

thanks for the great tutorial, really helped me to start with AVR's.

I'm trying to build a square wave generator (school assignment), with a variable frequency from 100hz up to 100khz.

I'm using an atmega8 with 8mhz crystal.

this works fine, I can get the frequency high enough (100khz) but it isn't nicely variable.

I'm using the hardware ctc part of this tutorial, and created this very simple code (the part to check button states is left out, because it is of no need here).

int main (void)
{
   DDRB |= (1 << 1); // Set LED as output

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

   TCCR1A |= (1 << COM1A0); // Enable timer 1 Compare Output channel A in toggle mode

   OCR1A   = (8000000 / 99500 - 1) / 2; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

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

   for (;;)
   {

   }
}

as you can see, I'm trying to get a frequency of 99,5khz here.
this does not work for me, since it outputs a nice 100khz :(

I think it is because the timer value for 100khz and 99,5khz (in this case) are very close to each other:

(8000000 / 99500 - 1) / 2 equals 39,701.
the value for 100khz is 39,5.

does anybody have a solution? I'm a bit stuck right now :S

thanks a lot

v3n0m

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DANG, nobody has an answer for this? :S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another brilliant tutorial! Cheers :D

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

If this starts the timer, what can I use to stop the timer?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
TCCR1B = 0;

Giving the timer a clock source starts it, so taking it away stops it. You'll need to manually reset it for the next time (TCNT1 = 0) if required.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AWSOME Tutorial!
Helped me out alot.

I originally learned these things on a Motorola 68hc11 and this tutorial helped me migrate flawlessly.

Can't wait to see the pwm Section.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello.....
thank you very very much for this topics about timers..

I want to ask you about using watchdog timer...eg:
setting this timer to turn off the micro controller after 5minutes....

thanks in advance..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How would one go about makeing the time interval much shorter (say for example .1 of a second?)

I am using a 4Mhz Clock


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

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

TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer

--

ISR(TIMER1_COMPA_vect)
{
// Flash LED
}

?

Thanks :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lower the OCR1A value. The tutorial explains how to calculate the compare value from the input clock, prescaler and desired interval.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am sorry for posting this, and might have over looked .. but did you manage to finish the PWM part of the tutorial?..

- Kent

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, I've been busy with Uni, my MyUSB and my new USB book. I know, I'm lazy!

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A long awaited TUT i think for many people here, but anywayz a big thanx for the tutorials you have written.. Will probably after the information on Timers figure out how PWM works, hopefully ;) ..

- Kent

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brilliant! Please keep up the good work. Looking forward to the next PWM posting.

Dave

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much for a great tutorial!
It is the most helpful thing I found on the internet for setting up timers and interrupts... awesome

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Dean,

Nice job so far. Timers can be quite a pain sometimes. I have a hard time remembering how my own PWM code works sometimes.

I'd attack the PWM section with several different examples, since PWM is used in so many different ways. Maybe single timer fixed frequency-variable duty cycle examples first like switching power supplies, then a variable frequency-variable duty cycle example using one timer, then end it with a more complicated multiple timer example.

Good luck, feel free to use my teslaphonic code or webcam servo code for examples if you want.

Scott

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Scott, good idea (and thanks for all the kudos posts above guys!).

I'm currently busy with MyUSB development and writing my USB book, but I'll come back to this eventually.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

abcminiuser wrote:
...

I'm currently busy with MyUSB development and writing my USB book, but I'll come back to this eventually.

- Dean :twisted:

Very proud of you!! Way to go Dean!
John

Resistance is futile…… You will be compiled!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Dean

I'm new to AVRs, but I use to work on 80C31 (very old tech I know, but that is varsity).

Thanx for the great tut. I understand timers now and I finaly got them to work. Great work, great tut.

Just wish you completed the PWM chapter as that is what I'm trying to sort out now, but I understand, varsity is hectic.

I do have another question. I've taken your code, in chapter 2 I think. I've added another LED on a different port. But for some odd reason, the timing changes. Why is this? Any ideas?

Here is the code.

#include
int main (void)
{
DDRB |= (1 << 1);
DDRB |= (1 << 2);
TCCR1B |= ((1 << CS10) | (1 << CS11));
for (;;)
{
if (TCNT1 >= 15625)
{
PORTB ^= (1 << 1);
PORTB ^= (1 << 2);

TCNT1 = 0;
}
}
}

btw, I'm using the Atmega8, so timing is different from what you calculated. I'm not trying to get exact timimg at the moment, just getting the basic.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By how much does the timing change? Just adding in a second port XOR command shouldn't make the timing wildly different.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, actually by quiet alot. I know it shouldn't make much of a difference , but the difference is big enough to notice it easilly. I'll say with about half a second or so.

Surelly something must be wrong on this side, but I don't know what.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So you can reliably making the timing change wildly by commenting out the second XOR in the loop?

That baffles me. Your timer prescaler is 64, so any code with an execution length of less than 64 clock cycles won't change the timer's count value by more than 1. The code uses a >= comparison, so any slight overshoot won't make any difference.

Perhaps someone else can jump in. I don't see how a three cycle operation (IN EOR OUT) inside the IF statment (which executes after the duration has elapsed) would vary the timing so much.

Is that an exact copy of the code you are working with?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mmmm, ok if I use this code
#include
int main (void)
{
DDRB |= (1 << 1);
DDRB |= (1 << 2);
TCCR1B |= ((1 << CS10) | (1 << CS11));
for ( ; ; )
{
if (TCNT1 >= 15625)
{
PORTB ^= (1 << 1) | (1 << 2); //Code I change
TCNT1 = 0;
}
}
}
timing stayes the same, but if I use this code;
#include
int main (void)
{
DDRB |= (1 << 1);
DDRB |= (1 << 2);
TCCR1B |= ((1 << CS10) | (1 << CS11));
for ( ; ; )
{
if (TCNT1 >= 15625)
{
PORTB ^= (1 << 1) ;
PORTB ^= (1 << 2); //Code I change from 1st program
TCNT1 = 0;
}
}
}

Timing changes completely and only 1 pin flashes, PINB1, while 2 stayes of.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have read the tutorial about the topic and now i need help in PWM with Atmega88. The PWM will turn the RGB Led on and off. I dont know if i doing it correctly or not. Please guide me.

int main(void)
{
	
	wait(10000);			//wait a while for power up


	DDRB 	= _BV(3);   	// LED red
     		
	DDRD 	= _BV(3)   		// LED blue
     		| _BV(6);  		// LED green
    DDRC 	= 0x0f;			
	
	sei();					
	timer0();				
	timer1();				
	timer2();				
	lcd_init();				

	TCNT0=134;
	TCNT2=134;
	TCNT1=134;

	for (;;) 
   { 

   }

}


void timer0(void)
{
	// Mode of Operation: Phase Correct PWM Mode
	// Clock select: Quartz / 256 (Prescaler)
	// Timer Overflow Interrupt Enable
	TCCR0A |= (1<<WGM00) | (0<<WGM01) | (1<<COM0A1);
	TCCR0B |= (1<<WGM02) | (1<<CS02);
	TIMSK0 |= (1<<TOIE0) | (1<<OCIE0A);
}

void timer1(void)
{
	// Mode of Operation: Phase Correct PWM Mode
	// Clock select: Quartz / 256 (Prescaler)
	// Timer Overflow Interrupt Enable
	TCCR1A |= (1<<WGM10) | (0<<WGM11) | (1<<COM1A1);
	TCCR0B |= (0<<WGM12) | (1<<CS12);
	TIMSK0 |= (1<<TOIE1) | (1<<OCIE1A);
}

void timer2(void)
{
	// Mode of Operation: Phase Correct PWM Mode
	// Clock select: Quartz / 256 (Prescaler)
	// Timer Overflow Interrupt Enable
	TCCR0A |= (1<<WGM20) | (0<<WGM21)| (1<<COM2A1);
	TCCR0B |= (1<<WGM22) | (1<<CS22) | (1<<COM2B1);
	TIMSK0 |= (1<<TOIE2) | (1<<OCIE2A);
}

ISR(TIMER1_OVF_vect) 
{ 
 
TODO: Toggle LED when  OCR1A = 230;			//LED blue 4.5V, 90%

   TCNT1  = 134; // Reload timer with precalculated value 

}


ISR(TIMER0_OVF_vect) 
{ 
TODO: Toggle LED when OCR0A = 112;			//LED green 2.2V, 44%
   TCNT0  = 134; // Reload timer with precalculated value 


}

ISR(TIMER2_OVF_vect) 
{ 
TODO: Toggle LED when OCR2A = 102;			//LED red 2.0V, 40%
   TCNT2  = 134; // Reload timer with precalculated value 

}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i've read the tutorial. again and again.. but i can't figured out whats wrong with my project.

my project is purposed to create some ballistic time counter using ATMEGA8535.

and here is the code:

#include 

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x15 ;PORTC
#endasm
#include 
#include 
#include 

unsigned long counter=0;
unsigned long time_out=0;
unsigned long extra=0;
unsigned long extra_out=0;
char *time;
char *ext;

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
        TCNT0=252;
        TCCR0=0X01;

}

// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
        TCCR0=0X00;
        time_out=counter;
        extra_out=extra;
        
        sprintf(time,"Time = %u us",time_out);
        sprintf(ext,"Extra = %u",extra_out);
        lcd_puts (time);
        lcd_gotoxy(0,1);
        lcd_puts (ext);
        delay_ms(5000);
        lcd_clear();
        lcd_putsf("Ready");
        counter=0;
        extra=0;
}


interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
        TCNT0=252;
        if (++counter==50000)
        {
                counter=0;
                extra++;
                }

}

// Declare your global variables here

void main(void)
{
PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTD=0x00;
DDRD=0x00;

TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;


// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: On
// INT1 Mode: Rising Edge
// INT2: Off
GICR|=0xC0;
MCUCR=0x0F;
MCUCSR=0x00;
GIFR=0xC0;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// LCD module initialization
lcd_init(16);
lcd_putsf("Ready");
// Global enable interrupts
#asm("sei")

while (1);
}

the time counter started when INT0 is raising, and stopped when INT1 is raising.

the problem is, it's always return ZERO result.

is it the speed just goes too fast ? ( in theory it can reach about 164 m/s and the distances is 4 cm)

Last Edited: Wed. May 21, 2008 - 05:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suspect no-one will bother to read your code unless you change the QUOTE tags to CODE tags and fix the indentation.

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The timer is never started (make a prescaler selection using the CS02-CS00 bits in TCCR0). Also, you will be better off using the CTC mode (read about it in this tutorial). Any code that assigns the TCNTx register from an interrupt will suffer (i.e., timing will be inaccurate) because of interrupt latency.
/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lajon wrote:
The timer is never started (make a prescaler selection using the CS02-CS00 bits in TCCR0). Also, you will be better off using the CTC mode (read about it in this tutorial). Any code that assigns the TCNTx register from an interrupt will suffer (i.e., timing will be inaccurate) because of interrupt latency.
/Lars

but the thing is, my project is working when i tested with a free falling object (it shows about 600 us when it falls from 1 meter).

but when i give some velocity here (blowing it with 2 bar pressure), the system (just like i say) gave me ZERO result.

and about the latency things, have you read the tutorial ?. i've done my code just like the tut's.

see this in part 8?

ISR(TIMER1_OVF_vect)
{
   PORTB ^= (1 << 0); // Toggle the LED
   TCNT1  = 49910; // Reload timer with precalculated value
}

and now....

what went wrong...
realy ?

nb: johan...... you're not helping at all

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
and about the latency things, have you read the tutorial ?. i've done my code just like the tut's.
Read "Part Five - CTC Mode using Interrupts ". That said, the timer 1 input capture function is a better fit for your application. It would make better use of the timer HW so your program is not so busy with timer interrupts. I suspect your current solution suffers from this but I don't think that this alone explains the problem you have.
/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you checked the signals connected at INT0 and INT1 (with a oscilloscope). Do they look ok also when a higher speed test is done?
/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why are you preloading timer? This is normally done when you want to control the time ( such as flashing an LED at a set rate) It seems here you want to measure the time in which case I would just zero and start the timer on the first int0 and forget the reload values. If the device you are using has an input capture that would be an even better way to accomplish this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lajon wrote:
Read "Part Five - CTC Mode using Interrupts ". That said, the timer 1 input capture function is a better fit for your application. It would make better use of the timer HW so your program is not so busy with timer interrupts. I suspect your current solution suffers from this but I don't think that this alone explains the problem you have.
/Lars

i missed that part.... sorry

but you were right about the busy part..
a friend of mine told me that my code in interrupt overflow need more than 4 cycle. and thats it.

Quote:
Have you checked the signals connected at INT0 and INT1 (with a oscilloscope). Do they look ok also when a higher speed test is done?
/Lars

the signal always ok i think.
because the result is always zero... not the "Ready" words.

problem is....
i have to waited a week until my lab is open again.

until then i'll report to you guys.

thanks a lot....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everybody..

first of all thank you very much Dean for this wonderful tutorial.
next..
pleeease help me..

I'm using this function to control the speed of a small DC motor using pwm, and the problem is that the output of OC1A is still VCC whether I give OCR1A any value including 0xFFFF and 0x0000 and any value between them.. this is the function...


/*********************************************
Chip type           : ATmega8535
Program type        : Application
Clock frequency     : 4.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 128
*********************************************/

#include 
//MOTOR:
//**********************************************************
//Motor Pins:
//--------------
//PIND.5=OC1A:PWM source for the motor .
//
//The following function is used to set Timer1 in fast pwm mode
void settings(void)
{
DDRD |=0b00100000;//PORTD.5=OC1A is output
/*
// Bit7:6=COM1A1:0(Compare Output Mode for Channel A)=10>>(Clear OC1A/OC1B on Compare Match, 
// set OC1A/OC1B at TOP (Non-Inverting)) with   WGM13:0=1111
// Bit5:4=COM1B1:0(Compare Output Mode for Channel B)=00>>Normal port operation, OC1B disconnected.
// Bit3=FOC1A(Force Output Compare for Channel A)=0>>No Forcing for Output Compare of Channel A 
// Bit2=FOC1B(Force Output Compare for Channel B)=0>>No Forcing for Output Compare of Channel B
// Bit1:0=WGM11:0(Waveform Generation Mode)=11+WGM13:2=11>>Mode: Fast PWM top=OCR1A
*/
TCCR1A=0b10000011;

TCNT1=0xFFFE;// MAX count value;
/*
// Bit7=ICNC1(Input Capture Noise Canceler)=1>>Input Capture Noise Canceler On
// Bit6=ICES1(Input Capture Edge Select)=0>>Falling Edge
// Bit5=Reserved Bit=0;
// Bit4:3=WGM13:2(Waveform Generation Mode)=11+WGM11:0=11>>Mode: Fast PWM top=OCR1A
// Bit2:0=CS12:0(Clock Select)=001>>>clock source clkI/O/1 (No prescaling).
*/
TCCR1B=0b10011001;

OCR1A=0x9999;//PWM Duty
}

thanks in advance

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Readers beware! The above post by ia17348 is a cross post. Don't waste time answering here. Discussion is already ongoing here: http://www.avrfreaks.net/index.p...

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're right Johan , But after I added this topic here I noticed that there is no body here (at this moment at least) so I put it at the AVR forum , any way I want to be one of these who thanked Dean for this wonderful tutorial....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all, I'd like to thank Dean for this excellent tutorial. I have used the information here with much success on an ATmega8.

I am now starting another small project based on an ATtiny2313, and I am not sure what the problem with my code is. The idea is that I need a timer to be triggered every second. It doesn't have to be as accurate as an atomic clock, so "about 1 Hz" should be good enough.

The ATtiny2313 is running off the internal oscillator at 8 MHz; indeed, the only thing I changed in the fuses is enabling the EESAVE bit (lfuse 0x64, hfuse 0x9f, efuse 0xff).
I calculated that 1 Hz requires the timer to get to 31250 with clk/256 prescaler (8000000 / 256 = 31250):

TCCR1B |= (1 << WGM12); 	// CTC mode
TIMSK |= (1 << OCIE1A);		// interrupt-driven
OCR1A = 31250;				// 1 second = 31250 (@ 8 mhz)
TCCR1B |= (1<<CS12);		// f/256

The interrupt routine is just a boring led blinker so far ( PORTD ^= 1<<PD5; )
The problem is that it doesn't blink at 1 Hz at all, it takes MUCH longer (around 7 seconds, measured very empirically). Indeed, using a smaller prescaler, that is clk/64, gives a blinking that is somewhat closer to 1 Hz, but not quite (it should be only 4 times faster though!).
However, I'm quite confused as to why I am having such weird behavior. Truth be told, I am almost sure that it's something very stupid that it's before my eyes and I'm just missing, but any hint is certainly appreciated as I risk getting old looking for it. :)

Thank you!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Check your fuse settings again. The Tiny2313 has a divide by 8 option that is selected by default. It divides the frequency by 8 so you are actually running at 1 Mhz instead of 8.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
Check your fuse settings again. The Tiny2313 has a divide by 8 option that is selected by default. It divides the frequency by 8 so you are actually running at 1 Mhz instead of 8.

Oops! That's right, thanks for making me notice that. I had completely skipped that fuse, and to think it's been there in front of me for a good two hours. :)

Edit in case someone needs it: running the ATtiny2313 off 3.1 V (instead of 5 V) seems to yield a much more reliable 1 Hz timer (at 5 V, my clock was ahead of a good two minutes after barely half an hour!). :)

Another edit: it's still not quite accurate: after an hour and a half, it's ahead of 4 minutes. I thought that at most the timer would be *slower* than real time, but it seems it's actually faster. Would an external crystal for the clock (or just for the timers) help? Before I dismantle this and add a 74HC595 (or use an ATmega8), as I'm out of pins already, I'd like to be sure it's worth it. :) Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great tutorial on timers. I will look forward to the PWM section for additions.
Thank you for your work and efforts, this is the kind of thing that makes avrfreaks.net a great place for AVR beginners as well as the advanced audience.
I too would consider a book as a benefit to my technical library. Once again, thanks.

I'll believe corporations
are people when Texas executes one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great tutorial, looking forward to PWM update.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a great tutorial Dean. Keep up the good work :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean,

Is the PWM Timer section going to be done anytime soon?

-Melanie

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hard to say. I'm being perpetually sidetracked by other projects -- right now I'm implementing the RNDIS specification on to my MyUSB USB stack to set up a webserver over USB. I have started the next tiny bit - when I feel like it I'll write the remainder.

I know, I've been meaning to do it for a long time, I just feel the call of writing code more than the call of writing tutorials these days. What's the world coming to!

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Dean,

I just wanted to express my gratitude too! I have been working with a mega32 for the last year, building a balancing robot for my Uni dissertation:

http://www.youtube.com/watch?v=V...

However, I ended up doing all the coding in a poxy basic language for the AVRs (BASCOM... *shudders*). I'm now porting the code to C, and this has really helped with setting up all the pesky interrupts, timers and PWMs I used.

In fact, let me know if you want someone to lay out some PWM code for the tutorial. I have all the registers I setup all already in a log book, I'm sure it won't take me long to work out how to access them.

So thanks! Keep up the good work, and I hope your Uni exams went well (last year)!

Paul.

Pages