#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define SetBit(port, bit) port|=(1<<bit)
#define ClearBit(port, bit) port&=~(1<<bit)

const float timeOut_display = 0.5;
const uint8_t numData[] = { 0b11101110, 0b01000010, 0b11100101, 0b11100011, 0b01001011, 0b10101011, 0b10101111, 0b01100010, 0b11101111, 0b11101011, 0b00000000};
uint8_t dot_cond = 0, time_Hours = 9, time_Minutes = 0, temp;

ISR(TIMER1_OVF_vect)
{
	if(dot_cond) ClearBit(PORTB, 0); else SetBit(PORTB, 0);
	if(dot_cond)dot_cond = 0; else dot_cond = 1;
}
void shiftOut(uint8_t data);
void I2CInit(void)
{
	TWBR = 2; // Настройка частоты шины
	TWSR = (1 << TWPS1)|(1 << TWPS0); // Предделитель на 64
	TWCR |= (1 << TWEN); // Включение модуля TWI
}

void I2CStart(void)
{
	TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTA); // Передача условия СТАРТ
	while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT
}

void I2CStop(void)
{
	TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTO); // Передача условия СТОП
	while(TWCR & (1 << TWSTO)); // Ожидание завершения передачи условия СТОП
}

uint8_t I2CWriteByte(uint8_t data)
{
	TWDR = data; // Загрузка данных в TWDR
	TWCR = (1 << TWEN)|(1 << TWINT); // Сброс флага TWINT для начала передачи данных
	while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT
	// Проверка статуса
	// Если адрес DS1307+R и принято "подтверждение"(0x18)
	// или адрес DS1307+W и принято "подтверждение"(0x40)
	// или передается байт данных и принято "подтверждение"(0x28)
	if((TWSR & 0xF8) == 0x18 || (TWSR & 0xF8) == 0x40 || (TWSR & 0xF8) == 0x28) return 1; // OK
	else return 0; // ОШИБКА
}

uint8_t I2CReadByte(uint8_t *data,uint8_t ack)
{
	// Возвращаем "подтверждение" после приема
	if(ack) TWCR |= (1 << TWEA);
	// Возвращаем "неподтверждение" после приема
	// Ведомое устройство не получает больше данных
	// обычно используется для распознования последнего байта
	else TWCR &= ~(1 << TWEA);
	// Разрешение приема данных после сброса TWINT
	TWCR |= (1 << TWINT);
	while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT
	// Проверка статуса
	// Если принят байт данных и возвращается "подтверждение"(0x50)
	// или принят байт данных и возвращается "ненеподтверждение"(0x58)
	if((TWSR & 0xF8) == 0x50 || (TWSR & 0xF8) == 0x58)
	{
		*data = TWDR; // Читаем данные из TWDR
		return 1; // OK
	}
	else return 0; // ОШИБКА
}

uint8_t DS1307Read(uint8_t address,uint8_t *data)
{
	uint8_t res;
	I2CStart(); // СТАРТ
	res = I2CWriteByte(0b11010000); // адрес DS1307+W
	if(!res)    return 0; // ОШИБКА
	// Передача адреса необходимого регистра
	res = I2CWriteByte(address);
	if(!res)    return 0; // ОШИБКА
	I2CStart(); // Повторный СТАРТ
	res = I2CWriteByte(0b11010001); // адрес DS1307+R
	if(!res)    return 0; // ОШИБКА
	// Чтение данных с "неподтверждением"
	res = I2CReadByte(data,0);
	if(!res)    return 0; // ОШИБКА
	I2CStop(); // СТОП
	return 1; // OK
}

uint8_t DS1307Write(uint8_t address,uint8_t data)
{
	uint8_t res;
	I2CStart(); // СТАРТ
	res = I2CWriteByte(0b11010000); // адрес DS1307+W
	if(!res)    return 0; // ОШИБКА
	// Передача адреса необходимого регистра
	res = I2CWriteByte(address);
	if(!res)    return 0; // ОШИБКА
	res = I2CWriteByte(data); // Запись данных
	if(!res)    return 0; // ОШИБКА
	I2CStop(); // СТОП
	return 1; // OK
}

ISR(TIMER0_OVF_vect)
{
	DS1307Read(0x01,&temp); // Чтение регистра минут
	time_Minutes = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
	DS1307Read(0x02,&temp); // Чтение регистра часов
	time_Hours = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
}

int main(void)
{
	DDRB = 0b11000001;
	DDRC = 0b00111110;
	DDRD = 0b00000011;
	PORTB = 1;
	PORTC = 0b0000110;
	PORTD = 0b0000011;
	
	DS1307Read(0x00,&temp);
	temp &= ~(1 << 7); // обнуляем 7 бит
	DS1307Write(0x00,temp);
	
	TCCR0 = (1<<CS02);
	TIMSK = (1<<TOIE0);
	TCNT0 = 0xff;
	
	TCCR1B = (1<<CS12);
	TIMSK |= (1<<TOIE1);
	TCNT1L = 0xff;
	TCNT1H = 0xff;
	sei();
	
    while (1) 
    {
		shiftOut(numData[(time_Hours/10==0)?10:time_Hours/10]);
		ClearBit(PORTD, 1);
		_delay_ms(timeOut_display);
		SetBit(PORTD, 1);
		shiftOut(numData[time_Hours%10]);
		ClearBit(PORTD, 0);
		_delay_ms(timeOut_display);
		SetBit(PORTD, 0);
		shiftOut(numData[time_Minutes/10]);
		ClearBit(PORTC, 1);
		_delay_ms(timeOut_display);
		SetBit(PORTC, 1);
		shiftOut(numData[time_Minutes%10]);
		ClearBit(PORTC, 2);
		_delay_ms(timeOut_display);
		SetBit(PORTC, 2);
    }
}

void shiftOut(uint8_t data)
{
	for(uint8_t i = 0; i < 8; i++)
	{
		if(data & 0x80) SetBit(PORTB, 6); else ClearBit(PORTB, 6);
		SetBit(PORTC, 3);
		ClearBit(PORTC, 3);
		data <<= 1;
	}
	SetBit(PORTB, 7);
	ClearBit(PORTB, 7);
}