#include <mega16.h>
#include <delay.h>
#define F_CPU 8000000UL

//Номер цифры числа частоты
unsigned char dig_id = 0;
//Количество обнулений таймера 0
unsigned long int t0 = 0;
//В этой переменной будет храниться частота
unsigned long int frequ = 123456789;

//Процедура включения сегментов из которых получается число
void output(unsigned char digit, unsigned char dot) {

	//Целиком используется порт B для включения отдельных сегментов
	unsigned char portout[10] = {0b11111010,0b00100010,0b10111001,0b10101011,0b01100011,0b11001011,0b11011011,0b10100010,0b11111011,0b11101011};
	PORTC = portout[digit];
	
	//Включение точки если необходимо
	if (dot == 1) PORTC.2 = 1;
	else PORTC.2 = 0;
	
	return;
	
}

//Прерывание по переполнению таймера 0 происходит приблизительно каждые 2 мс, зависит от F_CPU
//Это прерывание позволяет выводить цифры на LED дисплей
interrupt [TIM2_OVF] void timer2_ovf_isr(void) {

	//Разрешим прерывания, что позволит точно измерять длительность и количество импульсов
	//То есть позволит прерывания по таймерам 0 и 1.
	#asm("sei");
	
	//Вывод на дисплей числа (всего 9 цифр)
	//Для включения каждой цифры целиком используется порт A и пин 0 порта D
	switch (dig_id) {
		case 0:
			PORTD.7 = 1;
			output(frequ%10,1);
            PORTA.0 = 0;
			break;
		case 1:
			PORTA.0 = 1;
			output((frequ/10)%10,0);
            PORTA.1 = 0;
			break;
		case 2:
			PORTA.1 = 1;
       		output((frequ/100)%10,0);
            PORTA.2 = 0;
			break;
		case 3:
			PORTA.2 = 1;
			output((frequ/1000)%10,1);
            PORTA.3 = 0;
			break;
		case 4:
			PORTA.3 = 1;
			output((frequ/10000)%10,0);
            PORTA.4 = 0;
			break;
		case 5:
			PORTA.4 = 1;
			output((frequ/100000)%10,0);
            PORTA.5 = 0;
			break;
		case 6:
			PORTA.5 = 1;
			output((frequ/1000000)%10,1);
            PORTA.6 = 0;
			break;
		case 7:
			PORTA.6 = 1;
			output((frequ/10000000)%10,0);
            PORTA.7 = 0;				
			break;
		case 8:
			PORTA.7 = 1;
    		output((frequ/100000000)%10,0);
            PORTD.7 = 0;
			break;
		default:
			break;
	}		
    //При следующесм прерывании переходим к следующей цифре числа
    if (dig_id >= 8) dig_id = 0;
    else dig_id++;
}


// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void) {
	//Остановка счётчиков
	TCCR1B = 0x00;
	TCCR0 = 0x00;
	
	frequ = F_CPU * TCNT1 / (TCNT0 + 256 * t0);

	//Обнуление счётчиков
	TCNT0 = 0x00;
	TCNT1 = 0x00;
	t0 = 0;
	
	//Запуск счётчиков
	// clk / (No prescaling)
	TCCR0 = 0x01; // 0000 0001
	// External clock source on T1 pin. Clock on rising edge.
	TCCR1B = 0x07; // 0000 0111
	
}

//Прерывание по переполнению таймера 0
//Это прерывание как бы добавляет разряд к таймеру
interrupt [TIM0_OVF] void timer0_ovf_isr(void) {
	t0++;
}

void main(void) {
	
	//unsigned int delayms = 1000;
	
	DDRA = 0xff;
	DDRB = 0xfd; //1111 1101
	DDRC = 0xff;
	DDRD = 0xff;

	PORTA = 0xff;
	PORTB = 0x00; // 0000 0000 На PORTB.1 Z состояние!!! необходима подтяжка на 0
	PORTC = 0x00;
	PORTD = 0x80; // 1000 0000

	//Таймер 0 Normal Mode Коэф-т деления 1
	//Будет считать время
	// clk / (No prescaling)
	TCCR0 = 0x01; // 0000 0001
	TCNT0 = 0x00;
	OCR0 = 0x00;
	
	//Таймер 1 Normal Mode Коэф-т деления 1
	//Будет считать количество импульсов
	TCCR1A = 0x00;
	// External clock source on T1 pin. Clock on rising edge.
	TCCR1B = 0x07; // 0000 0111
	TCNT1 = 0x00;
	ICR1H = 0x00;
	ICR1L = 0x00;
	OCR1A = 300;
	OCR1B = 0x00;
	
	//Таймер 2 Normal Mode коэф-т деления 64
	//Будет помогать выводить числа на LED
	TCCR2 = 0x04; // 0000 0100
	TCNT2 = 0x00;
	OCR2 = 0x00;
	
	//Прерывание по переполнению таймера 0
	//Timer/Counter1, Output Compare A Match Interrupt Enable
	//Прерывание по переполнению таймера 2
	TIMSK=0x51; // 0101 0001
	//Глобально разрешаем прерывания
	#asm("sei");

	//Программа тут
	while (1) {
	}
}
