ATMega32 Timer Wrong Results

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Hi, Running ATmega32 at 12MHz fuse setting shown in image at the bottom. Please have a look at code and share whats wrong with the code? always reading wrong frequency.

#define F_CPU 12000000UL

ISR(TIMER1_CAPT_vect)
{
	time=ICR1;
	TCNT1=0;
	ICR1= 0;
}
int main()
{
    setup(); //For port directions
	TCCR1A=0x00;
	TCNT1=0x00;
	TCCR1B  = ((1 << ICNC1) | (1 << ICES1) | (0 << CS10)| (1 << CS11));
	TIMSK|= (1 << TICIE1);

	TCNT1=0x00;
	ICR1=0;
	sei();
	
	cli();
    _freq= 1500000/time;
	sei();
	
	display(_freq);
}

	

The results are as follow 

at 1Hz it shows 20

at 10Hz it shows 40

at 100Hz it shows 50

 

 

This topic has a solution.

Last Edited: Fri. Sep 18, 2020 - 05:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You haven't shown your definitions for _freq or time.

 

time would need to be volatile.

 

Note that names with a leading underscore are reserved for the system - you should not be naming your own variables with a leading underscore.

 

How are you sure it's the measurement that's wrong - rather than your display() function ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint8_t line = 0;
uint8_t red=0;
uint8_t loop=0;
volatile uint16_t time=0;
uint16_t freq=0;

No difference with volatile and and underscore removal.

Display is totally fine I have displayed counter values and the show up correctly

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

Your code has no check that time has been set to a valid value before it is used to compute freq 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Because Time is always going to be overwrite only in ISR. it is updated no where else. And I need time value updated in ISR.

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

sidk wrote:
 Time is always going to be overwrite only in ISR.

But you need to know when it has been updated; ie, when it contains a valid value from which you can calculate a valid frequency.

 

As it stands, your code just uses whatever value it finds as soon as it gets there.

 

You are also exiting from main() - which is not how embedded programs should work.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
You are also exiting from main() - which is not how embedded programs should work.
Worse that that - beyond main() is a CLI so if you have code that is just relying on constant interrupts then they stop once you leave main()

 

BTW rather than just cli() and sei() around the access to shared "time" you might want to explore ATOMIC_BLOCK()

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

My bad, to keep the code clean at this post I copied the selected code and pasted here and while loop got omitted, let me show you complete main chunk as I have cleaned it a bit

int main(void)
{

    setup();
    int speed=0;
    uint8_t _index=0;
    uint8_t _index2=0;
    uint8_t _indexTemp=0;
    uint32_t L_byte=0;
    uint32_t H_byte=0;
    uint64_t A_byte=0;
    uint64_t _disp_delay=0;
    uint64_t value_Hi = 0;
    uint64_t value_Lo = 0;
    uint8_t _dig0;
    uint8_t _dig1;
    uint8_t _dig2;
    uint8_t *_pdig0;
    uint8_t *_pdig1;
    uint8_t *_pdig2;

    TCCR1A=0x00;
    TCNT1=0x00;
    TCCR1B  = ((1 << ICNC1) | (1 << ICES1) | (0 << CS10)| (1 << CS11));
    TIMSK|= (1 << TICIE1);

    TCNT1=0x00;
    ICR1=0;
    sei();

    //Read Frequency 
    
    while(1)
    {
        cli();
        freq= 1500000/time;
        sei();
        
        if (freq>40)
        {
            red =1;
        }
        else
        {
            red=0;
        }

        display(freq);


    }
}

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay its running, the prescalar setting was not suitable for the applied pulse being measured. Thanks all

 

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

The normal way to use ICR is to enable the interrupt,   start a timer.

In the ISR() you subtract the previous ICR value from the current ICR.    This gives you the period.   You never reset the Timer.

 

You can calculate frequency from the period.   Either in the ISR() or by reading period atomically in the foreground code.

 

This works fine for periods within the Timer range.

If you want longer periods you increment a count in an Timer overflow ISR() or you just prescale the Timer to keep inside overflow range.

 

Since the hardware controls ICR value you don't need to worry about latency, display speed, ...

 

Note that calculating the frequency from an integer period gives poor granularity.   (for small number of ticks)

You can improve this x10 by adding 10 periods.

 

David.

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

sidk wrote:
its running

Jolly good - now please mark the soltion.

 

See Tip #5 in my signature, below, if you need instructions:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a really worthy suggestion. Thanks

 

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

david.prentice wrote:

The normal way to use ICR is to enable the interrupt,   start a timer.

In the ISR() you subtract the previous ICR value from the current ICR.    This gives you the period.   You never reset the Timer.

 

You can calculate frequency from the period.   Either in the ISR() or by reading period atomically in the foreground code.

 

This works fine for periods within the Timer range.

If you want longer periods you increment a count in an Timer overflow ISR() or you just prescale the Timer to keep inside overflow range.

 

Since the hardware controls ICR value you don't need to worry about latency, display speed, ...

 

Thanks David for the worthy suggestion.