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

 
 
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
_Pasha
сообщение Dec 8 2013, 11:52
Сообщение #16


;
******

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



Цитата(AndreyVN @ Dec 8 2013, 12:17) *
Нет, volatile не использую.


Ну вот и ответ на вопрос.
Go to the top of the page
 
+Quote Post
WHALE
сообщение Dec 8 2013, 19:26
Сообщение #17


Знающий
****

Группа: Свой
Сообщений: 902
Регистрация: 2-01-06
Из: Краснодар
Пользователь №: 12 768



Цитата(_Pasha @ Dec 8 2013, 15:52) *
Ну вот и ответ на вопрос.

ТС так и не указал используемый компилятор.Но судя по приведенным кускам кода-это CV.
А он не такой резкий в оптимизации как тот-же ЯР и не выкидывает без предупреждения
не- volatile переменные в прерываниях.Кажется,квалификатра volatile там и вовсе нет...
Но я бы не заметал непонятки под ковер, а постарался-бы все-таки разобраться до конца,
бо неизветно,не всплывут-ли они потом при модификации кода.


--------------------
"Hello, word!" - 17 errors 56 warnings
Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Dec 9 2013, 04:25
Сообщение #18


Знающий
****

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



Цитата(WHALE @ Dec 8 2013, 23:26) *
ТС так и не указал используемый компилятор.Но судя по приведенным кускам кода-это CV.
А он не такой резкий в оптимизации как тот-же ЯР и не выкидывает без предупреждения
не- volatile переменные в прерываниях.Кажется,квалификатра volatile там и вовсе нет...
Но я бы не заметал непонятки под ковер, а постарался-бы все-таки разобраться до конца,
бо неизветно,не всплывут-ли они потом при модификации кода.


Да, действительно, Code Vision (версию сейчас не назову), на модификатор volatile CV ошибки не выдает, но, возможно, никаких действий не предпринимает.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Dec 9 2013, 05:51
Сообщение #19


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(_Pasha @ Dec 8 2013, 15:52) *
Ну вот и ответ на вопрос.
+1


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 9 2013, 14:38
Сообщение #20


Гуру
******

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



Цитата(WHALE @ Dec 8 2013, 21:26) *
А он не такой резкий в оптимизации как тот-же ЯР и не выкидывает без предупреждения не- volatile переменные в прерываниях.
А никто не говорил, что переменная выкидывается в прерывании. И ИАР не выкидывает. Выкидывается ее чтение в основном цикле. И выкидывается совершенно законно, и предупреждать никто не обязан - иначе вы получали бы ворох предупреждений на каждую строчку кода.

Цитата(AndreyVN @ Dec 9 2013, 06:25) *
Да, действительно, Code Vision (версию сейчас не назову), на модификатор volatile CV ошибки не выдает,
Было бы удивительно, если бы он ругался на описанное в стандарте языка ключевое слово.
Цитата(AndreyVN @ Dec 9 2013, 06:25) *
но, возможно, никаких действий не предпринимает.
Полагаю, что вы ошибаетесь. Иначе практически все программы под этим компилятором вели бы себя так же непредсказуемо, как ваша.

Даже несмотря на то, что CV - компилятор "языка, похожего на C", вам обязательно стоит потратить лишние несколько минут чтобы разобраться, что дает ключевое слово volatile и когда его просто необходимо применять. Во избежание в дальнейшем траты кучи времени на "глюки компилятора".


--------------------
На любой вопрос даю любой ответ
"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

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

 


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


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