Создаем I2C библиотеку для микроконтроллера Atmega8

Для включения шины I2C, нам необходим регистр TWCR:
TWINT — бит прерываний. Устанавливается в 1, когда  задание на шине завершится и будет ожидаться реакция программы.  Сбрасывается в 0программно.
TWEA — бит разрешающий подтверждение. При установке 0 система не будем просить подтверждение от ведомого устройства.
TWSTA — бит  генерирования условия «Старт».
TWSTO — бит  генерирования условия «Стоп».
TWWC — бит ошибочной записи. Устанавливается в 1, при попытки записи в адресный буфер, когда флаг TWINT ещё не установился. Сбрасывается сам, когда ошибка уходит.
TWEN — бит, активации шины I2C. 
TWIE — бит,разрешающий прерывание.
 
Так же нам нужен будет еще регистр TWSR:
TWPS1 и TWPS0 — два биты для делителя частоты шины.
Остальные пять битов регистра содержат код статуса операции, которая выполнялась.
Регистр TWBR отвечает за скорость передачи данных.
 
Расчет значения выполняется по формуле:
TWBR = ((F_cpu/F_scl) — 16)/(2*4^TWPS)
где:
F_cpu — рабочая частота микроконтроллера.
F_scl — необходимая рабочая частота шины
TWPS — значение данного регистра, выбирается из таблицы:
Считанные данные и данные которые мы передаем помещаются в регистр TWDR.

Ножки в микроконтроллере Atmega8 для шины I2C:

 PC5 -сигнал SCL

 PC4 -сигнал SDA

текст программы:
Заголовочный файл.

#ifndef I2C_H_
#define I2C_H_
#include <avr/io.h>

void I2C_init(void);// инициализация
void I2C_Start(void);//Старт
void I2C_Stop(void);//Стоп
void I2C_SendByte(unsigned char c);//отправка данных
void I2C_SendByteAdres(unsigned char c, unsigned char addr );// отправка данных по адресу
unsigned char I2C_ReadByte(void);// чтение байта
unsigned char I2C_ReadLastByte(void);// чтение последнего байта

#endif /* I2C_H_ */

Рабочий файл.

#include «I2C.h»
void I2C_init(void){
TWSR=(0<<TWPS1)|(0<<TWPS0);// настройка делителя
TWBR=0x03; // настройка рабочей частоты шины
}

void I2C_Start(void){
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR&(1<<TWINT))){;}
}

void I2C_Stop(void){
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void I2C_SendByte(unsigned char c){
TWDR=c;
TWCR=(1<<TWINT)|(1<<TWEN);
while (!(TWCR&(1<<TWINT))){;}
}

void I2C_SendByteAdres(unsigned char c, unsigned char addr )
{
I2C_Start();
I2C_SendByte(addr);
I2C_SendByte(c);
I2C_Stop();
}

unsigned char I2C_ReadByte(void){
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR&(1<<TWINT))){;}
return TWDR;
}

unsigned char I2C_ReadLastByte(void){
TWCR=(1<<TWINT)|(1<<TWEN);
while (!(TWCR&(1<<TWINT))){;}
return TWDR;
}