[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

Quote:
The general idea being I can change OCR long before the timer gets close to its new or old value.
This is a good idea but you are much better off using the free running mode of the timer.
Quote:
If I can take the 1.2mS interval into N (256) discrete time units, I can accurately control the servo to that many positions.

You can run the timer faster and get a lot more than 256 steps. Granted, you may not need more steps and depending of the rest of your program you will get som jitter from interrupt latency.
Here is some example code:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38601&postdays=0&postorder=asc&start=24

Edit: But if you really need to control just one (or a few) servo(s) you are better off using PWM. Even using a prescaler /8 you should be able to control the servo at micro second resolution with a 16-bit timer. Note that one micro second is likley to be smaller than the servo deadband. So I really don't get this:

Quote:
I am trying to control a servo (more accurately than PWM will give me) by setting two interrupts.

/Lars

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

Quote:
different prescales of our AVR's 1MHz system clock:

Code:
Target Period = ((2 ^ 16) * (Prescale / 1000000)

Missing parenthesis (or extra paren).
It's a pleasure to reread this tut.

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

I wanna ask a stupid question, what happens if the timer count till it's max without you restting, does it remain at max?

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

No it does EXACTLY what the data sheet tells you it will. In part it depends on your selected WGM mode. In some modes it counts down after it has counted up, in some it only counts as far as a match value and then resets to 0 and in some it counts the entire range of the TCNT register and effectively therefore wraps back to 0. You really need to read the datasheet.

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

Noted, can I say that a prescaler of 1024 will set the timer to count to 65535 at slower rate?

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

Quote:

at slower rate

Than what?

A prescaler set to 1? Yes. A Prescaler set to 16K (if there is such a setting)? No.

Seriousl (not trying to be an asshole): what part of the data sheet writing on the prescaler is it that you do not understand? (And when you answer that, also tell us what datasheet you are reading).

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

JohanEkdahl wrote:
Quote:

at slower rate

Than what?

A prescaler set to 1? Yes. A Prescaler set to 16K (if there is such a setting)? No.

Seriousl (not trying to be an asshole): what part of the data sheet writing on the prescaler is it that you do not understand? (And when you answer that, also tell us what datasheet you are reading).


I am sorry for my question...
I am into Atmega88 datasheet, I need a timer that counts to max in more than a second...
I reckon that a prescaler of 1024 would do the job, accuracy in this counter is not an issue...

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

Quote:

I am into Atmega88 datasheet, I need a timer that counts to max in more than a second...
I reckon that a prescaler of 1024 would do the job, accuracy in this counter is not an issue...

How can anyone answer? You haven't said what clock rate you intend to run the mega88 at.

But lets assume it's the fastest possible - 20MHz - one CPU cycle is 50ns. If you use a /1024 prescaler then a timer tick is 51.2us. An 8bit timer counts 256 times so it can reach 51.2us*256 = 13.1072ms. A 16 bit timer can count to 256 times this amount so 3.35s

EDIT: just figured that ns*1000=us, not ms - Doh!

Last Edited: Wed. May 12, 2010 - 09:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

F_CPU/prescaler/65536 gives the frequency for a 16 bit timer. e.g.

1MHz / 1024 / 65536 = 0.015 Hz so 67 seconds.

Even at 20MHz clock you will get 3.35 seconds.

F_CPU/prescaler/256 gives the frequency for a 8 bit timer. e.g.

1MHz / 1024 / 256 = 3.8 Hz so 0.262 seconds.

David.

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

Cheers mates!
I am using the internal clock (8Mhz) with div8...
Using int i=TCNT1, is that 16bit value from the timer?
Do I needa to set the timer to 16 bits?
I do believe that TCNT1 is 16bits...

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

Why don't you make a cup of tea (just pre-empting David!) then sit down and read:

a) this tutorial again

and

b) the datasheet

All the questions you have posed so far would have been explained by one or other of those.

(and yes on a 48/88/168 timer0=8bit, timer1=16bit and timer2=8bit)

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

Cheers clawson...
I did read the tute and datasheet, but just to comfirm...
Sorry if my question are really stupid...
I have not done embbeded programming before...

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

Quote:

I have not done embbeded programming before...

About 20-30% of the job is reading - there's no avoiding that I'm afraid.

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

Hi All,
Grade tutorials!
I'm stuck on Part Five - CTC Mode using Interrupts...
I'm using WinAVR as compiler + AVR Studio simulator.
In winAVR everything looks ok - no errors from compile but in simulation (I attached *.elf file for AVR Studio) simulation never jump to the ISR(TIMER1_COMPA_vect).
I tried with ATmega128 + LED and as well dosen't work.
I will happy hepy if some body could help me, please.
Slav.

Attachment(s): 

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

Do not trust the simulator for CTC and PWM modes.

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

very nice tutorial!

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

You rock buddy,,...

What an awesome tutorial

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

only starting from the scratch, anyone can understand timer. very good job. I like it. Thanks for the sharing.

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

thankz Dean, keep writing please, your stuff is very useful, glad to read it.

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

From the ATmega168 datasheet:

...In CTC mode the counter is cleared to zero when the counter value (TCNT1) matches either the OCR1A (WGM13:0 = 4) or...

So, if counter is 2bit and:

OCR1A=3;

The counter is being cleared immediately the
counter try to switch from 2 to 3:

TCNT1: |0|1|2|0|1|2|0|1| ...
       |<-T->|

So the time elapsed since the reset is

T = Number * Tck

not

T = (Number + 1) * Tck

Where number is what I stored in OCR1A register.

Or the counter is cleared when counter try to switch from 3 to 4 so when elapsed the 3...not at begin.

Where I am mistaking?

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Quote:
...we calculated that 1Hz at 1MHz with a prescaler of 64 needs a compare value of 15624...

But if I use "Avr fp calc", I have as result 15625 (0x3D09)

Still not clear this point...

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

CTC always uses 1 less than you think because 0 is included in the count. So if you want 6 counts you set it to 5 and the counts are then 0, 1, 2, 3, 4, 5 - which is 6 periods.

Avrcalc (the Tiddwell program) does NOT make this -1 adjustment so the displayed OCRH/L value is always one more than you actually require for CTC usage.

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

clawson wrote:
So if you want 6 counts you set it to 5 and the counts are then 0, 1, 2, 3, 4, 5 - which is 6 periods.

So I have to set OCRxx a number greater than the top of the timer?

I.e. : I want T=1s, my Tck is 0.25s, I need of count up to 3, so my OCRxx should be 4 ?

[0][1][2][3|<--- Here happens the match? 

Quote:
Avrcalc (the Tiddwell program) does NOT make this -1 adjustment

Glad to hear that was a bug of this AVRcalc :)

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Quote:

Glad to hear that was a bug of this AVRcalc

It's not a bug because what it offers is the value to reset TCNT to in an OVF ISR

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

clawson wrote:

It's not a bug because what it offers is the value to reset TCNT to in an OVF ISR

:( .... I have to study better the matter...will search for a good book.

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Ok...now it's clear to me...just the datasheet ;) of ATmega168, p. 16:

Quote:
...The 16-bit comparator continuously compares TCNT1 with the Output Compare Register (OCR1x). If TCNT equals OCR1x the comparator signals a match. A match will set the Output Compare Flag (OCF1x) at the next timer clock cycle. If enabled (OCIE1x = 1), the Output Compare Flag generates an Output Compare interrupt.

So:

OCR1A=3; // We want a time of (4 * tick)
TCNT1: |0|1|2|...
       |<-T->|<--- here comparator signals a match 

but:

TIFR1: |0|1|2|3|...
       |<--T-->|<--- here OCF1A is flagged (and int. fired)

When OCF1A is set, an "Output Compare Match A Interrupt" is fired (of course if it has previoulsy enabled) so interrupt happens every 4 periods instead of 3.

update

A similar behaviour is performed when timer is used in normale mode. ATmega168 datasheet, p. 119:

Quote:
In normal operation the Timer/Counter Overflow Flag (TOV1) will be set in the same timer clock cycle as the TCNT1 becomes zero.

So overflow interrupt is fired on restart from zero, a tick after timer has got to its maximum value (overflow).

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Another doubt :)

Found this trick to achieve customizable times also in normale mode:

http://www.ermicro.com/blog/?p=950

Quote:
We set the ATMega168 TIMER0 overflow interrupt on every 10ms, this could be achieve by setting the TIMER0 prescaler to 1024 and TIMER0 counter register (TCNT0) to 0×94 as this following code:

// Initial ATMega168 Timer/Counter0 Peripheral
TCCR0A=0x00;                  // Normal Timer0 Operation
TCCR0B=(1<<CS02)|(1<<CS00);   // Use maximum prescaller: Clk/1024
TCNT0=0x94;                   // Start counter from 0x94, overflow at 10 mSec
TIMSK0=(1<<TOIE0);            // Enable Counter Overflow Interrupt
sei();                        // Enable Interrupt

With the TCNT0 register set to 0×94 (148) and using AVRJazz Mega168 board clock frequency of 11059200 Hz; then we could calculate the TCNT0 over flow period as follow:

TIMER0 clock frequency with 1024 prescaler = 11.059.200 Hz / 1024 = 10.800 Hz

TCNT0 overflow period = (256 - 148) / 10.800 Hz = 0.01 Second = 10 ms

Ok...we start loading the TCNT0 with an initial number greater than zero...but once the timer is cleared on interrupt, it will restart from zero not from this value.

Is it?

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

I think you will find that TCNT0 is reset to 0x94 inside ISR(TIMER0_OVF_vect). Now, if the timer has a CTC mode, then it's much better to use that. Basically any code that updates TCNTx inside an interrupt will have inexact timing (from the interrupt latency).
/Lars

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

Lajon wrote:
I think you will find that TCNT0 is reset to 0x94 inside ISR(TIMER0_OVF_vect). Now, if the timer has a CTC mode, then it's much better to use that. Basically any code that updates TCNTx inside an interrupt will have inexact timing (from the interrupt latency).
/Lars

Thanks for your precisation. You are right, the reset ot 0x94 it's done in a code (above) of course as last istruction, without any comment, any explanation :( :

ISR(TIMER0_OVF_vect)
{
 ....
 TCNT0=0x94;
}

I agree with you: this trick "violates" a bit that needs that motivate to use timer (we want exact timing not depending on software execution times).

So CTC mode is always to prefer unless we finished all CTC channels (A and B) ;)

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Quote:
So CTC mode is always to prefer unless we finished all CTC channels (A and B)
I think that you will find that though there may be more than one compare match channel in a timer, only one of them can be used for CTC. After all, how could you have the timer reset at two different values since the timer would be reset at the lower value and never reach the higher value. Only the OCRxA register can be used as TOP in CTC.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Only the OCRxA register can be used as TOP in CTC.

So, OCR1B register at what can be used for?

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

PWM mode. When in PWM mode, you can use both (or, on some timers, all three) channels for individual channel control, because you are changing each channel's individual compare value, and not TOP. When in CTC mode, the timer is reset once the compare value is reached, making any additional channels useless.

- 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:
PWM mode.

Thanks Dean. Your tutorial about PWM will be my next step ;)

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Koshchi wrote:
Only the OCRxA register can be used as TOP in CTC.

p.109, ATmega168 datasheet:

"If a fixed TOP value is required, the ICR1 Register can be used as an alternative, freeing the OCR1A to be used as PWM output."

So if we are in CTC mode (either with interrupt or "pure CTC") we can also use ICR1, instead of OCR1A, to set TOP value?

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Quote:

So if we are in CTC mode (either with interrupt or "pure CTC") we can also use ICR1, instead of OCR1A, to set TOP value?

Yes, look to your AVR's datasheet there's a 16 entry table showing 16 timer Waveform Generation Modes (WGM) labelled mode 0 to mode 15. I predict that you see CTC twice there (maybe modes 4 and 12) one using OCR1A as "TOP" and one using ICR1

EDIT: just checked 168 data and it's the same as the mega16 data I was looking at.
Cliff

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

What do you think about of the following way to measure a pulse width of a square input signal, about equal to (tfall - trise) ?

Since Timer1 rolls over continuously, in order to measure time differences greater than 2^n*Tck, I was thinking to add a count number to keep trace of which period is referring the TCNT1 data.

For example, if the timer has 2bit:

count +4      +8     +12      +16
       |       |       |       |
0|1|2|3|0|1|2|3|0|1|2|3|0|1|2|3|0|1|2|3|...
   |<------------->|      
  rise            fall

Infact:

fall_time - rise_time = (10-2) * Tclock

At every timer overflow, the variable count is incremented of 4 (2^n).

A possible pseudo code:


count = 0;

Timer1 Overflow Interrupt:
{
  count = count + 2^n;
}


Capture Input Interrupt:
{
   if input is rising
   {
      rise_time = ICR1 + count;
      change input sense to falling; 
   } 
   else 
   {
      fall_time = ICR1 + count;
      change input sense to rising;
      calculate pulse width as (fall_time - rise_time);
      count = 0; 
   }

}

What do you think about?

But if count (unsigned long) being greater than 2^32?

How I can prevent overflow error?

EDIT1: I could reset count variable after calculated pulse width. Correct?

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

You are dragging this thread off topic - it is for discussion of the tutorial article presented in the first post. For questions like this please start a new thread in AVR Forum.

Moderator.

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

clawson wrote:
You are dragging this thread off topic

sorry, my apologies.

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

thanks

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

Okay so I followed the TUT add a bit(sort off)and got this code:

#include      
#include  

volatile uint8_t count;

int main(void)
{
// LED outputs
	DDRC |= (1<<DDC1)|(1<<DDC2); 

// TIMER0 
   // Prescaler = FCPU/1024 FCPU =16MHz
   TCCR0A|=(1<<CS02)|(0<<CS01)|(1<<CS00);

   //Enable Overflow Interrupt Enable
   TIMSK0|=(1<<TOIE0);

   //Initialize our varriable
   count = 0;
	
	//Enable Global Interrupts
   sei();

   //Infinite loop
   while(1);

}

//interrupt vir timer0 overflow each 16.3ms

ISR(TIMER0_OVF_vect)	
{

	count++;
	// Flash 1s , off 1s
	if (count == 61)
	{
		count = 0;
		PORTC ^= (1<<PORTC2);
		PORTC ^= (1<<PORTC1);	
	}
}

But the LED's just wont flash, what is wrong?

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

You didn't say which AVR but based on the TIMSK0 I guessed it might be a 48/88/168/328. I built and ran the code in simulator 2 with a breakpoint in the ISR. After several minutes when it hadn't hit the breakpoint I studied the Timer0 registers to see what was happening.

That's when I discovered that CS0n weren't in TCCR0A on that chip - they are in TCCR0B.

So far this is all guess work as you didn't give enough detail but I'm guessing you are using an AVR that does not have the CS0n bits in the A register

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

Thanx clawson! Correct my CS0n was in TCCR0B register. Your guess work is not far off its the 324. I will remember to include mu AVR next time in my question so no one will have to guess.

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

Good grief man, you are a wizard Clawson. How you managed to get that amount of data by just that amount of input is beyond me.

Chapeu!

Code, justify, code - Pitr Dubovich

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

It was just an educated guess really but the moral of this tale (assuming you don't have an OCD interface) is to try timer code in the simulator if it doesn't appear to work in the hardware. As simulator1 is utter rubbish at simulating timers it's worth "porting" the code to a modern AVR model and trying that in simulator2. In this case it was lucky it just happened to be for a "modern" AVR anyway which was already supported by sim2 (which is why, when it didn't "tick" at all, I knew there was something fundamentally wrong as the sim2 timers can usually be trusted)

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

Quote:

How you managed to get that amount of data by just that amount of input is beyond me.

One word: Experience

(Seriously)

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

I believe you. Experience.

And I am glad that he explained that bit about Sim2 as well. As you might have gathered from my earlier posts, I am often in places where simulation is my only option.

Code, justify, code - Pitr Dubovich

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

Dude!
what an awsome tutorial!
i enjoyed reading it and enjoyed playing with my AVR.
Thank you very much for the great guide!
by the way, what are(were?) you studying at the university?

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

Thanks!

Quote:

by the way, what are(were?) you studying at the university?

Still here - studying for a double degree in Computer Science and Electronics Engineering. I'm in my fourth of either five or six years, depending on if I do honors.

- Dean :twisted:

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

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

Dean

Thanks a million! What a tricky subject and how well you've dealt with it.

I started life with the Arduino platform (a few weeks back) and have progressed 'downwards' to a ATtiny25 :) Built my own dev platform and programmer (USBtinyisp) and am loving every minute of it :)

Professionally, I'm a software engineer (writing that .NET cr@p), but these little MCU's are more fun than I've had in years!!

For any ATtiny users who have struggled with this tutorial, I offer up the following heavily documented code that I've got working...

Hope it can help somebody...

/*
 * main.c
 *
 * BlinkInterrupts project
 *
 *  Created on: Nov 14, 2010
 *      Author: gregorysmith
 *
 *  Set for a ATtiny25 with internal clock / 8 == 1Mhz
 *
 */

/*
 * Random thoughts
 *
 * 	1,000,000 fqz / 1024 = 1000  milliseconds???
 * so
 * each tick of the isr routine = 255 (see counter OCR0A)
 * so
 * times the tick by 4 to = 1000 i.e 1 second (ish)
 */

#define F_CPU 1000000UL


#include 
#include 

long cnt = 0L;		// a delay counter for making the counter longer



// prototypes
void Setup(void);


void Setup(void)
{
	// Start by making sure interrupts are OFF
	//
	cli();
	// Set port direction and initial state
	//
	// PB4 off, PB3 on,  BOTH port bits as outputs
	//
	DDRB |= (1<<PB4);
	DDRB |= (1<<PB3); /* set PB4 and PB3 to output */

	PORTB |= (1<<PB4);  // LED on
	PORTB &= ~(1<<PB3); // LED off
	//------------------------------------------------
	//
	// Setup timer control register B for timer 0
	// with a /1024 prescaler
	TCCR0B |= (1 << CS02); // Set up timer (control register 0, CS02 = prescaler )
	TCCR0B |= (1 << CS00); // Set up timer (control register 0, CS00 = prescaler == 1024)
	//-----------------------------------------------------------------------------------
	//
	// Set timer control register A for a compare mode
	 TCCR0A |= (1 << WGM01);  // CTC mode
	 //------------------------------------------------
	 //
	 // Set the value that the timer is being compared with
	 OCR0A = 0xFF; //  compare == 255
	 //-----------------------------------------------------
	 //
	 // Now enable the output compare interrupt enable via the mask register
	 TIMSK |= (1 << OCIE0A); // Enable CTC interrupt
	 //
	 // set the global interrupt enable flag
	 sei();	// enable interrupts

}

// What exactly do we want to happen when the interrupt occurs?
// well, as it's firing too fast for us, we need to slow everything down
// we will keep a counter that increments each time it fires and only
// do the 'thing' when 'our' counter reaches the desired value (cnt ==4)
ISR(TIMER0_COMPA_vect)
{

	cnt++;			// increment a long counter
	if(cnt > 3L) {	// and test it (in this case it eq 4)

	 PORTB ^= (1<<PB4); /* LED toggle */
	 PORTB ^= (1<<PB3); /* LED toggle */

	 cnt=0;	// reset our count
	}
} // end of interrupt service routine



// Our main program is just going to set things up
// and then do 'nothing'
int main()
{
	Setup();	// action the setup routine

	while(1){;} // do nothing -- everything should happen via interrupts

}

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

hey Dean..tutorial really helped..I was just wondering, in Case 3 (using variables) my LED is both ON and OFF for the same duration. How could I change the duration of either one? I was planning on using these timers in a sort of PWM fashion (Topic:PWM....WITHOUT PWM?????)...cheers

Pages