Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08 ,далее в регистр данных посылаю адрес , но в этом месте все зависает в прерывании ... что не так? Контроллер ATMEGA 328 AVRStudio 7. все по даташиту дела.
void i2c_transmit(void) // функция передачи инициирует условие старта далее все должно происходить в прерывани.
{
TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTA)|(1<<TWIE);
}
вектор прерывания
ISR (TWI_vect) // прерывание по i2c
{
switch((TWSR & 0xF8))
{
case 8: // если старт прошел зависает на этом кейсе
{
TWDR = i2c_SlaveAddress; // в дата регистр пишем адрес подчиненного (он уже сдвинут на 1 в лево!)
TWCR = 1<<TWINT|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE; // команда напередачу
break;
}
case 0x18: // если аск от ведомого получен
{
TWDR=200; // передаем например 200
TWCR = (1<<TWINT)|(1<<TWEN);
}
}
vdv22 писал(а):TWCR = 1<<TWINT|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE; // команда напередачу
какой разный стиль... а вот я бы везде ставил скобки, потому что, к стыду своему, приоритетность плохо помню.
а зачем при команде на передачу ещё раз включать и интерфейс, и прерывание, это действительно по даташиту так у атмелов?
Добавлено after 4 minutes 49 seconds:
а, TWCR-у всё заново присваивается... ну. так некрасиво. Это портит логику работы.
[uquote="vdv22",url="/forum/viewtopic.php?p=4274288#p4274288"]Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08[/uquote]
Я в Си не понимаю, но вот что бросилось в глаза... пишете что ловите 0х08 а в коде пишете 0хF8...
switch((TWSR & 0xF8))
а ведь нужно проверять после команды старт именно 0x08 а не 0хF8
Последний раз редактировалось VNS Ср авг 17, 2022 11:46:29, всего редактировалось 1 раз.
если перед выходом из прерывания добавить TWCR = (1<<TWINT); то зависания нет ,но адрес упороно не передается (по осциллнографу и лог анализатору.
SR (TWI_vect) // прерывание по i2c
{
switch((TWSR & 0xF8))
{
case 8: // если старт прошел
{ out=(TWSR & 0xF8);
TWDR = i2c_SlaveAddress; // в дата регистр пишем адрес подчиненного (он уже сдвинут на 1 в лево!)
TWCR = (1<<TWINT)|(0<<TWSTA)|(0<<TWSTO)|(1<<TWEN); // команда напередачу
break;
}
case 0x18: // если аск от ведомого получен
{
TWDR=200; // передаем например 200
TWCR = (1<<TWINT)|(1<<TWEN);
}
}
TWCR = (1<<TWINT); // если добавить сброс флага ,то зависания нет ,но адрес упороно не передается (по осциллнографу и лог анализатору.)
}
Добавлено after 1 minute 6 seconds:
[uquote="VNS",url="/forum/viewtopic.php?p=4274309#p4274309"][uquote="vdv22",url="/forum/viewtopic.php?p=4274288#p4274288"]Здравствуйте, хочу написать функцию на прерываниях для i2c. Формирую условие старта . в прерываниях ловлю код 0х08[/uquote]
Я в Си не понимаю, но вот что бросилось в глаза... пишете что ловите 0х08 а в коде пишете 0хF8...
switch((TWSR & 0xF8))
[/uquote]
F8 это маска . она накладывается на регистр и смотрим какое число получилось
И, заметьте, после каждого обработанного флага, соответствующий флаг сбрасывается (в регистре IFC). А вы сбрасывая глобальный флаг, возможно оставдяете, что-то необработанным.
Обработчик всех флагов будет, но мне сейчас дадо чтоб он хоть адрес отправит - я в свиче обычно делаю default чтоб другое не нужное отсечь. Сейчас в прерывание он заходит только один раз (отслеживаю через uart ) то есть после получения 0x08.
Добавлено after 1 minute 45 seconds:
[uquote="veso74",url="/forum/viewtopic.php?p=4274319#p4274319"]Ждете, пока шина будет готова, проверьте код состояния для отправленного условия запуска:
Было бы хорошо обработать все возможные состояния.[/uquote]
то что вы предлогаете это блокирующий режим -он у меня прекрасно работает . Но я не хочу в цикле жать -мне нужен режим с прерываниями.
Вариант:
--------------------------
ISR(TWI_vect){
static unsigned char state = 0, lastVal = 0;
// Disable Global Interrupt
cli();
switch(TW_STATUS){
case TW_START: // 0x08
case TW_REP_START: // 0x10
case TW_MT_SLA_ACK: // 0x18
case TW_MT_SLA_NACK: // 0x20
case TW_MT_DATA_ACK: // 0x28
case TW_MT_DATA_NACK: // 0x30
case TW_MR_SLA_ACK: // 0x40
case TW_MR_SLA_NACK: // 0x48
case TW_MR_DATA_ACK: // 0x50
case TW_MR_DATA_NACK: // 0x58
case TW_ST_ARB_LOST_SLA_ACK: // 0xB0
case TW_SR_ARB_LOST_SLA_ACK: // 0x68
case TW_SR_GCALL_ACK: //0x70
case TW_SR_ARB_LOST_GCALL_ACK: // 0x78
case TW_SR_GCALL_DATA_ACK: // 0x90
case TW_SR_GCALL_DATA_NACK: // 0x98
case TW_NO_INFO: // 0xF8
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_SR_SLA_ACK: // 0x60: SLA+W received, ACK returned
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_SR_DATA_ACK: // data received
state = TWDR;
if(lastVal == 'S'){
targetTemp = state;
state = 0;
}
lastVal = state;
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_SR_STOP: // 0xA0: stop or repeated start condition received while selected
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_ST_SLA_ACK: // 0xA8: SLA+R received, ACK returned
if(state == 'T'){
TWDR = temperature; // Fill TWDR register whith the data to be sent
}else if(state == 'H'){
TWDR = humidity;
}else{
TWDR = -1;
}
TWCR = ((1 << TWEA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE)); // Enable TWI, Clear TWI interrupt flag
break;
case TW_ST_DATA_ACK: // 0xB8: data transmitted, ACK received
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_ST_DATA_NACK: // 0xC0: data transmitted, NACK received
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
case TW_ST_LAST_DATA: // 0xC8: last data byte transmitted, ACK received
case TW_BUS_ERROR: // 0x00: illegal start or stop condition
default:
TWCR |= (1<<TWINT); // Clear TWINT Flag
break;
}
sei();
}