Прошу помощи в реализации интерфейса I2C на Attiny85 в режиме ведомого.
Проблема в следующем:
При срабатывании прерывания по переполнению счетчика, в регистре данных USIDR оказывается полученный байт сдвинутый влево.
Код тестировал в Proteus. На скриншотах показана ячейка памяти 2F, которой соответствует регистр USIDR.
На первом скриншоте отправляется 0x00, в USIDR оказывается 0x01; на втором скриншоте отправляется 0x01, в USIDR - 0x03.
Думал проблема в симуляции, но нет. Тестировал в железе - то же самое.
Заранее благодарю!
Код:
Код:
// Инициализация I2C интерфейса
void i2c_init()
{
// Настройка интерфейса USI на режим TWI
USICR |= (1<<USIWM0);
USICR |= (1<<USIWM1);
// Настройка интерфейса на источник тактирования
USICR &= ~(1<<USICLK);
USICR &= ~(1<<USICS0);
USICR |= (1<<USICS1);
// Выставление пинов интерфейса на вход
// SDA
DDRB &= ~(1<<0);
PORTB &= ~(1<<0);
// SCL
DDRB &= ~(1<<2);
PORTB &= ~(1<<2);
// Включение прерывания по старту и очистка флага прерывания
USICR |= (1<<USISIE);
USISR |= (1<<USISIF);
}
// Прерывание по старту
ISR(USI_START_vect){
while( (PINB & (1 << PIN_SCL)) && (!(PINB & (1 << PIN_SDA))) );
// Очистка регистра статуса
USISR |= (1<<USISIF);
// Включение прерывания по переполнению
USICR |= (1<<USIOIE);
}
// Прерывание по переполнению счетчика
ISR(USI_OVF_vect){
uint8_t i2c_byte = USIDR;
*pwm_0 = 0;
if (i2c_byte>=1){
*pwm_0 = 250;
}
if (i2c_byte==1){
*pwm_0 = 100;
}
USISR |= (1<<USIOIF); // Сброс флага прерывания по переполнению
USISR = 0; // Сброс счетчика
}
Добавлено after 5 hours 27 minutes 30 seconds:Еще заметил, что после отправки байта, регистр 2E находится в значении 0100 0010, что соответствует значению счетчика 2 и выставленному флагу срабатывания прерывания по переполнению. Такое ощущение, что в регистр USIDR попадает бит NACK, который по сути и не должен генерироваться, т.к. USIWM выставлены в 11, что значит что после срабатывания прерывания по переполнению линия SCL притягивается к нулю и в счетчик и регистр USIDR ничего писаться не должно...