# define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#define I2C_SDA         PB3
#define I2C_SCL         PB4
#define TEMP            PB0

#define OLED_ADDR       0x78
#define OLED_CMD_MODE   0x00
#define OLED_DAT_MODE   0x40
#define OLED_INIT_LEN   17

#define I2C_SDA_HIGH()  DDRB &= ~(1<<I2C_SDA)
#define I2C_SDA_LOW()   DDRB |=  (1<<I2C_SDA)
#define I2C_SCL_HIGH()  DDRB &= ~(1<<I2C_SCL)
#define I2C_SCL_LOW()   DDRB |=  (1<<I2C_SCL)

const uint8_t OLED_INIT_CMD[] PROGMEM = 
{
	0xA8, 0x1F,
	0x81, 0x0F,			// Яркость дисплея (0x7F - max)
	0x22, 0x00,
	0x03, 0x20,
	0x01, 0xDA,
	0x02, 0x8D,
	0x14, 0xAF,			// Включить дисплей
	0x00, 0x10,
	0xB0, 0xA1,
	0xC8
};

const uint8_t OLED_FONT[] PROGMEM = 
{
	0x7F, 0x41, 0x7F, // 0  0
	0x00, 0x00, 0x7F, // 1  1
	0x79, 0x49, 0x4F, // 2  2
	0x41, 0x49, 0x7F, // 3  3
	0x0F, 0x08, 0x7E, // 4  4
	0x4F, 0x49, 0x79, // 5  5
	0x7F, 0x49, 0x79, // 6  6
	0x03, 0x01, 0x7F, // 7  7
	0x7F, 0x49, 0x7F, // 8  8
	0x4F, 0x49, 0x7F, // 9  9
	0x7F, 0x09, 0x7F, // A 10
	0x7F, 0x48, 0x78, // b 11
	0x7F, 0x41, 0x63, // C 12
	0x78, 0x48, 0x7F, // d 13
	0x7F, 0x49, 0x41, // E 14
	0x7F, 0x09, 0x01, // F 15
	0x00, 0x60, 0x00, // . 16
	0x00, 0x36, 0x00, // : 17
	0x08, 0x08, 0x08, // - 18
	0x00, 0x00, 0x00  //   19
};

void I2C_write(uint8_t data)
{
	for(uint8_t i = 8; i; i--)
	{
		I2C_SDA_LOW();
		if (data & 0x80)
		I2C_SDA_HIGH();
		I2C_SCL_HIGH();
		data<<=1;
		I2C_SCL_LOW();
	}
	I2C_SDA_HIGH();
	I2C_SCL_HIGH();
	asm("nop");
	I2C_SCL_LOW();
}

void I2C_start(uint8_t addr)
{
	I2C_SDA_LOW();
	I2C_SCL_LOW();
	I2C_write(addr);
}

void I2C_stop(void)
{
	I2C_SDA_LOW();
	I2C_SCL_HIGH();
	I2C_SDA_HIGH();
}
	
void OLED_cursor(uint8_t xpos, uint8_t ypos)
{
	I2C_start(OLED_ADDR);
	I2C_write(OLED_CMD_MODE);
	I2C_write(xpos & 0x0F);
	I2C_write(0x10 | (xpos >> 4));
	I2C_write(0xB0 | (ypos & 0x07));
	I2C_stop();
}
	
void OLED_clear(void) 
{
	OLED_cursor(0, 0);
	I2C_start(OLED_ADDR);
	I2C_write(OLED_DAT_MODE);
	for(uint16_t i=512; i; i--) I2C_write(0x00);
	I2C_stop();
}

void I2C_init(void)
{
	DDRB  &= ~((1<<I2C_SDA)|(1<<I2C_SCL));
	PORTB &= ~((1<<I2C_SDA)|(1<<I2C_SCL));
}
	
void OLED_init(void) 
{
	I2C_init();
	I2C_start(OLED_ADDR);
	I2C_write(OLED_CMD_MODE);
	for (uint8_t i = 0; i < OLED_INIT_LEN; i++) I2C_write(pgm_read_byte(&OLED_INIT_CMD[i]));
	I2C_stop();
}
	
uint8_t OLED_stretch(uint8_t b)
{
	b=((b & 2)<<3)|(b&1);
	b|=b<<1;b|=b<<2;
	return b;
}
	
void OLED_printD(uint8_t ch) 
{
	uint8_t i, j, k, b;
	uint8_t sb[4];
	ch += ch << 1;
	for(i=8; i; i--) I2C_write(0x00);
	for(i=3; i; i--) 
	{
	b = pgm_read_byte(&OLED_FONT[ch++]);
	for(j=0; j<4; j++, b >>= 2) sb[j] = OLED_stretch(b);
	j=4; if(i==2) j=6;
	while(j--) 
		{
			for(k=0; k<4; k++) I2C_write(sb[k]);
		}
	}
}
			
void OLED_printB(uint8_t *buffer) 
{
	I2C_start(OLED_ADDR);
	I2C_write(OLED_DAT_MODE);
	for(uint8_t i=0; i<8; i++) OLED_printD(buffer[i]);
	I2C_stop();
}
			
uint8_t therm_reset()
{
	uint8_t i;
	PORTB &= ~(1 << TEMP);
	DDRB |= (1 << TEMP);
	_delay_us(480);
	DDRB &= ~(1 << TEMP);
	_delay_us(60);
	i=((PINB >> TEMP) & 1);
	_delay_us(420);
	return i;
}

void therm_write_bit(uint8_t bit)
{
	DDRB |= (1 << TEMP);
	if(bit) DDRB &= ~(1 << TEMP);
	_delay_us(60);
	DDRB &= ~(1 << TEMP);
}

uint8_t therm_read_bit(void)
{
	uint8_t bit=0;
	DDRB |= (1 << TEMP);
	DDRB &= ~(1 << TEMP);
	_delay_us(14);
	if(PINB & (1 << TEMP)) bit=1;
	_delay_us(45);
	return bit;
}

uint8_t therm_read_byte(void)
{
	uint8_t i=8, n=0;
	while(i--)
	{
		n>>=1;
		n|=(therm_read_bit()<<7);
	}
	return n;
}

void therm_write_byte(uint8_t byte)
{
	uint8_t i=8;
	while(i--)
	{
		therm_write_bit(byte&1);byte >>= 1;
	}
}

int read_temp()
{
	uint8_t temperature[2];
	int temper;
	therm_reset();
	therm_write_byte(0xCC);
	therm_write_byte(0x44);
	while(!therm_read_bit());
	therm_reset();
	therm_write_byte(0xCC);
	therm_write_byte(0xBE);
	temperature[0]=therm_read_byte();
	temperature[1]=therm_read_byte();
	therm_reset();
	return temper = (temperature[1] << 8 | temperature[0])*10/16;
}

int main(void)
{
	OLED_init();
	OLED_clear();
	
	while(1)
	{
	int temp = read_temp();
	uint8_t a0 = temp/100;
	uint8_t a1 = temp/10%10;
	uint8_t a2 = temp%10;
	uint8_t buffer[8] = {19, a0, a1, 16, a2, 19, 12, 19};
	OLED_printB(buffer);
	_delay_ms(100);
	}
}