реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Опрос АЦП внутри прерывания
AndreyVN
сообщение Dec 7 2013, 06:41
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Всем привет!
Перенес код опроса АЦП (ATmega16) внутрь обработчика прерываний от таймера, АЦП напрочь перестал работать, оба байта стабильно 00, 00.
Есть какие-то подводные камни при запуске однократного преобразования АЦП в теле обработчика прерывания? (Сам факт вызова процедуры обработчика прерывания вижу на осциллографе.)

Этим кодом пользовался много раз:
Код

//АЦП доступен, прерывания разрешены
//ADCSRA: 7-ADEEN 6-ADSC 5-ADATE 4-ADIF 3-ADIE 2-ADPS2 1-ADPS2 0-ADPS0
//           1      0       0      0      0      1       1       1
ADCSRA = 0x87;
...
ADCSRA |= 0x40; //Начать одиночное преобразование АЦП
while( (ADCSRA & 0x40)==0x40 ); //ждем завершения преобразования ADSC (13-14 тактов)
c1 = ADCL; //Читаем результат преобразования сначала младший
c2 = ADCH; //затем старший (иначе не работает!)
VADC = c1 + c2*256;
Go to the top of the page
 
+Quote Post
Abell
сообщение Dec 7 2013, 08:03
Сообщение #2


профессиональный дилетант
****

Группа: Участник
Сообщений: 866
Регистрация: 16-03-06
Из: Шебекино - Лысьва - Тюмень
Пользователь №: 15 292



А Вы не обрабатывайте АЦП в прерывании, Вы обрабатывайте его в главном цикле, так-то оно правильней будет... за 13-14 тактов многое может произойти, да так, что и выйти корректно из прерывания может не получиться, или выйти не туда laughing.gif


--------------------
Скоро дело сказывается, да не скоро сказка делается, или тише будешь - дальше уедешь...

Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 7 2013, 09:12
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Цитата(Abell @ Dec 7 2013, 11:03) *
А Вы не обрабатывайте АЦП в прерывании, Вы обрабатывайте его в главном цикле, так-то оно правильней будет... за 13-14 тактов многое может произойти, да так, что и выйти корректно из прерывания может не получиться, или выйти не туда laughing.gif

Ну так оно и было, все работало. Мне нужно обеспечить гарантированное время в петле регулирования. Все что связано с регулированием (измерение и вычисление управляющего воздействия) засунул в прерывание от таймера, а интерфейсную часть (опрос клавиатуры и вывод на LCD) оставил в основном цикле. И... неожиданно обломался. Уже пару дней перечитываю даташит - ну не вижу я ни одной причины по которой нельзя опросить АЦП внутри обработчика прерывания!
Времена на стадии отладки сделал огромные (21 mS), при входе в прерывание выставляю на пин "1" на осциллографе вижу, что прерывание случилось, при выходе из прерывания сбрасываю пин в "0", то есть, все работает, но не измеряет. Опора как была так и есть. В общем, фигня какая-то. cranky.gif Клавиатура работает, LCD тоже, то есть структура программы не рушится, если случаются вложенные прерывания, они отрабатывают корректно.
Go to the top of the page
 
+Quote Post
stells
сообщение Dec 7 2013, 09:30
Сообщение #4


внештатный сотрудник
******

Группа: Участник
Сообщений: 2 458
Регистрация: 10-05-08
Из: МО, Медвежьи озера
Пользователь №: 37 401



я сталкивался с неправильной обработкой АЦП в подпрограмме обработки прерывания от таймера даже при непрерывном преобразовании... почему - так и не понял, перенес обработку АЦП в основной цикл
Go to the top of the page
 
+Quote Post
Abell
сообщение Dec 7 2013, 09:41
Сообщение #5


профессиональный дилетант
****

Группа: Участник
Сообщений: 866
Регистрация: 16-03-06
Из: Шебекино - Лысьва - Тюмень
Пользователь №: 15 292



Цитата(AndreyVN @ Dec 7 2013, 13:12) *
Ну так оно и было, все работало.

Ну пусть дальше и работает sm.gif А, случайно, прерывания АЦП запретили? Регистр состояния не меняется в процессе обработки? Может, проще в основном цикле запускать преобразование, а по прерыванию АЦП брать результат и синхронизировать с таймером?


--------------------
Скоро дело сказывается, да не скоро сказка делается, или тише будешь - дальше уедешь...

Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 7 2013, 10:02
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Цитата(Abell @ Dec 7 2013, 12:41) *
Ну пусть дальше и работает sm.gif А, случайно, прерывания АЦП запретили? Регистр состояния не меняется в процессе обработки? Может, проще в основном цикле запускать преобразование, а по прерыванию АЦП брать результат и синхронизировать с таймером?


Да, сам АЦП прерывания не генерит, ADIE=0. Так все красиво в программном коде разложилось, не хочется перелопачивать. Попробую посмотреть на ассемблере, что там компилятор сотворил.

Цитата
я сталкивался с неправильной обработкой АЦП в подпрограмме обработки прерывания от таймера

А у Вас тоже 00 00 было или просто точность измерений упала?
Go to the top of the page
 
+Quote Post
stells
сообщение Dec 7 2013, 10:19
Сообщение #7


внештатный сотрудник
******

Группа: Участник
Сообщений: 2 458
Регистрация: 10-05-08
Из: МО, Медвежьи озера
Пользователь №: 37 401



Цитата(AndreyVN @ Dec 7 2013, 14:02) *
А у Вас тоже 00 00 было или просто точность измерений упала?

нули были... причем при изменении входного сигнала (а он у меня медленно меняющийся во времени) или касании пальцем входных цепей АЦП начинал работать правильно
Go to the top of the page
 
+Quote Post
Xenia
сообщение Dec 7 2013, 17:15
Сообщение #8


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(AndreyVN @ Dec 7 2013, 13:12) *
Мне нужно обеспечить гарантированное время в петле регулирования. Все что связано с регулированием (измерение и вычисление управляющего воздействия) засунул в прерывание от таймера, а интерфейсную часть (опрос клавиатуры и вывод на LCD) оставил в основном цикле. И... неожиданно обломался. Уже пару дней перечитываю даташит - ну не вижу я ни одной причины по которой нельзя опросить АЦП внутри обработчика прерывания!


А вы старт АЦП делайте из прерывания, а ожидание и прием данных в основном цикле. Тогда и синхронизация будет отличная и ждать долго не придется (т.к. пока выйдет из прерывания и в основном цикле до опроса дело дойдет, глядишь, преобразование само закончится без дополнительного ожидания).

Для этого лишь надо кроме старта еще самодельный флаг выставить, что с АЦП данные надо востребовать, а в основном цикле его проверяете, и если стоит, то ждете готовности и опрашиваете.

P.S. Сама делала так: таймер запускала на удвоенную частоту опроса, в четных перерываниях от таймера делала старт АЦП, а в нечетных его опрашивала без ожидания.
Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 7 2013, 18:59
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Цитата(Xenia @ Dec 7 2013, 20:15) *
А вы старт АЦП делайте из прерывания, а ожидание и прием данных в основном цикле. Тогда и синхронизация будет отличная и ждать долго не придется (т.к. пока выйдет из прерывания и в основном цикле до опроса дело дойдет, глядишь, преобразование само закончится без дополнительного ожидания).


Идея понятная. Нечто подобное я делал, нашел в в своих-же разработках: Запуск АЦП по переполнению таймера
Код
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
ADCSRA |= 0x40; //Начать одиночное преобразование АЦП
}

Ловим результат в обработчике прерываний от АЦП (естественно, прерывания от АЦП разрешены ADIE=1)
Код
interrupt[ADC_INT] void ADC(void)
{
unsigned char c1,c2;
c1 = ADCL; //Читаем результат преобразования сначала младший
c2 = ADCH; //затем старший (иначе не работает!)
VADC = c1 + c2*256;
}

Сейчас работать не хочет, видимо, причина где-то в другом месте.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Dec 7 2013, 19:17
Сообщение #10


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Мега8 недалеко ушла от 16-й, все работало и работает, АЦП опрашивается, 3962.5 Гц, тоже цикл регулирования. Смотрите листинг
Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 7 2013, 19:36
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Цитата(_Pasha @ Dec 7 2013, 22:17) *
Мега8 недалеко ушла от 16-й, все работало и работает, АЦП опрашивается, 3962.5 Гц, тоже цикл регулирования. Смотрите листинг


А Иде смотреть-то?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 8 2013, 00:31
Сообщение #12


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(AndreyVN @ Dec 7 2013, 08:41) *
оба байта стабильно 00, 00.
А где вы их проверяете? В этом же прерывании или в основном цикле? Если в основном цикле, то как объявлена переменная VADC?

Цитата(AndreyVN @ Dec 7 2013, 08:41) *
Код
while( (ADCSRA & 0x40)==0x40 ); //ждем завершения преобразования ADSC (13-14 тактов)
Вы только не забывайте, что это 13-14 тактов частоты АЦП, в вашем случае это 13...14 * 128 = 1664 или 1792 тактов ядра. Вы хорошо подумали, прежде чем засунуть такое ожидание в обработчик прерывания?

Цитата(AndreyVN @ Dec 7 2013, 08:41) *
Код
c1 = ADCL; //Читаем результат преобразования сначала младший
c2 = ADCH; //затем старший (иначе не работает!)
VADC = c1 + c2*256;
Ой. Делайте VADC = ADC; и не морочьте себе голову. Любой компилятор для AVR знает, в каком порядке надо читать двухбайтные регистры.

Цитата(AndreyVN @ Dec 7 2013, 21:36) *
А Иде смотреть-то?
В своем листинге. Внимательно смотреть, что сгенерил компилятор и думать - где вы могли неправильно объяснить ему свою задумку.

Чудес не бывает.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 8 2013, 06:22
Сообщение #13


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Цитата
А где вы их проверяете? В этом же прерывании или в основном цикле? Если в основном цикле, то как объявлена переменная VADC?


Я контролирую не VADC, а непосредственно с1, с2, чтобы свести к минимуму возможные причины ошибок в т.ч. присвоения, преобразования типов и т.п..
VADC тоже выводится на экран после мат. обработки, но это сейчас не интересно.
Вывод на LCD и в основном цикле пробовал и прямо в обработчике пробовал. Переменные тоже пробовал объявлять глобальными и локальными, ситуация не меняется.

Цитата
Вы только не забывайте, что это 13-14 тактов частоты АЦП, в вашем случае это 13...14 * 128 = 1664 или 1792 тактов ядра. Вы хорошо подумали, прежде чем засунуть такое ожидание в обработчик прерывания?

Общего быстродействия хватает, тем более, что сейчас ловлю готовность АЦП в прерывании (см. выше).

Цитата
Ой. Делайте VADC = ADC; и не морочьте себе голову. Любой компилятор для AVR знает, в каком порядке надо читать двухбайтные регистры.

Когда код заработает так и сделаю, а сейчас, предпочитаю видеть каждый байт как он есть.

Цитата
В своем листинге. Внимательно смотреть, что сгенерил компилятор и думать - где вы могли неправильно объяснить ему свою задумку.
Чудес не бывает.

Ой, Спасибо! Однако, Вы не сказали, удавалось лично Вам опрашивать АЦП в обработчике прерываний таймера?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 8 2013, 08:57
Сообщение #14


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(AndreyVN @ Dec 8 2013, 08:22) *
Вывод на LCD и в основном цикле пробовал и прямо в обработчике пробовал. Переменные тоже пробовал объявлять глобальными и локальными, ситуация не меняется.
Покажите объявление этих переменных. Хорошо, без намеков: используете ли вы в объявлении ключевое слово volatile?
Цитата(AndreyVN @ Dec 8 2013, 08:22) *
Ой, Спасибо! Однако, Вы не сказали, удавалось лично Вам опрашивать АЦП в обработчике прерываний таймера?
Мне удается опрашивать его где угодно. Еще раз повторю: чудес не бывает. В документации опрашивать АЦП в прерывании таймера не запрещено.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 8 2013, 09:17
Сообщение #15


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Цитата(Сергей Борщ @ Dec 8 2013, 11:57) *
Покажите объявление этих переменных. Хорошо, без намеков: используете ли вы в объявлении ключевое слово volatile?
Мне удается опрашивать его где угодно. Еще раз повторю: чудес не бывает. В документации опрашивать АЦП в прерывании таймера не запрещено.

Нет, volatile не использую. Раньше пользовался, когда менял C'шные переменные из кода ассемблерных вставок, но так и не знаю, зачем это надо компилятору. Собственно, проблема решилась, заработала конструкция:

Код
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
ADCSRA |= 0x40; //Начать одиночное преобразование АЦП  
PORTA.4 = ~PINA.4; //Для осциллографа
}

interrupt[ADC_INT] void ADC(void)
{
unsigned char c1,c2;
#asm("sei"); //Разрешить вложенные прерывания (управляющие H-мостом)
PORTA.4 = ~PINA.4; //Для осциллографа
c1 = ADCL; //Читаем результат преобразования сначала младший
c2 = ADCH; //затем старший (иначе не работает!)
V2 = (c1 + c2*256)*4.97*Ku/1024;
PORTA.4 = ~PINA.4; //Для осциллографа
}


Отключил 90% кода не связанного с обслуживанием АЦП, измерение ожило, затем стал возвращать процедуру за процедурой, специально проверил, работоспособность прерываний которые случаются во время interrupt[ADC_INT] (это разрешено командой SEI) - все работает, переменные c1, c2 хранятся в регистрах, но успешно сохраняются и восстанавливаются через стек. К сожалению, так и не понял, что было. Сейчас вернул почти весь код на место, все работает, возвращаться к обработке АЦП "внутри таймера" уже нет смысла.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 16:32
Рейтинг@Mail.ru


Страница сгенерированна за 0.01521 секунд с 7
ELECTRONIX ©2004-2016