/*
* LM75_Tempsensor.c
* Temperaturmessung (5x pro Sekunde) und Ausgabe der Temperatur als Binärwert am PORTD
* Eine negative Temperatur wird zusätzlich durch eine LED an PB0 angezeigt
* CPU: ATmega88
* FCPU: 8MHz
* I²C CLK Frequency = 100kHz, CLK = 8000000/(16 + 2*(0x50)*1)
*/
#include <avr/io.h>
#include <util/delay.h>

/*** Statusregister codes and other defines ***/
#define START			0x08	// A START condition has been transmitted
#define R_START			0x10	// A REPEATED START condition has been transmitted
#define SLA_W			0x90	// Slave Address & Write 1001 0000
#define SLA_R			0x91	// Slave Address & Read 1001 0001
#define MT_SLA_ACK		0x18	// Master Transmit SLA+W has been transmitted & ACK has been received
#define MR_SLA_ACK		0x40	// Master Receive SLA + R has been transmitted & ACK has been received
#define MT_DATA_ACK		0x28	// Master Transmit Data byte has been transmitted & ACK has been received
#define MR_DATA_NACK	0x58	// Master Receive Data byte has been transmitted & NACK has been returned
#define BIT_RATE		0x50	// Set value for the bit rate register TWBR
#define POINTER_ADDRESS 0x00	// LM75 pointer address for temperature register
void ERROR(void);				// Prototyping of function "ERROR"

/*** Function to send a START Condition ***/
void TWI_START(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	// Wait for TWINT Flag set. This indicates that the START condition has been transmitted
	while (!(TWCR & (1<<TWINT)));
	// Check value of TWI statusregister. Mask prescaler bits. If status different from START go to ERROR if ((TWSR & 0xF8) != START)
	ERROR();
}

/*** Function to send the Slave Address with ACK in Master Transmit Mode ***/
void TWI_MT_SLA_ACK(void)
{
	// Load SLA_W into TWDR Register
	TWDR = SLA_W;
	// Clear TWINT bit in TWCR to start transmission of address
	TWCR = (1<<TWINT) | (1<<TWEN);
	// Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received.
	while (!(TWCR & (1<<TWINT)));
	// Check value of TWI status register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR
	if ((TWSR & 0xF8) != MT_SLA_ACK)
	ERROR();
}

/*** Function to send 8Bit of data with ACK in Master Transmit Mode **/
void TWI_MT_DATA_ACK(void)
{
	// Load DATA into TWDR register
	TWDR = POINTER_ADDRESS;
	// Clear TWINT bit in TWCR to start transmission of data
	TWCR = (1<<TWINT) | (1<<TWEN);
	// Wait for TWINT flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received.
	while (!(TWCR & (1<<TWINT)));
	// Check value of TWI status register. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR
	if ((TWSR & 0xF8) != MT_DATA_ACK)
	ERROR();
}

/*** Function to send a REPEATED START condition **/
void TWI_R_START(void)
{
	// Send a START condition
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	// Wait for TWINT Flag set. This indicates that the START condition has been transmitted
	while (!(TWCR & (1<<TWINT)));
	// Check value of TWI statusregister. Mask prescaler bits. If status different from R_START go to ER-ROR
	if ((TWSR & 0xF8) != R_START)
	ERROR();
}

/*** Function to send the Slave Address in Master Receive Mode with Acknowledge **/
void TWI_MR_SLA_ACK(void)
{
	// Load SLA_R into TWDR Register
	TWDR = SLA_R;
	// Clear TWINT bit in TWCR to start transmission of address
	TWCR = (1<<TWINT) | (1<<TWEN);
	// Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received.
	while (!(TWCR & (1<<TWINT)));
	// Check value of TWI status register. Mask prescaler bits. If status different from MR_SLA_ACK go to ERROR
	if ((TWSR & 0xF8) != MR_SLA_ACK)
	ERROR();
}

/*** Function to read one Databyte in Master Receive Mode with NACK ***/
uint8_t TWI_READ_DATABYTE_NACK(void)
{
	// Read one data byte
	TWCR = (1<<TWINT)| (1<<TWEN);
	// Wait for TWINT flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received.
	while (!(TWCR & (1<<TWINT)));
	// Check value of TWI status register. Mask prescaler bits. If status different from MR_DATA_NACK go to ERROR
	if ((TWSR & 0xF8) != MR_DATA_NACK)
	ERROR();
	return TWDR; // Return the value of data register
}

/*** function to send a STOP condition ***/
void TWI_STOP(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // Transmit STOP condition
}

/*** function to show a bus error ***/
void ERROR(void)
{
	PORTB |= (1<<PB1); // ERROR LED ON
}

uint8_t LSByte, MSByte;
uint16_t data_16bit, temperature, high_byte, low_byte;

int main(void)
{
	DDRD = 0xFF;		// PORTD = output
	DDRC = 0x3F;		// PC0 ... PC5 = output
	DDRB = 0x03;		// PB0 and PB1 = output
	TWBR = BIT_RATE;	// Set the TWI clock-frequency in bit rate register
	while(1)
	{
		TWI_START();						// Send START condition
		TWI_MT_SLA_ACK();					// Master Transmit Slave Address with ACK
		TWI_MT_DATA_ACK();					// Master Transmit Data with ACK
		TWI_R_START();						// Send REPEATED START condition
		TWI_MR_SLA_ACK();					// Send the Slave Address in Master Receive Mode with ACK
		MSByte = TWI_READ_DATABYTE_NACK();	// Read one Databyte without ACK
		LSByte = TWI_READ_DATABYTE_NACK();	// Read one Databyte without ACK
		TWI_STOP();							// Send STOP condition
		low_byte = LSByte >> 5;				// Shift LSByte 5 digits right
		high_byte = MSByte << 8;			// Shift MSByte 8 digits left
		data_16bit = high_byte + low_byte;	// Store 16bit-result of temp-register in data
		temperature = data_16bit >> 8;		// Shift data 8 digits right to get a 8bit value
		
		if (MSByte & 0x80)					// if bit7 = 1 --> negative Temperature
		{
			MSByte = ~MSByte + 1;			// build 2´s complement
			temperature = MSByte >> 3;		// divide by 8
			PORTD = temperature;			// Show negative temperature on PORTD
			PORTB |= (1<<PB0);				// LED for negative Temperature ON
		}
		
		else								// if bit7 = 0 --> positive Temperature
		{
			PORTB &= ~(1<<PB0);				// LED for negative Temperature OFF
			PORTD = temperature;			// Show positive temperature on PORTD
		}
		_delay_ms(200);						// wait 200ms for new readout
	}
}