atmega8 измерение частоты

nanotroll
Offline
Зарегистрирован: 24.07.2016

Добрый день! 

16-разрядный таймер Т1 вызывает прерывание раз в секунду (частота 12МГц внешний кварц, предделитель 256, 46875 тиков - 1 сек). 8-разрядный тактируется от внешнего сигнала (вход Т0), считает количество переполнений. В прерывании таймера 1 я считаю сколько пришло импульсов по формуле: Fin = TIM0_OVF_cnt * 256 + TCNT0. Значение выводится на lcd. В протеусе при входном сигнале 100 Гц показывает точно 100, при 500 Гц уже 499, при 1000 Гц показывает 9980. Так и должно быть, или это ошибка в коде/формуле/протеусе?

#define F_CPU 12000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd-lib.h"

volatile unsigned int ovfCnt = 0;
char freqBuff[20];

void timersInit() {
	// Timer 1
	TIMSK = (1<<OCIE1A) | (1<<TOIE0);
	TCCR1B = (1<<WGM12) | (1<<CS12); // CTC mode, prescaler 256
	TCNT1 = 0;
	OCR1A = 46875;
	
	// Timer 0
	TCCR0 = (1<<CS02) | (1<<CS01) | (1<<CS00); // External clock source on T0, clock on rising edge
}

void gpioInit() {
}

void indication() {
	unsigned int freq = (ovfCnt * 256) + TCNT0;
	
	lcd_home();
	sprintf(freqBuff, "%d", freq);
	lcd_string(freqBuff);
}

ISR (TIMER1_COMPA_vect) {
	indication();
	ovfCnt = 0;
	TCNT0 = 0;
}

ISR (TIMER0_OVF_vect) {
	ovfCnt++;
}

int main(void)
{
	gpioInit();
	timersInit();
	lcd_init();
	
	sei();
	
    while(1)
    {
    }
}

krigemelik
Offline
Зарегистрирован: 18.09.2018

Некропост конечно, но вдруг кому интересно. Нельзя обнулять TCNT0. Нужно продолжать считать, а при следующем вычислении частоты вычесть начальное значение TCNT0 с учётом его переполнения. Погрешность появилась из-за того что были потеряны насчитанные импульсы пока был вывод на экран.