Необходимо по прерыванию от таймера #1 запускать через 40µs АЦП, данные накапливать, причём процедура эта должна проводиться 4 раза, результат усредняться.
Столкнулся с тем, что иногда выпадают значения. При это последовательность усреднённых результатов выглядит так: 675, 675, 675, 675, 506, 675, 675…
Очевидно, что одно из четырёх измерений возвращает 0. Подцепился осциллографом к PB4, обнаружил, что /иногда/ длительность измерения равна 44µs против 68µs.
Код
ISR(TIMER1_COMPA_vect)
{
TCNT2 = -80;
TCCR2 = _BV(CS21);
PORTB |= _BV(4);
TIFR |= _BV(TOV2);
TIMSK |= _BV(TOIE2);
}
ISR(TIMER2_OVF_vect)
{
TIMSK &= ~(_BV(TOIE2));
set_bit(ADCSRA, ADSC);
ADCSRA |= _BV(ADIE)/*|_BV(ADIF)*/;
PORTB ^= _BV(4);
PORTB ^= _BV(4);
TCCR2 = 0;
}
ISR(ADC_vect)
{
captured+=ADCW;
PORTB &= ~(_BV(4));
ADCSRA &= ~(_BV(ADIE));
(count==3)?(TIMSK &= (~(_BV(OCIE1A)))):0;
count++;
}
static void ioinit(void)
{
/* ... */
ADMUX=0;
ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|7;
/* ... */
set_sleep_mode(SLEEP_MODE_IDLE);
/* ... */
}
{
TCNT2 = -80;
TCCR2 = _BV(CS21);
PORTB |= _BV(4);
TIFR |= _BV(TOV2);
TIMSK |= _BV(TOIE2);
}
ISR(TIMER2_OVF_vect)
{
TIMSK &= ~(_BV(TOIE2));
set_bit(ADCSRA, ADSC);
ADCSRA |= _BV(ADIE)/*|_BV(ADIF)*/;
PORTB ^= _BV(4);
PORTB ^= _BV(4);
TCCR2 = 0;
}
ISR(ADC_vect)
{
captured+=ADCW;
PORTB &= ~(_BV(4));
ADCSRA &= ~(_BV(ADIE));
(count==3)?(TIMSK &= (~(_BV(OCIE1A)))):0;
count++;
}
static void ioinit(void)
{
/* ... */
ADMUX=0;
ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADIF)|7;
/* ... */
set_sleep_mode(SLEEP_MODE_IDLE);
/* ... */
}
Запускаю измерения следующим образом:
Код
count=0;
captured=0;
TIFR |= _BV(OCF1A);
TIMSK |= (_BV(OCIE1A));
while(count<4)
{
sleep_mode();
};
captured>>=2;
captured=0;
TIFR |= _BV(OCF1A);
TIMSK |= (_BV(OCIE1A));
while(count<4)
{
sleep_mode();
};
captured>>=2;
Ниже: жёлтый — сигнал с PB4, голубой — измеряемый сигнал.
Нажмите для просмотра прикрепленного файлаНажмите для просмотра прикрепленного файла — обычное измерение.
Нажмите для просмотра прикрепленного файла — "неправильное"
Больше в программе ниоткуда обращения к АЦП не происходят, всё "крутится" исключительно здесь.
Куда копать?
В крайнем случае, посоветуйте, как правильнее всего отбрасывать эти "промахи"?
Заранее спасибо.
UPDATE #1:
Удалось получить статистику неверных измерений.
Здесь точка — нормальное измерение (значение>=10), 1:2 — измерение, вернувшее 1 при count==2.
Код
................................................1:2 ................................................2:3 ...............................................0:3 ................................................1:0 ................................................1:1 ...............................................1:1 ................................................1:2 ................................................1:3 ...............................................1:3 ................................................1:0 ................................................0:1 ...............................................0:1 ................................................1:2 ................................................1:3 ...............................................1:3 ................................................1:0 ................................................0:1 ...............................................0:1 ................................................1:2 ................................................1:3 ...............................................1:3 ................................................1:0 ................................................0:1 ................................................1:2 ................................................1:3 ................................................0:0 ................................................1:1 ................................................1:2 ................................................1:3 ................................................1:0 ................................................1:1 ...............................................3:1
UPDATE #2:
Временно решил проблему следующим способом:
Код
register volatile int8_t last0 asm("r7");
ISR(ADC_vect)
{
register uint16_t now=ADCW;
register uint8_t now0 = (now < 4);
PORTB &= ~(_BV(4));
ADCSRA &= ~(_BV(ADIE));
if (!now0 || last0)
{
captured += now;
(count==3)?(TIMSK &= (~(_BV(OCIE1A)))):0;
count++;
}
last0 = now0;
}
ISR(ADC_vect)
{
register uint16_t now=ADCW;
register uint8_t now0 = (now < 4);
PORTB &= ~(_BV(4));
ADCSRA &= ~(_BV(ADIE));
if (!now0 || last0)
{
captured += now;
(count==3)?(TIMSK &= (~(_BV(OCIE1A)))):0;
count++;
}
last0 = now0;
}
Но вообще хотелось бы узнать мнение сообщества по поводу причин столь странного поведения.
--
WBR, Andrew