Страница 1 из 1

Повторное прерывание INT2 при глобальном разрешении

Добавлено: Вт июн 14, 2016 07:58:11
Nikopol
Доброго времени суток.
Столкнулся со следующей проблемой.
Есть МК AtMega128 на нем настроены ряд прерываний:
- 2 по таймерам
- внешнее по нарастающему фронту на INT2

На вход INT2 подан сигнал с детектора ноля сетевого напряжения. В обработчике внешнего прерывания управляю временем открытия клапана на основе пропуска полупериодов (клапан на 220 В).
В основном цикле программы выполняю считывание температуры с датчиков DS18B20. Использую библиотеку для датчиков температуры http://chipenable.ru/index.php/componen ... 18b20.html
алгоритм опроса прост - считываю текущее значение температуры, запускаю новое преобразование на всех датчиках, через 1 секунду повторяем. Время отсчитывает таймер и кладет указатель на функцию опроса датчиков в кольцевой буфер, откуда в основном цикле производиться ее вызов, такой себе мини диспетчер задач. Библиотека по опросу датчиков работает на основе задержек и в момент формирования таймслотов глобально запрещает все прерывания, а затем разрешает их.
Собственно проблема в том, что при опросе датчиков (или просто глобальном запрете, а затем разрешении прерываний) происходят ложные срабатывания по внешнему прерыванию. Т.е. в данный момент, для проверки, я в обработчике INT2 просто инвертирую выход. Подключив осциллограф одним каналом на выход детектора, а второй на выход МК, который я инвертирую наблюдаю следующее:
- в случает отсутствий манипуляций с запретом/ разрешение глобально прерываний, фронты четко совпадают и смена состояния выхода четко соответствует переднему фронту сигнала с детектора
- в случае опроса датчика возникает дополнительные вызовы обработчика прерывания в следствии чего за один период выхода с детектора получаю 5 и более дополнительных смен состояний выхода Мк.

Вопрос из-за чего может возникать повторно прерывание и как этот эффект побороть, потому как в следствии этого я не корректно считаю периоды, а следовательно клапан фактически открыт меньше.

Инициализация прерывания

Код: Выделить всё

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: On
// INT2 Mode: Rising Edge
// INT3: Off
// INT4: Off
// INT5: Off
// INT6: Off
// INT7: Off
EICRA=0x30;
EICRB=0x00;
EIMSK=0x04;
EIFR=0x04;
А вот так производиться отправка бита на 1-wire

Код: Выделить всё

#define __save_interrupt() SREG
#define __restore_interrupt(var) SREG = (var)
#define __disable_interrupt() #asm("cli")
#define __enable_interrupt() #asm("sei")
#define __delay_cycles(var) delay_us((unsigned int)(var)/(_MCU_CLOCK_FREQUENCY_/1000000))

void OWI_WriteBit1(unsigned char pins)
{
    unsigned char intState;
    
    // Disable interrupts.
    intState = __save_interrupt();
    __disable_interrupt();
    
    // Drive bus low and delay.
    OWI_PULL_BUS_LOW(pins);
    __delay_cycles(OWI_DELAY_A_STD_MODE);
    
    // Release bus and delay.
    OWI_RELEASE_BUS(pins);
    __delay_cycles(OWI_DELAY_B_STD_MODE);
    
    // Restore interrupts.
    __restore_interrupt(intState);
}

Re: Повторное прерывание INT2 при глобальном разрешении

Добавлено: Вт июн 14, 2016 09:25:14
Nikopol
Вот в результате гугления наткнулся на http://www.gaw.ru/html.cgi/txt/doc/micr ... h128/8.htm Там описано:
СпойлерВнешние прерывания 3 - 0 активизируются через внешние выводы INT3:0, если установлены флаг I в регистре статуса SREG и соответствующая маска прерывания в EIMSK. Выбор уровня или фронта для активизации внешнего прерывания осуществляется в соответствии с таблицей 48. Фронты на INT3..INT0 выявляются асинхронно. Прерывание по выв. INT3:0 будет сгенерировано, если длительность импульса будет больше минимально необходимой (см. табл. 49). При возникновении импульсов меньшей длительности генерация прерывания не гарантируется. Если выбрано прерывание по низкому уровню, то для генерации прерывания необходимо, чтобы этот уровень оставался на прежнем низком уровне до момента завершения выполнения текущей инструкции. После разрешения прерывания по уровню оно будет генерироваться непрерывно до тех пор, пока на входе присутствует низкий уровень. При изменении бит ISCn может возникнуть прерывание. Поэтому, рекомендуется вначале отключить прерывание INTn путем сброса бита разрешения прерывания в регистре EIMSK. После этого, значение бит ISCn может быть изменено. И, наконец, перед возобновлением работы прерываний необходимо сбросить флаг прерывания INTn путем записи лог. 1 во флаг прерывания (INTFn) в регистре EIFR.
Я вот думаю, не тут ли собака порылась. Вечерком попробую проверить..

Re: Повторное прерывание INT2 при глобальном разрешении

Добавлено: Вт июн 14, 2016 14:58:21
BOB51
Если флаг не сбрасывается аппаратно при вызове прерывания, то надо его принудительно сбросить.
Однако с разрешением вложенного прерывания надо еще внимательно за остальными разрешенными следить - дабы не разрешить побочно перекрытие более "высокоприоритетным" и того, что было ранее вызвано (в итоге окажется совсем "несвоевременным").
8)
Хоша под СИ... может компилятор ту вероятную "замесь" самостоятельно отслеживает?
:dont_know:

Re: Повторное прерывание INT2 при глобальном разрешении

Добавлено: Вт июн 14, 2016 15:10:38
ARV
BOB51 писал(а):Хоша под СИ... может компилятор ту вероятную "замесь" самостоятельно отслеживает?
нет.
компилятор отслеживает только синтаксис

Re: Повторное прерывание INT2 при глобальном разрешении

Добавлено: Вт июн 14, 2016 20:19:24
BOB51
Тогда печалька...
:(

Re: Повторное прерывание INT2 при глобальном разрешении

Добавлено: Чт июн 16, 2016 15:02:07
Demiurg
ТС, как успехи?

Re: Повторное прерывание INT2 при глобальном разрешении

Добавлено: Вт июн 21, 2016 08:19:21
Nikopol
Сорри за молчание.
В данный момент вроде как победил траблы, весь косяк в опросе датчика DS18B20. Подробнее вот тут http://forum.easyelectronics.ru/viewtop ... 8&start=25
Просто так сложилось, что там начали быстрее реагировать, но все равно спасибо за советы.