Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Теряются данные от АЦП
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Andrew O. Shadoura
Hello all.

Необходимо по прерыванию от таймера #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);
  /* ... */
}


Запускаю измерения следующим образом:
Код
  count=0;
  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;
}


Но вообще хотелось бы узнать мнение сообщества по поводу причин столь странного поведения.

--
WBR, Andrew
aesok
Отключайте прерывания когда обращаетесь к переменным, которые могут измениться в обратотчиках прерываний.

Анатолий.
zhevak
Цитата(Andrew O. Shadoura @ Nov 2 2008, 17:29) *
Удалось получить статистику неверных измерений.
Здесь точка — нормальное измерение (значение>=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


Приходит мужик к врачу на прием.
-- Док, у меня все болит. Куда пальце не ткну, везде больно.
-- Батенька, дак у Вас палец сломан!

Andrew, у Вас пожоже какой-то периодический процесс живет. И действует как помеха. Попробуйте пределить, на что еще проц отвлекается. Мне сейчас не очень хочется углубляться в работу таймеров, но как предположение -- може первый таймер повторно перезапускает второй?

И я не совсем понял, зачем чем продиктова такой алгоритм работы:

Код
прерывание от первого таймера
  запускаем второй таймер

прерывание от второго таймера
  запускаем АЦП

прерывание от АЦП
  запускаем второй таймер

прерывание от второго таймера
  запускаем АЦП

прерывание от АЦП
  запускаем второй таймер

прерывание от второго таймера
  запускаем АЦП

прерывание от АЦП
  запускаем второй таймер

прерывание от второго таймера
  запускаем АЦП

прерывание от АЦП
  запускаем второй таймер



Возможно я ошибаюсь, но я бы предложил сделать так
Код
прерывание от первого таймера
  запускаем второй таймер

прерывание от второго таймера
  запускаем АЦП

прерывание от второго таймера
  запускаем АЦП

прерывание от второго таймера
  запускаем АЦП

прерывание от второго таймера
  запускаем АЦП


Тогда время четырех отсчетов не будет зависеть от времени преобразования АЦП.

Да, и еще, поскольку "на форуме электронщики, а не телепаты" (С) electronix.ru
пожалуйста, указывайте сразу больше данных по своим изделиям (тип МК, частота, компилятор, версия, питание... еще что-нибудь). Тогда легче будет помочь Вам.

ЗЫ
Отформатируйте свою сообщение. Разбейте
длиииииииииииииииииииииииииииииииииииииииииииииннющую строку на несколько, например, как у меня.
Andrew O. Shadoura
Цитата(aesok @ Nov 2 2008, 14:50) *
Отключайте прерывания когда обращаетесь к переменным, которые могут измениться в обратотчиках прерываний.


Не совсем понимаю, о каких именно переменных идёт речь. Обращение к count повлиять на результат наврядки может, а к captured я обращаюсь тогда уже, когда прерывание запрещено его же обработчиком.

Цитата(zhevak) *
Andrew, у Вас пожоже какой-то периодический процесс живет. И действует как помеха. Попробуйте пределить, на что еще проц отвлекается.


Что у меня ещё есть — так это таймер 0, который срабатывает довольно редко, всё, что он делает — устанавливает флажок в 1. Кроме того, обработчик UART, но через UART ничего в данном случае не шло.

Цитата
И я не совсем понял, зачем чем продиктова такой алгоритм работы


Измеряемый сигнал может быть довольно коротким, более того, он зависит от ШИМа, выдаваемого как раз таймером 1, соответственно, четыре измерения за раз не сделаешь:

0а. ШИМовский выход выставляется в 1
0б. Срабатывает прерывание от таймера 1, но на входе АЦП ещё ничего нет, соответственно, необходима задержка, реализуемая на таймере 2
1. Срабатывает прерывание от таймера 2, обработчик запускает АЦП (на осциллограмме это видно как тонкий импульс 1->0->1)
2. Когда АЦП что-то намерял, забираем результат и ждём дальше.

Цитата
Тогда время четырех отсчетов не будет зависеть от времени преобразования АЦП.


К сожалению так сделать, скорее всего не получится — для этого надо будет как-то засинхронизировать таймеры 1 и 2, чтобы второе, третье и т.д. прерывания от таймера 2 происходили с периодом таймера 1.

Цитата
пожалуйста, указывайте сразу больше данных по своим изделиям (тип МК, частота, компилятор, версия, питание... еще что-нибудь).


У меня ATmega16 на 16МГц, но здесь эти данные не особо важны. Компилятор, очевидно, avr-gcc (hi, aesok!).

--
WBR, Andrew
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.