Прерывание - это уникальное средство. Его надо понять. И понять правильно.
Прерывание вызывается из любого места основной проги. В начале прерывания (средствами компилятора) осуществляется сохранение состояния процессора, а по завершению прерывания восстановление состояния. Таким образом основная программа "как бы не замечает" работы прерывания и может быть написана как логически завершённая задача (и это правильный подход). С другой стороны прерывание - тоже является логически законченой процедурой. Так сказать фоновым процессом. Если у вас несколько прерываний - то получается несколько фоновых задач. Возможно также построение, когда в голове имеется несколько независимых задач, а в прерывании осуществляется переключение между ними. Тогда говорят об ОС. Из этого видно, что само прерывание в той или иной степени "как бы распаралеливает задачи на несколько". Это надо понять. И найболее правильным подходом является общение между этими независимыми программами через данные. Тогда ваши задачи будут максимально независимы, а значит их будет легко отлаживать и они приобретут прозрачность построения.
Ну например. Фоновая задача в прерывании по таймеру читает значение АЦП и ложит их в соответствующие глобальные переменные. После того,как данные обновлены она выставляет флаг завершения измерения. Голова ждёт флага завершения измерения и обрабатывает данные из глобальных переменных после чего сбрасывает флаг. Если через пол года вы измените измерение каналов АЦП на измерение частотных датчиков, к примеру, то вам необходимо будет только переписать прерывание. (Это как пример)
Теперь надо понимать ещё один момент. Во время когда работает прерывание (берём общий случай и берём AVR для простоты картины) останавливается работа головы, а также задерживаются остальные прерывания. Это, естественно, не есть хорошо. К примеру если за время работы прерывания по UART придут 3 символа, то один будет потерян. Более того, если вы вызываете прерывание от таймера скажем каждые 100 мкс, а обработка этого прерывания будет занимать более 100 мкс, то очевидно, что часть прерываний будет потеряна. Короче, из этого проистекает, что прерывания должны быть максимально короткими. Этого добиваются разными способами. Например вам надо читать 6 каналов АЦП. Найболее частым решением будет следующее:
1) За одно прерывание читаем только 1 канал.
2) Процедура следующая: читаем канал - переключаем канал на следующий - выходим.
Прога будет выглядеть примерно так. (Это конечно от балды выдумано)
Код
#pragma vector=TIMER1_OVF_vect
__interrupt static void pvPWMEnd(void)
{
// Перезапуск таймера на той же частоте
TCNT1=-KPWM; // Период следования 16МГц/3200 = 5кГц
Adc[TekChan++]=ADCH; // Прочитать значение АЦП
if(TekChan==MAXADC)
{
TekChan=0; // начать сначала
Flag.fADCConv=1; // Результат измерений получен
}
ADMUX=KADMUX | TekChan; // Выбрать канал
ADCSRA =KADCSRA; // Начать отсчёт заново
}
Ой простите. На асме - так
Код
Tim0_Ovf:
push wl
in wl,sreg
push wl
push Xl
push Xh
ldi wl, -KPWM
out TCNT0,wl
ldi Xl, low(MemAdc)
ldi Xh, high(MemAdc)
add Xl, TekChan
ldi wl, 0
adc Xh, wl
in wl, ADCH
st X, wl
inc TekChan
ldi wl, MAXADC
cp TekChan, wl
brne Tim0_Ovf_0
clr TekChan
sbr Flag, exp2(fADCConv)
Tim0_Ovf_0:
ldi wl, KADMUX
or wl, TekChan
out ADMUX,wl
ldi wl, KADCSRA
out ADCSRA, wl
pop Xh
pop Xl
pop wl
out sreg,wl
pop wl
reti
Простите делал на скорую руку. Прямо тут. Естественно не самым оптимальным образом. Всё зависит от проекта. От распределения памяти и свободных регистров. Всё это естественно можно ужать.