#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include "ind.h"
#include "HC595.h"

#define SEG_A				(1<<0) //Назначаем сегменты
#define SEG_B				(1<<2)
#define SEG_C				(1<<4)
#define SEG_D				(1<<6)
#define SEG_E				(1<<7)
#define SEG_F				(1<<1)
#define SEG_G				(1<<3)
#define SEG_H				(1<<5)	


unsigned char ind_pos=0; //Номер позиции для вывода.
unsigned char ind_byte=1; //Байт для вывода в регистр, Выбор разряда.
volatile unsigned char cur_pwm=0; //Текущее значение ШИМ

volatile unsigned char ind_state=0; //Состояние индикации 0=выкл. 1=вкл.

volatile unsigned char ind_data[TOTAL_DIGITS+1];

const unsigned char digits[]   =   //Коды сегментов. Проект был сложный, потому их много. 
	//По хорошему, это нужно поместить в память программ, а не в ОЗУ. Но мне было лениво.
{
	SEG_A+SEG_B+SEG_C+SEG_D+SEG_E+SEG_F,

	SEG_B+SEG_C,

	SEG_A+SEG_B+SEG_D+SEG_E+SEG_G,

	SEG_A+SEG_B+SEG_C+SEG_D+SEG_G,

	SEG_B+SEG_C+SEG_F+SEG_G,

	SEG_A+SEG_C+SEG_D+SEG_F+SEG_G,

	SEG_A+SEG_C+SEG_D+SEG_E+SEG_F+SEG_G,

	SEG_A+SEG_B+SEG_C,

	SEG_A+SEG_B+SEG_C+SEG_D+SEG_E+SEG_F+SEG_G,

	SEG_A+SEG_B+SEG_C+SEG_D+SEG_F+SEG_G,

	0,

	SEG_G,

	SEG_A+SEG_B+SEG_C+SEG_E+SEG_F,

	SEG_B+SEG_C+SEG_E+SEG_F+SEG_G,

	SEG_A+SEG_B+SEG_C+SEG_D+SEG_E+SEG_F+SEG_G,

	SEG_F+SEG_E+SEG_D+SEG_G,

	SEG_A+SEG_D+SEG_E+SEG_F,

	SEG_A+SEG_B+SEG_E+SEG_F+SEG_G,

	SEG_B+SEG_C+SEG_F+SEG_G,

	SEG_A+SEG_C+SEG_D+SEG_E+SEG_F+SEG_G,

	SEG_A+SEG_D+SEG_E+SEG_F+SEG_G,

	SEG_E+SEG_G,

	SEG_B+SEG_C+SEG_D+SEG_E+SEG_G,

	SEG_C+SEG_D+SEG_E+SEG_G,

	SEG_C+SEG_E+SEG_G,

	SEG_A+SEG_E+SEG_F+SEG_G,

	SEG_C+SEG_D+SEG_E+SEG_F+SEG_G
};



ISR(TIMER0_OVF_vect) //Прерывание по переполнению. Выводим текущую цифру и инкрементируем позицию.
{
	if(ind_state) //Если включено
	{
		Write_Byte(ind_byte); //Здесь работа с индикаторами осуществляется через 74HC595. Функции эти в другом файле. (#include "HC595.h")
		Write_Byte(digits[ind_data[TOTAL_DIGITS-ind_pos-1]]);  //Перекодируем в семисегментный. Это можно делать заранее, в функции ниже.

		Trig_Buf(); //Дергаем регистр. Только после этой строки на выводах регистра появится записанный туда байт.

		ind_pos++; //Инкримент позиции для вывода. 
		ind_byte*=2; //Устанавливаем следующий разряд. Если они не по порядку, то сдесь можно сдлеать точно так же, как и с кодом сегментов, через массив.

		if(ind_pos>=TOTAL_DIGITS) //Сброс если достигли конца.
		{
			ind_pos=0;
			ind_byte=1;
		}
	}
}

ISR(TIMER0_COMP_vect) //Прерывание по сравнению. Гасим индикатор
{
	if(ind_state) //Если включено
	{
		OCR0=cur_pwm;
		Write_Byte(0);
		Write_Byte(0);
		Trig_Buf();	
	}
}


void Ind_SetTime(unsigned char hr,unsigned char min) //Пример функции для вывода на индикатор. 
{
	ind_data[0]=hr/10;
	ind_data[1]=hr%10;
	ind_data[2]=min/10;
	ind_data[3]=min%10;
}

void Ind_SetPWM(unsigned char pwm) //Устанавливаем яркость в пределах от 40 до 250 
	//(кажется. промежуток связанн со временем выполнения кода в прерывании. Установить эксперементально)
{
	cur_pwm=pwm;
}

void Ind_On(void) //Включение индикации
{
	ind_state=1;
}

void Ind_Off(void) //Выключение индикации
{
	ind_state=0;    
	Write_Byte(0);	//Гасим все
	Write_Byte(0);
	Trig_Buf();
}

void Ind_Init(void) //Инициализация таймера и прерываний
{
	TCCR0=0x03;
	TCNT0=0x00;
	OCR0=0xF0;

	TIMSK=0x1B;//Это включит еще прерывания. Так что тут нужно посмотреть. 
	//Вообще процедура инициализации переферии у меня одна. Так удобней. Но это для наглядности
	sei();
}