Не совсем так. Таймер у меня генерирует ШИМ с частотой 37,5 кГц (внутренний RC Тини13 9,6 МГц) и сбрасывать его нельзя. Одновременно таймер генерирует прерывания по ПЕРЕПОЛНЕНИЮ, т. е. каждые 26,67 мкс. Эти прерывания успользуются у меня как-то вроде клока - в процедуре обработки просто инкрементируется регистр-счетчик и если доходит до FF, то перестает инкрементироваться.
Сигнал от фотоприемника заведен на ногу PCINT3 и включены асинхронные прерывания PCINT и по маске выбрана эта нога, чтоб только с нее происходило прерывание. В этом прерывании регистр-счетчик проверяется и обнуляется - таким образом я измеряю длительность импульса от фотоприемника.
Поэтому прерывания от ноги и от таймера никак не связаны и запросто могут инициироваться одновременно. Другой вопрос, что значение регистра-счетчика +/- 1 не существенно - я проверяю отклонение импульса +/- 25% от номинальной длительности протокола RC5.
Alexeyslav писал(а):Но если два раза или более одно и то же прерывание возникнет во время обработки прерывания - оно будет обработано по окончанию только один раз
Во время обработки этого же прерывания? Т. е. при помехе во время штатного выполнения процедуры обработки прерывания по изменению уровня эта процедура повторится гарантированно 1 раз?
Если так, то при этом повторе прога вылетит на ошибку при анализе регистра-счетчика (он останется нулевым) и все будет нормально.
Если не так, то я должен хранить значение уровня при предыдущем прерывании и проверять - если читается то же, то что-то не так, а если противоположное - то все норм.
Собственно в этом вопрос - нужно ли добавлять эту проверку (т. е. усложнять код) или она излишняя?
ЗЫ: по идее, надо делать как вы описали, т. е. использовать захват, но таймер 1, а мне нужен ШИМ для ЦАПа. И к тому же, если не ошибаюсь, у Тини 13 нет захвата таймера. Можно взять Тини25, но я люблю максимальную простоту и дешевизну при максимальной функциональности. Не хватит памяти Тини13 - придется брать 25.
Димаn, конструкция вида "1 <<PD2" - тупо для препроцессора. Я обычно пишу что-то типа: 0b00000010 - нагляднее как-то. В вашем случае это единица, сдвинутая на константу PD2 (забыл, какое значение несет эта аббревиатура...). Причем это выражение вычисляется препроцессором при компиляции и в конечной проге бедет стоять как я написал двоичное число, а не набор команд.
***
Вот что вычитал в ДШ:
1) При возникновении прерываний флаг I регистра SREG аппаратно сбрасывается, запрещая тем самым обработку следующих прерываний. При возврате из подпрограммы обработки прерываний (команда RETI) флаг I устанавливается аппаратно.
2) Все имеющиеся прерывания можно разделить на два типа. Прерывания первого типа генерируются при наступлении некоторого события, в результате которого устанавливается флаг прерывания. При этом флаг прерывания аппаратно (или программно) сбрасывается.
Прерывания второго типа не имеют флагов прерываний и генерируются в течение всего времени, пока присутствуют условия, необходимые для этого. Соответственно, если условия, вызывающие прерывание, исчезнут до разрешения прерывания, генерации прерывания не произойдет.
3) Микроконтроллеры семейства Mega поддерживают очередь прерываний, которая работает следующим образом: если условия генерации одного или более прерываний возникают в то время, когда флаг общего разрешения прерываний сброшен, соответствующие флаги устанавливаются в «1» и остаются в этом состоянии до установки флага общего разрешения прерываний. После разрешения прерываний, выполняется их обработка в порядке приоритета.
4) После выхода из прерывания процессор всегда выполняет одну команду основной программы, прежде чем обслужить любое отложенное прерывание.
5) для индикации внешних прерываний используется регистр флагов прерываний GIFR (тини13/25).
Если в результате события на любом из выводов PCINT... формируется запрос на прерывание, этот бит устанавливается в 1. Флаг сбрасывается аппаратно при запуске подпрограммы обработки прерывания или программно, записью в него 1.
Получается, если у меня произошло прерывание PCINT по изменению на ноге, то у меня запускается процедура его обработки, сбрасывается флаг PCINT в GIFR и I в SREG. Если в процессе выполнения этой процедуры уровень на ноге опять меняется, то у меня устанавливается флаг PCINT, но поскольку флаг I сброшен, повторно обработчик не может быть вызван (п. 3). Когда процедура завершается, команда reti устанавливает флаг I. Проц выполняет одну команду из кода (п. 4) и повторно вызывает этот мой обработчик, т. к. флаг PCINT установлен и прерывание в очереди. Запустившись повторно, обработчик "думает", что это следующий фронт импульса, но проанализировав значение регистра-счетчика, которое к этому моменту будет равно 0, максимум 1, "понимает", что "импульс" слишком короткий и по этому условию вылетает на обработку ошибки (что мне и нужно).
Вроде ничего не напутал?
Выходит, анализировать предыдущее состояние не надо - любая помеха гарантированно вызовет повторное прерывание и вылет на ошибку.
Если рассмотреть взаимодействие внешнего прерывания и прерывания от таймера, то одно из них попадет в очередь и выполнится после завершения 1-го. Если во время обработки внешнего прерывания в очередной раз переполнится таймер, его прерывание произойдет только после завершения подпрограммы обработки внешнего прерывания и на ее работу не повлияет.
Если фотоприемник "дернет" ногу во время прерывания от таймера, то обработка этого события начнется после выхода из обработчика таймера, который всего-навсего получит значение регистра-счетчика на 1 больше, что не смертельно в данном случае (разброс на длительность импульса +/-25%, типовая ожидаемая ширина импульса - 33 единицы регистра-счетчика - 880 мкс) .
А вот что я не учитывал до настоящего времени - это то, что в прерывании надо сохранять в стек SREG

Возможно, в этом причина некоторых "странных и непонятных" глюков предыдущих моих устройств. Например, прерывание возникает в момент выполнения операции сравнения и не запомнив SREG, после выхода из прерывания я прос*у результат сравнения и уйду не на ту метку не по тому условию.