Описание регистров я приводить не буду, их достаточно в интернете, да и без лишней нужды в них лезть не приходиться в большинстве случаев. А вот то что нужно знать - это формула которая определяет частоту работы TWI - всеми известен I2C.
TWBR - задает коэффициент деления частоты генератора скорости связи. TWPS - Биты 0:1 предделителя TWI
Несложными движениями выражаем TWBR, он то нам и нужен. Получилось следующее -
TWBR = ( (CPU_F/SCL_F) - 16) / (2*4^TWPS);
Если поставить значение TWPS -00, сокращаем формулу до -
TWBR = ( (CPU_F/SCL_F) - 16) / (2*1) - не должен быть 0 или больше 255!
Теперь дело за малым, зная как работает twi и покурив даташит был написан сл.код -
#define CPU_F 4000000UL // 4МГц
#define SCL_F 100000UL // 100кГц, 400кГц - максимум для twi
// Значение пропуска, проверить что бы не совпадало с возможными данными
// Иначе изменить на неиспользуемое число
#define Skip_Flag 0xff
// Адрес устройства в формате 7бит(без бита RW)
#define Dev_Adr 0x00
//Инициализация twi
void twi_Init(void)
{
TWBR = ( ( (CPU_F)/(SCL_F)-16 ) /2 ) ;
TWSR = 0; //Очищаются биты TWPS0 и TWPS1
}
// Запись по twi, reg_adr - адрес регистра, data - значение, если не нужно пишем Skip_Flag
void twi_write(unsigned char reg_adr, unsigned char data)
{
// Сброс флага прерывания TWINT, установка Старта, установка разрешения работы twi
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
// Ждем пока будет свободна линия, если занята
while(!(TWCR & (1<<TWINT)));
// Передаем адрес с флагом записи 0
TWDR = (Dev_Adr<<1) | 0;
// Говорим, что мы хотим передать данные
TWCR = (1<<TWINT)|(1<<TWEN);
// Ждем окончания передачи данных
while(!(TWCR & (1<<TWINT)));
// Передаем адрес регистра
TWDR = reg_adr;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// Тут два пути, или нам просто нужно было установить адрес регистра и считать с него, тогда пропускаем ф-ю
// Либо устанавливаем значение в регистр
if (data != Skip_Flag )
{ // /Пишем значение
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
}
// Устанавливаем условие завершения передачи данных (СТОП)
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
// Чтение
unsigned char twi_read(void)
{
unsigned char data;
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// Передаем адрес с флагом чтения 1
TWDR = (Dev_Adr<<1) | 1;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
// Очистка флага прерывания TWINT
TWCR = (1<<TWINT)|(1<<TWEN);
// Ждем окончания приема..
while(!(TWCR & (1<<TWINT)));
// Считываем байт данных
data = TWDR;
// Стоп
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
// Возвращаем принятые данные
return data;
}
В коде реализация выглядит так
twi_Init();
twi_write(0x00, Skip_Flag); // 0x00 - обычно под этим адресом какой-то DevID, Skip_Flag - ничего не записываем, только чтение по этому адресу
data = twi_read(); // Принимаем ID