Trivial Timer1 Trouble

Hi,
I’m trying to understand the Timer1 and I have some questions on a tutorial code I’m using to learn the timer.

#include <mega16.h>

#define period_out PORTC

unsigned char ov_counter; 
unsigned int starting_edge, ending_edge; 
unsigned int clocks;

interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
	++ov_counter;
}

interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
	ending_edge = 256*ICR1H+ICR1L;
	clocks = (unsigned long) ending_edge + ((unsigned long) ov_counter * 65536) - (unsigned long) starting_edge;
	period_out = ~(clocks / 750);
	ov_counter = 0;
	starting_edge = ending edge;
}

void main(void)
{
	DDRC = 0xFF; 
	TCCR1A = 0xFF;
	TCCR1B = 0xC2;
	TIMSK = 0x24;
	#asm("sei")

	while(1)
	{
		;
	}
}

I’m not sure if my understanding is right:

  1. starting_edge will be set first time ICP is set
  2. after that timer starts to count and may overflow
  3. overflow quantities are being counted by ISR
  4. when ICP is set again, duration is calculated
  5. calculation is: the ending_edge time, when ICP goes set again, plus how many times overflow happened, minus the starting_edge when first ICP was set.

I also can’t understand this line:

period_out = ~(clocks / 750);

Well the timer is clocked by Fclk/8 (6MHz / 8 = 750) so 750 counts per ms, so we divide clocks by 750, but then what does the “~” operator there please?!

I would greatly appreciate the help to understand these moments.

schema_timer1.TIF (416 KB)

but then what does the "~" operator there please?!

http://arduino.cc/en/Reference/BitwiseXorNot

That code does not look like Arduino code. Have you tried compiling?

It will compile just fine, but variables shared between ISR’s and other functions and main must be declaread volatile, example:
volatile unsigned char ov_counter;

PaulS:

but then what does the “~” operator there please?!

http://arduino.cc/en/Reference/BitwiseXorNot

That code does not look like Arduino code. Have you tried compiling?

Paul it is neither Arduino code, nor for compiling! It is in a book on AVR, as an example code to understand the Timer1 which till now I can’t :frowning:

I decided to get deeper understanding the MCU with purpose of writing libraries to not to write same code every time.

My problem now exactly is that I can’t fully understand “time” and “count” in Timer1.

This line:

clocks = (unsigned long) ending_edge + ((unsigned long) ov_counter * 65536) - (unsigned long) starting_edge;

Is still a mystery to me, I really need to finish studying this book and fully understand it, please help if you can, by explaining the line. I’ll upload a scan of the part the code is explained and attach (start from 2.7.3. on the middle of the first page ignoring the code of first page).

timer1.pdf (1020 KB)

starting_edge and ending_edge are when events of interest occurred. The timer counts up to 65,636, then overflows. Each time it overflows ov_counter is incremented. So, the total time is 65536 * the number of overflows + ending_edge - starting_edge.

Think of it like this. Supposed starting_edge represented a time, like 2:30 Wednesday afternoon, and ending_edge represented a time, like 8:30 Saturday morning. You want to determine the elapsed time between those events. There is part of Wednesday, all of Thursday and Friday, and part of Saturday to consider. All of Thursday and Friday is represented by 2 in ov_counter. So the total time is 9.5 (for Wednesday) + 2 * 24 (hours) + 8.5 (for Saturday).

Paul, many thanks!

So to model the way you described:

  1. Our timer counts 65,636
  2. When the event starts, the MCU reads Timer1, (possibly a part of it, as in your description)
  3. There may be x times "whole 65,636".
  4. When the event ends, the MCU reads Timer1, again possibly a part of 65,636
  5. The formula counts some "y"
  6. We divide this 'y' by 750 (spec. to this hardware/software setup) and get how many ms time passed.

Did I get it right please?

A final question: Then how I know that the clock (variable, in the formula below) itself will not over flow? Since even a 'long' may not be enough!

clocks = (unsigned long) ending_edge + ((unsigned long) ov_counter * 65536) - (unsigned long) starting_edge;

The ~ operator is bitwise NOT. Its closely related to negation (for 2's complement arithmetic which is what nearly all computers use for signed integers) ~a == -1-a

Did I get it right please?

I think so.

A final question: Then how I know that the clock (variable, in the formula below) itself will not over flow? Since even a 'long' may not be enough!

You should figure out what the type is for clocks. Then, see what the range of values are for that type. Then, consider what period of time that represents, before the value rolls over.

On the Arduino, millis() returns an unsigned long, which rolls over after approximately 49 days.

Many thanks Paul! I'm now going on with the book. Toward learning to write efficient code on MCU...the endless road... :-)

PaulS: starting_edge and ending_edge are when events of interest occurred. The timer counts up to 65,636, then overflows. Each time it overflows ov_counter is incremented. So, the total time is 65536 * the number of overflows + ending_edge - starting_edge.

Think of it like this. Supposed starting_edge represented a time, like 2:30 Wednesday afternoon, and ending_edge represented a time, like 8:30 Saturday morning. You want to determine the elapsed time between those events. There is part of Wednesday, all of Thursday and Friday, and part of Saturday to consider. All of Thursday and Friday is represented by 2 in ov_counter. So the total time is 9.5 (for Wednesday) + 2 * 24 (hours) + 8.5 (for Saturday).

There is a mystery in this still for me!

When you counted Wednesday you took out the 2:30 from the whole, i.e. 12 - 2.5 = 9.5. Next the complete formula is:

12 - 2.5 + 8.5 + x*2*12

According to you model, I think the counting for MCU must be: "65536 - starting_edge + ending_edge + x*65536", but there is one time 65536 lost in the book's formula! Isn't it?

clocks = (unsigned long) ending_edge + ((unsigned long) ov_counter * 65536) - (unsigned long) starting_edge;