1
\$\begingroup\$

How is the signal frequency measured in ATmega? In particular, how is the signal frequency (sine) measured in ATmega8?

\$\endgroup\$
  • 1
    \$\begingroup\$ It may be better to write Sine wave or Sinusoid instead of Sinus \$\endgroup\$ – RedGrittyBrick Dec 14 '13 at 12:40
  • \$\begingroup\$ Does ATmega8 have an ICP (input capture pin)? That is ideal for timing signal period. \$\endgroup\$ – jippie Dec 15 '13 at 7:44
1
\$\begingroup\$

Sample values using an ADC with a minimum frequency which needs to be twice (more is better ;-) the frequency you expect your sinus to be. Then perform a FFT (see here as well). Depending on how fast/often you need this to be done this should be possible on the atmega family.

That one here actually looks pretty impressive to be honest

\$\endgroup\$
3
\$\begingroup\$

Assuming that you are only interested to measure the frequency of the sinusoidal I would say convert it to square wave pulses (for example with an optocoupler) and then use the timers to measure the square wave.

There are several ways to measure the frequency but the more accurate is by using the input capture unit, refer to this post.

Another alternative that will give pretty accurate results but not as accurate as the above method is to use timer 1 as a gate for timer 0 to measure pulses in a specified window (for example 100ms) and then use math to get the signal frequency. In order to do that you set timer 0 to use the external signal pulses as a clock source, here is what I mean:

// sample for mega88
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/power.h>

#define ENABLE_TIMER1    TCCR1B=(1<<CS11) | (1<<CS10);
#define DISABLE_TIMER1    TCCR1B=0x00;
#define ENABLE_TIMER0    TCCR0B=(1<<CS02) | (1<<CS01) | (1<<CS00);
#define DISABLE_TIMER0    TCCR0B=0x00;
#define RESET_TIMERS    TCNT1 = 53036; TCNT0=0x00; timer0_ovf=0; timer1_ovf=0;

volatile unsigned char timer1_ovf;
volatile unsigned int timer0_ovf;
uint32_t frequency;

// Timer 0 overflow interrupt service routine
ISR(TIMER0_OVF_vect)
{
    timer0_ovf++;  // overfloaw counter , will be used in calculations later
}

// Timer1 overflow interrupt service routine
ISR(TIMER1_OVF_vect)
{
    DISABLE_TIMER1
    DISABLE_TIMER0
    timer1_ovf = 1;      // flag that measure has finshed
}


uint32_t measure_frequency(void)
{

    RESET_TIMERS
    _delay_ms(1);

    ENABLE_TIMER1
    ENABLE_TIMER0

    while(timer1_ovf != 1);  // wait for flag

    // measure window is 0.1sec, to convert to sec multiply with 10
    return (((TCNT0 + (256UL * timer0_ovf)) * 10));

}

void main(void)
{
    // Crystal Oscillator division factor: 1
    clock_prescale_set(clock_div_1);   

    // Timer/Counter 0 initialization
    // Clock source: T0 pin Rising Edge
    // Mode: Normal top=0xFF
    // OC0A output: Disconnected
    // OC0B output: Disconnected
    TCCR0A = (0 << COM0A1) | (0 << COM0A0) | (0 << COM0B1) | (0 << COM0B0) | (0 << WGM01) | (0 << WGM00);
    TCCR0B = (0 << WGM02) | (1 << CS02) | (0 << CS01) | (0 << CS00);
    TCNT0 = 0x00;
    OCR0A = 0x00;
    OCR0B = 0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: 125,000 kHz
    // Mode: Normal top=0xFFFF
    // OC1A output: Disconnected
    // OC1B output: Disconnected
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer Period: 0,52429 s
    // Timer1 Overflow Interrupt: On
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0) | (0 << WGM11) | (0 << WGM10);
    TCCR1B = (0 << ICNC1) | (0 << ICES1) | (0 << WGM13) | (0 << WGM12) | (0 << CS12) | (0 << CS11) | (0 << CS10);
    TCNT1 = 53036;  // 65536-12500 = 53036  , overflow at 100ms
    ICR1H = 0x00;
    ICR1L = 0x00;
    OCR1AH = 0x00;
    OCR1AL = 0x00;
    OCR1BH = 0x00;
    OCR1BL = 0x00;

    // Timer/Counter 0 Interrupt(s) initialization
    TIMSK0 = (0 << OCIE0B) | (0 << OCIE0A) | (1 << TOIE0);

    // Timer/Counter 1 Interrupt(s) initialization
    TIMSK1 = (0 << ICIE1) | (0 << OCIE1B) | (0 << OCIE1A) | (1 << TOIE1);

    // Global enable interrupts
    sei();

   frequency = measure_frequency();  // measure frequency and store to variable

    while(1)
    {
        // Place your code here

    }
} 
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.