Принимая решение об опросе или прерывании, вы должны полностью понимать природу события, которому вы пытаетесь следовать, и свой ответ на него.
Прерывания не требуют обработки, когда ничего не происходит, но требуют всего вашего внимания, когда что-то происходит. Если событие является внешним и имеет шумные края или быстрые импульсы, то это может вызвать сильную головную боль с прерываниями, вам следует быть осторожным при настройке прерываний.
В этом примере подпрограмма прерывания реагирует на прояснение лазерного луча и настраивается на событие, когда он блокируется:
BEAM_INTR_EN = TRUE; /*re-enable the beam interrupts*/
/*Set the beam interrupt for the next clear to blocked event*/
BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/
У этого кода есть 2 слабых места:
1) Если лазерный луч снова заблокировался перед сбросом флага прерывания (BEAM_INTR_FLAG = FALSE;). Прерывание будет пропущено, и код будет не синхронизирован с состоянием лазерного луча.
2) При настройке прерываний либо в фоновой подпрограмме, либо для более высокого приоритета, чем приоритет, на котором установлен этот код, необходимо соблюдать осторожность при включении прерывания. Если флаг прерывания уже был установлен (неправильно) до его включения, процедура прерывания будет вызвана неправильно, как только она будет включена, и, возможно, для неправильного края.
Самый простой способ исправить 1) - дважды проверить после настройки прерывания, если оно произошло, форсировать прерывание. Для исправления 2) переместите включение прерываний после двойной проверки:
/*Set the beam interrupt for the next clear to blocked event*/
BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/
/*Double check beam state to see if it has already gone blocked*/
if (BEAM_STATE == BEAM_BLOCKED)
{
BEAM_INTR_FLAG = TRUE; /*Force the interrupt to re-enter the ISR after exiting*/
}
BEAM_INTR_EN = TRUE; /*re-enable the beam interrupts*/
Форсирование прерывания заставляет систему работать с одним и тем же конечным автоматом, просто принудительно его округляя вручную, чтобы закрыть слепое пятно.
В основном:
Set the edge to detect the next interrupt event
Clear the interrupt flag
if (the event has already occurred)
{
Set the interrupt flag to force the interrupt
}
Enable the interrupt
Если время отклика на событие должно быть согласованным (например, 1 мс +/- 10 мкс после того, как после того, как входная линия повысится, передайте сигнал события), то прерывания обычно являются лучшими.
Если время ответа на событие должно быть в пределах определенного времени (например, в пределах 1 мс от входной линии, идущей вверх, передать сигнал события), тогда прерывание будет наилучшим.
Проблема с прерываниями заключается в том, что вы должны начать думать о многопоточности, и что два фрагмента кода могут одновременно обращаться к одним и тем же данным.
Прерывания также хороши для того, чтобы процессоры могли переходить в режимы пониженного энергопотребления (спящий режим / режим ожидания и т. Д.), Ожидая, когда что-то произойдет.
С учетом всего того, что опрос может дать очень сжатые временные отклики на события, если для процессора есть только одна вещь, часто аппаратному обеспечению прерывания требуется несколько циклов, чтобы ответить на событие, в то время как тугой цикл опроса будет делать.
Если событие не является критичным по времени и потенциально шумным (например, кто-то нажимает на переключатель), тогда опрос позволяет простую фильтрацию, не пропуская долгосрочные переходы. Распространенной ошибкой является многократный опрос при настройке:
void fnInitialiseSystem(void)
{
if (MODE_INPUT == MODE_A) /*First polling of the MODE_INPUT*/
{
PR2 = PR2_MODE_A;
}
else
{
PR2 = PR2_MODE_B;
}
OpenTimer2( TIMER_INT_ON &
T2_PS_1_1 &
T2_POST_1_8 );
if (MODE_INPUT == MODE_A) /*Second polling of the MODE_INPUT*/
{
CurrentMode = MODE_A;
PROBE_INT_EDGE = CLEAR_TO_BLOCKED;
}
else
{
CurrentMode = MODE_B;
PROBE_INT_EDGE = BLOCKED_TO_CLEAR;
}
}
В приведенном выше примере MODE_INPUT является внешним переключателем, если два раза, когда MODE_INPUT опрашивается, отличаются, то поведение является неожиданным. При чтении сигналов такого типа лучше всего использовать фильтрацию для определения долгосрочного состояния входа и выполнять действия с отфильтрованной версией.
Например, при отключении переключателя просто проверяйте переключатель регулярно (каждые 1 мс?), И если количество из них (скажем, 16) отличается (переключатель закрыт) от отфильтрованной версии (переключатель открыт), обновите результат и выполните действие требуется. Будьте осторожны с наложением сигналов, колебательный сигнал может выглядеть стабильно!
Пример использования опроса и прерываний, опять же, для использования входа, который не часто меняется, но шумит при этом. Еще раз, коммутатор является хорошим примером этого: код может установить прерывание для проверки изменения состояния переключателя, когда происходит прерывание, тогда переключатель можно регулярно опрашивать до тех пор, пока состояние переключателя не станет «стабильным» (либо измененным, либо состояние или возврат к тому, что было). Это дает преимущество в виде низких издержек обработки, когда ничего не происходит, и фильтрации шума, когда что-то происходит.