Я пишу прерывание микроконтроллера, которому необходимо добавить смещение к одному из его аппаратных таймеров. Однако из-за того, что работает предварительный делитель таймера, наивный подход может вводить ошибку «за-один» в зависимости от времени выполнения прерывания относительно часов предварительного делителя.Как я могу избежать этой ошибки за один раз при добавлении смещения к предварительно установленному аппаратным таймером?
Я использую таймер 1 на ATmega328P (= Arduino) для этого. Я настроил его в обычном режиме с предварительным делителем/8, и я использую прерывание захвата таймера, чтобы вызвать это; целью прерывания является установка таймера для переполнения точно period
циклов после события, которое запускает захват ввода (в случае возникновения триггера во время другого прерывания или в другой ситуации, в которой прерывания отключены).
(Я злоупотребляю выходом PWM для запуска двух оптоволоконных сетей с переменным смещением фазы переменного тока, без необходимости записывать на него все время процессора, прерывание запускается детектором пересечения нуля на фазе сети).
код для ISR будет что-то вроде этого:
uint_16 period = 16667;
ISR(TIMER1_CAPT_vect){
TCNT1 = TCNT1 - ICR1 - period + (elapsed counter ticks during execution);
}
критический интервал здесь является один между моментом, когда TCNT1
читается и, когда он записывается снова.
Насколько я знаю, нет способа напрямую прочитать состояние предделителя, поэтому я не думаю, что можно просто применить другое смещение, основанное на синхронизации ISR.
Я мог бы просто сбросить предварительный делитель до ISR (GTCCR |= _BV(TSM); GTCCR |= _BV(PSRSYNC); GTCCR &= ~_BV(TSM);
), чтобы синхронизировать, но это все еще вводит случайное смещение на таймер, зависящее от времени ISR.
Другой подход, который я рассматриваю, заключается в использовании таймера для генерации прерывания, синхронизированного с предделителем. Я уже использую оба регистра сравнения вывода на таймере 1, но таймер 0 делится предделителем, чтобы его можно было использовать. Однако выполнение прерывания таймера может быть отложено другим прерыванием или блоком cli, поэтому это не гарантируется.
Как я могу написать свое прерывание, чтобы избежать этой ошибки?
Я предполагаю, что вычисление 'TCNT1' не _always_ отключено одним (время 2?), Просто _sometimes_ (время 1)? – chux
@chux да, 'TCNT1' только иногда отключается одним. Я не совсем уверен, как объяснить это словами, но временная диаграмма, которую я включил, показывает, как это происходит. – AJMansfield
Является ли процедура ISR достаточно быстрой, чтобы пробовать и, конечно, обнаруживать импульс 'clk_Tn'? Может ли 'clk_Tn' установить флаг, который может быть очищен ISR? – chux