|
|
  |
Вопрос по АЦП, Free running mode |
|
|
|
Jan 14 2008, 22:53
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
При работе с АЦП делаю заранее заданное демпфирование по каналам. То есть порядок выборки каналов у меня постоянно скачет. Это поменять нельзя. АЦП запущено в "Free running mode" и проверяется по таймеру. Время с момента переключения канала и до выборки значения АЦП вдвое превышает означенные 25 тактов (пробовал и увеличивать). По каким-то, для меня непонятным причинам, иногда (достаточно редко) с АЦП в память попадает не текущее значение АЦП (точнее не то, что должно быть), а с предыдущего канала. Причём если я в данной точке останавливаюсь по JTAG, то в АЦП микросхемы вижу правильное значение. Например: Код 127 default: 128 x0=Adc[TekChan].X1=ADCH; // Прочитать значение АЦП \ ??pvPWWLvl1_7: \ 000000B8 91300079 LDS R19, 121 \ ??pvPWWLvl1_9: \ 000000BC 8334 STD Z+4, R19 \ 000000BE 2E23 MOV R2, R19 То есть по databreakpoint останавливаюсь в последней строчке и вижу в АЦП значение FF к примеру, а в ячейку уже занесено 83. Каналы и всё прочее выставляется верно. Создаётся впечатление, что АЦП не успевает завершить операцию. Но, как я уже писал, при увеличении времени в разы сама ошибка остаётся. Может я чего не знаю. Может необходимо как то обновить значение. Типа прочитать два раза или что-то ещё. Я в непонятках.
|
|
|
|
|
Jan 15 2008, 08:38
|

Просто Che
    
Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881

|
Может быть там присутствуют наложения циклов АЦП и таймера из-за несинхронности процесса. Момент переключения каналов иногда попадает на такт АЦП, когда каналы переключать нельзя. Но я "Free running mode" никогда не применял, поэтому это только догадки. В datasheet этот момент описан как-то обтекаемо и я до конца его смысл не понимаю  Там в явном виде не написано, что допускается переключать канал в любое время. А почему вы применили "Free running mode"? Я всегда применяю одиночные преобразования по таймеру и никогда таких проблем не имел. Для гарантии окончания переходных процессов после переключения каналов можно просто проводить АЦП через раз: перекл.канал / вкл.АЦП / прочитали результат, перекл.канал / вкл.АЦП / прочитали результат, перекл.канал / и т.д.
|
|
|
|
|
Jan 15 2008, 08:58
|

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

|
Я тоже склоняюсь к мысли, что это биения от несовпадения частоты преобразования и частоты чтения/смены канала. Цитата(SasaVitebsk @ Jan 15 2008, 00:53)  АЦП запущено в "Free running mode" и проверяется по таймеру. Т.е. вы его читаете в прерывании таймера и иногда меняете канал? В описании сказано примерно так, что если преобразование уже началось, то смена канала подействует только при следующем преобразовании. Это не ваш случай? Если я правильно понял раздел ADC Input Channels, то в вашем случае сделал бы так: сбросил ADIF, вычитал ADCH, проверил бы ADIF, если он снова стоит - повторил бы сброс и чтение, записал в ADMUX новый канал, дождался ADIF, отбросил бы этот результат (он скорее всего от предыдущего канала), ждал следующего ADIF. Но я тоже не использовал его в режиме FreeRunning. Цитата(GDI @ Jan 15 2008, 10:52)  это даже гдето в даташитах написано... Где конкретно? Покажите мне это место в даташите.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 15 2008, 10:48
|

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

|
Цитата(GDI @ Jan 15 2008, 12:04)  "ну его ф топку этот фри ран..."  Вот и я при чтении даташита пришел к тому же выводу - в режиме FreeRunning, если канал переключается не в прерывании АЦП первое измерение после переключения канала может относится как к старому, так и к новому каналу, поэтому его нужно отбросить. Это логически вытекает из описания и понятно. Но именно в режиме FreeRunning, если канал переключается не в прерывании АЦП, а не просто "При переключении мультиплексора". Поэтому я и уточнил - может есть еще какие-то тонкости.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 15 2008, 12:04
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(Сергей Борщ @ Jan 15 2008, 11:58)  Где конкретно? Покажите мне это место в даташите. Рекомендация о пропуске первого результата при смене канала во Free Running Mode действительно где-то была (то ли в даташитах, то ли в аппнотах). Цитата Вот и я при чтении даташита пришел к тому же выводу - в режиме FreeRunning, если канал переключается не в прерывании АЦП первое измерение после переключения канала может относится как к старому, так и к новому каналу, поэтому его нужно отбросить. Не совсем так. С точки зрения АЦП измерение по-любому будет относиться к старому каналу, а переключение на новый произойдет только после окончания преобразования по старому каналу. Более того, старый результат будет читаться вплоть до окончания первого преобразования по новому каналу. Ну а с точки зрения программы действительно непредсказуемо. Если чтение выполняется по какому-нибудь тику с периодом, заведомо большим времени преобразования АЦП, то проще всего переключение и чтение синхронизировать софтовым флагом, взводимым при переключении канала и сбрасываемым при чтении результата АЦП. Код // on ADC channel change SkipADCResult = 1; ... // on ADC read if(SkipADCResult) SkipADCResult = 0; else x0=Adc[TekChan].X1=ADCH;
|
|
|
|
|
Jan 15 2008, 14:32
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(pokos @ Jan 15 2008, 17:01)  Насколько я понимаю процесс жизнедеятельности этого АЦП, мультиплексор каналов никак не синхрится от самого процесса преобразования. Поэтому вполне очевидно, что при переключении мультиплексора в произвольные моменты времени на выходе АЦП могут быть любые результаты, в том числе, и вообще не относящиеся к какому-либо каналу. Ведь выборка УВХ длится 1,5 такта. Неправильно понимаете. Физическое переключение каналов выполняется только по окончании текущего преобразования. Цитата The MUXn and REFS1:0 bits in the ADMUX Register are single buffered through a temporary register to which the CPU has random access. This ensures that the channels and reference selection only takes place at a safe point during the conversion. The channel and reference selection is continuously updated until a conversion is started. Once the conversion starts, the channel and reference selection is locked to ensure a sufficient sampling time for the ADC. Соответственно выборка производится с совершенно конкретного канала.
|
|
|
|
|
Jan 15 2008, 14:36
|

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

|
Цитата(pokos @ Jan 15 2008, 16:01)  Насколько я понимаю процесс жизнедеятельности этого АЦП, мультиплексор каналов никак не синхрится от самого процесса преобразования. Напрасно вы так понимаете. В описании написано другое - запись из регистра в мультиплексор блокируется в начале преобразования. Т.е. что было в регистре на момент начала преобьразования - то и окажется в мультиплексоре. Цитата(xemul @ Jan 15 2008, 14:04)  Не совсем так. С точки зрения АЦП измерение по-любому будет относиться к старому каналу, а переключение на новый произойдет только после окончания преобразования по старому каналу. Ну да. А поскольку оно FreeRunning, то предугадать, когда этот момент наступит относительно нашей записи в регистр мультиплексора невозможно.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 15 2008, 17:03
|

Частый гость
 
Группа: Участник
Сообщений: 80
Регистрация: 12-01-07
Из: Энергодар Украина
Пользователь №: 24 374

|
Хочу тоже задать вопрос! МК ATmega8, задействован только один канал. При непрерывном преобразовании нужно ли разрешать прерывания АЦП? И ещё такой вопрос. Можно ли в режиме одиночного преобразования запускать АЦП (ADSC=1) один раз в 1 мсек, например в прерываниях таймера ТС0. Сделать 16 измерений, все 16 результатов просуммировать и сумму сдвинуть вправо на 4 разряда. Такими действиями можно убрать колебания 2 мл разрядов АЦП? И ещё: нужно ли потом результат обрабатывать по алгоритму скользящего среднего? Может туманно написал, так извините!
|
|
|
|
|
Jan 15 2008, 17:24
|

Просто Che
    
Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881

|
Цитата(Anjey_N @ Jan 15 2008, 19:03)  При непрерывном преобразовании нужно ли разрешать прерывания АЦП? Можно не разрешать Цитата Можно ли в режиме одиночного преобразования запускать АЦП (ADSC=1) один раз в 1 мсек, например в прерываниях таймера ТС0. Сделать 16 измерений, все 16 результатов просуммировать и сумму сдвинуть вправо на 4 разряда. Такими действиями можно убрать колебания 2 мл разрядов АЦП? Можно. Это и есть оверсамплинг. Цитата И ещё: нужно ли потом результат обрабатывать по алгоритму скользящего среднего? А это как вы хотите. Если больше колебаний не наблюдается, то зачем это делать?
|
|
|
|
|
Jan 15 2008, 17:40
|

Частый гость
 
Группа: Участник
Сообщений: 80
Регистрация: 12-01-07
Из: Энергодар Украина
Пользователь №: 24 374

|
Цитата(Baser @ Jan 15 2008, 21:24)  Можно не разрешать Можно. Это и есть оверсамплинг. А это как вы хотите. Если больше колебаний не наблюдается, то зачем это делать? спасибо, это то что я хотел услышать!
|
|
|
|
|
Jan 15 2008, 17:46
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Не буду утверждать, так как для каких либо утверждений требуется произвести соответствующие исследования. Но на мой взгляд, я делаю всё верно. Тем не менее хомуты есть. Особенно настораживает то что происходят они не регулярно, а крайне редко. Что наводит на размышления о каких то хомутах отнюдь не в проге.
Спасибо всем - я всё устранил. Теперь всё работает.
Общие замечания такие. Согласно даташиту (в моём прочтении) в режиме FRM, не требуется сбрасывать флаг ADIF как и не требуется запускать преобразование. Это происходит автоматически. Ты можешь просто читать текущее значение. Я не нашёл время первого измерения относительно смены канала, но похоже оно должно быть 25 тактов АЦП. Все последующие по 13 тактов. Таким образом максимальное время выставления нового значения должно быть не больше 13*2+25=51 такт. Я проверял на 75. Это как-то не согласуется с даташитом. В то же время прямого хомута в проге нет, так как я сейчас просто перевёл прогу на одиночное преобразование (Изменил инициализацию и вставил запуск) и всё стало работать как часы.
Ранее я применял FRM правда на м8/м88 и время считывания показаний значительно превышало время преобразования. Всё работало. Остаётся только гадать сколько именно требуется АЦП для правильного отображения инфы.
2 Anjey_N
при непрерывном или любом другом преобразовании можно разрешать или запрещать прерывания от АЦП. Это к самому преобразованию не относится. Это только определяет каким образом вы будете обрабатывать результат. Я, к примеру, никогда не применяю прерывание от АЦП. Похоже что и вам это тоже не надо. Вы можете сделать прерывание от таймера 1мс, запустить преобразование от АЦП например в том же FRM и просто в прерывании читать значение. А можно каждый раз запускать одиночное преобразование и тоже читать значение.
Алгоритм скользящего среднего обычно делают так. Хранят в кольцевом буфере 16 последних значений и хранят сумму этих значений (а не высчитывают её каждый раз) при получении нового значения прибавляют его к сумме, а из суммы вычитают затираемое. И затирают новым значением старое. Используют нужное колличество бит. Если буфер расчитан на 256 значений, то можно просто использовать старший байт суммы (при 8 битовом АЦП).
Колебания младшего бита АЦП убрать никаким образом нельзя так как это ваша точность. Таким способом вы просто сглаживаете кривую.
|
|
|
|
|
Jan 15 2008, 20:56
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Jan 15 2008, 13:48)  Вот и я при чтении даташита пришел к тому же выводу - в режиме FreeRunning, если канал переключается не в прерывании АЦП первое измерение после переключения канала может относится как к старому, так и к новому каналу, поэтому его нужно отбросить. Это логически вытекает из описания и понятно. Ну и где Вы такое прочитали в даташите ? Читаем внимательно: In Free Running mode, always select the channel before starting the first conversion. The channel selection may be changed one ADC clock cycle after writing one to ADSC.Правда это относится только к старту первого преобразования... Еще раз читаем внимательно, разговор о Free Running и выставление флага ADSC касается только первого преобразования... Для подтверждения этой мысли читаем даташит еще чуть подробнее: Note that the conversion starts on the following rising ADC clock edge after ADSC is written.А вот это нам указывает на то что преобразование будет запущенно не в момент когда мы скажем ADSC, а когда наступит этот самый "rising ADC clock edge", тока не нужно расказывать что он придет абсолютно в произвольный момент времени.... Он придет абсолютно синхронно через считаемое количество тактов после ADEN и ADSC, тока нужно научится считать эти такты...
|
|
|
|
|
Jan 15 2008, 23:54
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(singlskv @ Jan 16 2008, 00:56)  Он придет абсолютно синхронно через считаемое количество тактов после ADEN и ADSC, тока нужно научится считать эти такты... Ещё раз обращаю Ваше внимание на то, что ADSC, ADEN, ADIF я вообще не трогал. И согласно даташиту это не требуется (только ADSC и ADEN при инициализации АЦП). И так я работал без особых проблем в других проектах. Я предложил мой расчёт для получения результата. Тем не менее при съёме с периодом 75 тактов АЦП примерно 1 раз в 15 - 20 секунд и более (иногда до нескольких минут) АЦП запущенное на частоте 16М/128=125кГц каким то образом ловило предыдущий канал. Это я установил абсолютно точно. При одиночном запуске я сейчас считываю значение через 50 тактов. Всё работает отлично. Может быть при смене канала требуется дополнительное время? Это, в общем то логично, но я не нашёл такого упоминания в даташите. Может данный режим используется без смены канала? ЗЫ: Кристалл at90can128. Там возможна такая фишка, как задание источника перезапуска АЦП в этом самом FRM. Этим источником может являться к примеру таймер.
|
|
|
|
|
Jan 16 2008, 08:24
|
Местный
  
Группа: Участник
Сообщений: 270
Регистрация: 29-06-06
Пользователь №: 18 445

|
Цитата(SasaVitebsk @ Jan 16 2008, 02:54)  ....Тем не менее при съёме с периодом 75 тактов АЦП примерно 1 раз в 15 - 20 секунд и более (иногда до нескольких минут) АЦП запущенное на частоте 16М/128=125кГц каким то образом ловило предыдущий канал. Ну, вообще-то про предыдущий канал прямо написано: "If both ADFR and ADEN is written to one, an interrupt event can occur at any time. If the ADMUX Register is changed in this period, the user cannot tell if the next conversion is based on the old or the new settings." А про несинхронность обновления каналов, да, каюсь, был неправ. Нашёл таки, что оно действительно синхрится с преобразованием и в free-run режиме тоже.
|
|
|
|
|
Jan 16 2008, 11:36
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(pokos @ Jan 16 2008, 12:24)  Ну, вообще-то про предыдущий канал прямо написано: То есть иными словами, необходимо два раза считывать и брать второй результат. Я правильно понял? Либо наверное перестартовывать. Получается, что в общем-то этот режим, в условиях частой смены каналов, абсолютно бесполезен. Не для этого преднозначен. Вроде разобрались всем миром. Всем спасибо за обсуждение.
|
|
|
|
|
Jan 16 2008, 15:19
|

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

|
Цитата(singlskv @ Jan 15 2008, 22:56)  Ну и где Вы такое прочитали в даташите ? ..... Он придет абсолютно синхронно через считаемое количество тактов после ADEN и ADSC, тока нужно научится считать эти такты... Вот любите вы поспорить. Если вы можете в программе с кучей прерываний в любой момент сказать, сколько тактов прошло с момента запуска АЦП (предварительно поделив на частоту тактирования АЦП, вычтя 25 и поделя на 13, учтя и время этих действий тоже) - то конечно, вы всегда знаете момент начала очередного преобразования. Но поскольку в реальной программе к моменту, когда вдруг потребовалось сменить канал прошло "хз сколько" тактов, то можно говорить, что момент смены неизвестен со всеми вытекающими.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 16 2008, 18:26
|
Местный
  
Группа: Свой
Сообщений: 234
Регистрация: 30-03-07
Из: Одесса
Пользователь №: 26 621

|
Я отжимался со свободным режимом - отлично работает. Я использовал прерывание. При входе в перывание сразу переключал мультиплексор на следующий канал. И никаких попаданий значений не туда, куда надо. Это похоже, у вас имеется некоторое, довольно большое значение выходного сопротивления источника сигнала. Если в этом случае вы переключите мультиплексор, подождете 25 тактов, и снимете данные, то получите некое значение, чем то похожее на предыдущий канал. но с поправкой на текущий.  В свободном режиме надо сначала выдернуть значение, после чего запустится новая конверсия, а потом сразу переключить мультиплексор на новый канал. Но значение будет получено с того канала, который был на момент выдергивания значения из АЦП!
|
|
|
|
|
Jan 16 2008, 20:16
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Jan 16 2008, 18:19)  Вот любите вы поспорить. Ну иногда да, особенно когда начинают рассказывать про магические перетекания из канала в канал, про необходимые пропуски преобразований, итд.... Сделай все по даташиту и проблем не будет. Не, ну конечно Атмел сильно намудрил с описанием функциональности АЦП, но после примерно 3-4 прочтения становится все более менее понятно... Цитата Если вы можете в программе с кучей прерываний в любой момент сказать, сколько тактов прошло с момента запуска АЦП (предварительно поделив на частоту тактирования АЦП, вычтя 25 и поделя на 13, учтя и время этих действий тоже) - то конечно, вы всегда знаете момент начала очередного преобразования. Но поскольку в реальной программе к моменту, когда вдруг потребовалось сменить канал прошло "хз сколько" тактов, то можно говорить, что момент смены неизвестен со всеми вытекающими. Не нужно таких сложных вычислений, в основном нужно знать моменты когда нельзя менять канал... Ну и если есть свободный таймер то все это отследить вобще не представляет сложностей. Если нету, ненамного сложнее, всегда можно привязаться к таймеру который обслуживает другие задачи. P.S. Кстати, а что это за магическое число 25 про которое все здесь говорят ? В даташите 25 это только первое преобразование после ADEN или преобразование после смены Reference, во всех остальных случаях 25 неактуально. Кстати, во всех своих прогах, при инициализации АЦП делаю это холостое "длинное" преобразование на 25 тактов, ну и дальше 25 уже нигде не встречается... P.P.S. Даташит раздел АЦП : "However, the simplest method is to..." Если мы обсуждаем наипростейшие варианты работы с АЦП и никуда не торопимся, тогда конечно проще подождать пару преобразований до получения правильного результата...
|
|
|
|
|
Jan 16 2008, 23:20
|
Частый гость
 
Группа: Свой
Сообщений: 92
Регистрация: 8-03-05
Пользователь №: 3 160

|
Небольшоё, аккумулятор-> 510 ом и 0,2uF на землю. Я "относительно" написал потому что у меня два канала шим стабилизации тока, когда канал выкл, вызывается ф. ожидания стабилизации напряжения, затем его измерения, в это время второй канал наводит помехи. Вот их влияние намного видней на 125kHz, если б не чего не фонило, то считывалось бы одинаково. Просто не понял в даташите 13 - 260 μs Conversion Time а у меня 125к ->8uSek и еще The ADC module contains a prescaler, which generates an acceptable ADC clock frequency from any CPU frequency above 100 kHz. И это 50-200к Трудности с переводом (учил немецкий), ощущения что вылез за разрешение 10 бит, растолкуйте пожалуйста.
|
|
|
|
|
Jan 16 2008, 23:33
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Ещё раз поясняю младший бит не может "отличаться устойчивостью". Это ваша точность. Чтобы вам понятнее было представьте что у вас измеряемое значение 212.5 (в единицах АЦП). Соответственно АЦП будет показывать то 212, то 213. Несмотря на устойчивость. Поэтому сколько бы разрядов АЦП не имело всегда точность не менее +/- единица младшего разряда. По поводу погрешностей и прочего - почитайте даташит - там достаточно детально всё расписано и сведено в графики. От себя замечу, что точность АЦП AVR мне не понравилась. Правда я и не пытался добиваться высокоточных результатов. Применение внешнего АЦП как правило даёт более хорошие результаты по стабильности и точности.
По поводу каких-то ошибок в озу - нигде и никогда не слышал. То что вы видите в распечатке - это кусок листинга который формирует Си компилятор. Мне и в голову не приходило самому распределять там память. Как линкер её распределил, так я и работал. Из того что я уже приводил - понятно что ошибка возникает именно при чтении из АЦП. Вроде в этой ветке разобрались с её природой. То есть виноват я сам, так как нечего притягивать за уши те способы работы, которые для этого не предназначены. FRM предназначен для слежения за сигналом из одного канала, на сколько я понял. При применении перебора каналов необходимо использовать другие режимы работы АЦП, так как FRM не имеет в этом случае абсолютно никакого выигрыша, а доставляет головную боль.
2 _Diman_. По поводу задаваемого вами вопроса - поищите по форуму. Месяца два-три назад мощная тема была где спецы аналоговые это обсасывают. Так как есть понятие "максимальная частота преобразований" для АЦП, а есть понятие "полоса пропускания".
|
|
|
|
|
Jan 17 2008, 15:38
|
Местный
  
Группа: Свой
Сообщений: 313
Регистрация: 7-01-07
Из: Севастополь
Пользователь №: 24 170

|
Цитата(SasaVitebsk @ Jan 17 2008, 01:33)  ... FRM предназначен для слежения за сигналом из одного канала, на сколько я понял. При применении перебора каналов необходимо использовать другие режимы работы АЦП, так как FRM не имеет в этом случае абсолютно никакого выигрыша, а доставляет головную боль. Не выдержал... Саша, Вы же здесь один из гуру, не делайте таких скоропалительных выводов. Нормально этот режим работает, если точно привязываться к записи мультиплексора. А это можно правильно сделать, только используя прерывание самого АЦП... У меня в серийном изделии нормально оцифровываются все 8 каналов. Прерываний всего 3. Прерывание ADC используется для диспетчера задач и переключения каналов. Но есть одно но :-), может, Вы именно на него наткнулись. Переключать каналы надо осторожно, у меня были глюки с данными, когда я слишком рано записывал новый адрес канала в ADMUX, до завершения новой выборки. Вот тогда и было некое дрожание и привирание в результатах. Тогда я увеличил выдержку до задания нового канала - вставил фоновую прогу формирования вспомогательных ШИМов,- и все зааработало. Еще одно неудобство для меня заключалось в том, что я коммутирую входные сигналы на АЦП, и было довольно трудно рассчитать правильное время коммутации - нужно учитывать время успокоения усилителя и прочее. Сейчас все работает правильно.
|
|
|
|
|
Jan 17 2008, 17:08
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Сейчас изделие отправили на натурные испытания на МТЗ. Это закрывается только первый этап из трёх данной темы. Потом начнётся устранение хомутов мелких и изделие ко мне ещё вернётся. Хорошо - уговорили. Я детально исследую данный вопрос, чтобы не быть голословным, и подробно доложу.  Пока же я только говорю, что нет смысла при такой работе мне использовать данный режим АЦП. Причина такой фразы проста. При FRM я использовал текст запуска преобразования: Код if(TekChan==(MAXADC-1)) ADMUX=KADMUX | VIRTCHAN; // Выбрать виртуальный канал else ADMUX=KADMUX | TekChan; // Выбрать канал При одиночном преобразовании я делаю следующее Код if(TekChan==(MAXADC-1)) ADMUX=KADMUX | VIRTCHAN; // Выбрать виртуальный канал else ADMUX=KADMUX | TekChan; // Выбрать канал ADCSRA =KADCSRA; // Начать отсчёт заново Если я в автоматическом преобразовании сделаю перестарт, то будет то же самое что и при одиночном измерении. Если же я буду делать два чтения, то текст разрастётся ещё больше. Таким образом выигрыша по коду не получается. Выигрыша по точности - тоже. Так зачем же тогда? Расчёт тактов у меня осуществляется очень точно. Правда не по прерыванию АЦП, а по таймеру. Давайте посчитаем вместе с вами. У меня прерывания идут с частотой 5кгц. То есть 200мкс. АЦП настроено на работу с частотой 16M/128 = 125kHz. Или 8мкс, то есть 25 тактов на прерывание. Естественно может быть +/-. Я пробовал от запуска до измерения 3 прерывания. Это 75 +/-. Согласно рассчётам я могу попасть на середину предыдущего преобразования (оно будет запорчено), и потом должно пройти 2 полных 25+13. То есть по максимуму 25+13+13 = 51 такт. Но у меня больше!!! Как минимум на одно! И, главное хомут возникает нерегулярно, а достаточно редко! Представляете что иногда проходит несколько минут!!! Видимо при работе по прерыванию от АЦП гарантировано сбрасывается значение. А у меня работа несколько другая. У меня 3 канала АЦП + один частотный + 2 CAN. Я выставил канал - прочитал а потом к примеру перешёл на CAN, а АЦП - молотит. Через некоторое время, я, нечитая, перехожу на новый канал. Я не усматриваю здесь проблемы, но отрицать её - значит грешить против фактов! Короче, давайте на время прервём пока беспредметный спор. Я точно и подробно диагностирую, так как у меня всё настроено, и приведу результаты в данной ветке. Думаю в среду где-то. Когда прибор у меня на столе лежать будет.
|
|
|
|
|
Jan 17 2008, 22:47
|
Местный
  
Группа: Свой
Сообщений: 313
Регистрация: 7-01-07
Из: Севастополь
Пользователь №: 24 170

|
Цитата(_Pasha @ Jan 17 2008, 22:14)  Чушь! Вы чего-то не договариваете. Потому что ADMUX буферизован, и "слишком рано" записать нельзя. "Слишком поздно" - это можно, но тогда на следующем прерывании будет принят предыдущий канал. Да, каюсь, не договорил. У меня ADMUX+2 канала, именно чтобы не принимать предыдущий канал, и только тогда работает нормально... Так, как в даташите, +1, как раз дает примерно то же, что описал SasaVitebsk. А насчет буферизации - я же писал, что не стал проводить всесторонних исследований, нормально заработало после сдвига. Просто это первое, что я проверил. Дело в том, что у меня есть второе, совсем уж непредсказуемое по времени появления, прерывание. И первое, что бросилось мне в глаза, это периодическая и довольно редкая запись в мультиплексор после окончания нового цикла выборки. Я сформировал стробы на программный осциллограф и увидел довольно точную привязку этих событий к "дрожанию" данных. Ну и сделал сдвиг. Pasha - я, например, точно не знаю, как там буфериризация сделана. Может, криво. Может, я сам код криво написал - хотя там ровно два байта того кода... SasaVitebsk, буду ждать результатов.
Сообщение отредактировал IGK - Jan 17 2008, 22:50
|
|
|
|
|
Jan 18 2008, 09:36
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Jan 16 2008, 02:54)  Тем не менее при съёме с периодом 75 тактов АЦП примерно 1 раз в 15 - 20 секунд и более (иногда до нескольких минут) АЦП запущенное на частоте 16М/128=125кГц каким то образом ловило предыдущий канал. Это я установил абсолютно точно. Кстати, тут еще вспомнил один нюансик в работе АЦП. Судя по частоте появления ошибки, возможно Вы натыкаетесь на то, что преобразование заканчивается сразу же после считывания ADCL и до считывания ADCH. В этой ситуации запись со стороны ADC к ADCL и ADCH заблокированна и очередное преобразование просто теряется.
|
|
|
|
|
Jan 18 2008, 14:26
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(singlskv @ Jan 18 2008, 13:36)  ...сразу же после считывания ADCL и до считывания ADCH. В этой ситуации запись со стороны ADC к ADCL и ADCH заблокированна и очередное преобразование просто теряется. Вообще-то в момент чтения ADCL содержимое ADCH записывается во временный регистр, извините за банальность  , и таким образом за раз читаются все 16(10) бит. Было бы нелогично запрещать операции записи результата АЦП до завершения чтения временного регистра. Вы ничего не путаете?
|
|
|
|
|
Jan 18 2008, 14:35
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(_Pasha @ Jan 18 2008, 17:26)  Вообще-то в момент чтения ADCL содержимое ADCH записывается во временный регистр, извините за банальность  , и таким образом за раз читаются все 16(10) бит. Было бы нелогично запрещать операции записи результата АЦП до завершения чтения временного регистра. Вы ничего не путаете? А где это вы нашли временный регистр для хранения ADCH ? Вы случайно с таймерными 16бит регистрами не путаете ?  Читаем внимательно даташит: Otherwise, ADCL must be read first, then ADCH, to ensure that the content of the data registers belongs to the same conversion. Once ADCL is read, ADC access to data registers is blocked. This means that if ADCL has been read, and a conversion completes before ADCH is read, neither register is updated and the result from the conversion is lost. When ADCH is read, ADC access to the ADCH and ADCL Registers is re-enabled.
|
|
|
|
|
Jan 19 2008, 04:54
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(singlskv @ Jan 18 2008, 18:35)  А где это вы нашли временный регистр для хранения ADCH ? Вы случайно с таймерными 16бит регистрами не путаете ?  Читаем внимательно даташит: Мда-с... Проблема восприятия большого количества инфы... Спасибо, вразумили. Тогда это действительно многое объясняет. Получается, что в авто-триггерных режимах даже из-за приоритета прерывания можно на граблях кататься.
|
|
|
|
|
Jan 19 2008, 20:04
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(_Pasha @ Jan 19 2008, 22:43)  Вы, сишники, народ абстрактный...  Если это ко мне, то я не синшник, у меня чуть другой ник.... Похоже с первого раза вразумить не удалось....  Вы видимо крутой асемблерщик ? хотите посоревноваться в написании кода на асм ? тогда welcome, тока другую тему откройте... Цитата вот SasaVitebsk нам сишный код и покажет. Ну и ? У него(сишного кода), есть очень четкий эквивалент на асм в виде листинга компилятора...
|
|
|
|
|
Jan 20 2008, 01:56
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
2 SashaVitebsk.
IMHO считывать АЦП по таймеру немного неестветвенно (не природно) выглядит.
Я пользуюсь таким подходом - периодически запускаю АЦП в Single Conv режиме, с флажком "доверия" == "0", т.е. результат первого преобразования я всегда считаю неправильным. По прерыванию от АЦП вычитываю и выбрасываю результат, перезапускаю АЦП для того же самого канала и устанавливаю флажек "доверия" в "TRUE", что означает, что следующему результату однозначно можно доверять. На следующем прерывании от АЦП вычитываю и сохраняю результат текущего канала как (Vintegral = Vcurrent - Vaverage) и меняю канал, флажек "доверия" сбрасываю в "0" (т.е. первый рез-тат после смены канала будет выброшен), и так до тех пор пока не получу результат последнего, интересующего меня, канала.
Т.о. единожды запустив опрос АЦП - у меня получаются данные по всем каналам и опрос сам собой прекращается. Эта схема всегда работает - как часы.
Никогда не заморачивался с подсчетом тактов и ассемблером в этом вопросе.
|
|
|
|
|
Apr 15 2008, 08:02
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Имею проблему с выводом по UART результата измерения АЦП (Mega48, 20Мгц), работающего в free running mode. Настроен только на измерение с одного канала. Синхронизация передачи значения АЦП в BCD формате по UART осуществляется в главном цикле по флагу DISPLAY. UART работает с использованием прерывания (avr306 - interrupt controlled UART). В программе еще используется прерывание от таймера1 (вызывается через 10 мсек), в котором осуществляется динамическая индикация и обработка кнопок. Код void Initialise(void) { ................. //ADC initialisation: ADMUX=(1<<REFS1)|(1<<REFS0);//Установка Photo_Channel (ADC0), //Internal 1.1V Voltage Reference with external capacitor at AREF pin //Старт непрерывного преобразования с частотой 156,25 кГц, Предделитель = 128, //Разрешить прерывание АЦП ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); }
//////////////////////////////////////////////// void main(void) { Initialise(); __enable_interrupt(); for(;;) { if(Flags&DISPLAY) { itoa(tmp, buf2); TransmitByte(*(buf2+0)+'0'); TransmitByte(*(buf2+1)+'0'); TransmitByte(*(buf2+2)+'0'); TransmitByte(*(buf2+3)+'0'); TransmitByte(13); //CR TransmitByte(10); //LF // delay_ms(250); Flags &= ~DISPLAY; } __sleep(); //Idle mode } }
////////////////////////////// #pragma vector=ADC_vect __interrupt void ADC_ISR(void) { acum += ADC;
if(++SampleCounter == max) { value = acum/max; SampleCounter=0; acum=0; if(!(Flags&DISPLAY)) { tmp = value; Flags |= DISPLAY; } } .... } Собственно, я подошел к сути проблемы. На терминале получаю значения АЦП, чередующиеся с 0, типа так: 0031 0031 0030 0000 0000 0000 0031 0031 0030 0000 0000 0000Если остановить таймер1, то выводит то, что положено - без нулей. Если запустить таймер1 и после очередной отправки результата по UART вставить задержку 250ms (в приведенном коде закомментирована), то выводит также без нулей. При уменьшении задержки до 100ms начинают вылазить нули. Почему так происходит? PS. Выводить результат на UART нужно максимально быстро. Single Mode не предлагать.
|
|
|
|
|
Apr 15 2008, 12:38
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(SasaVitebsk @ Apr 15 2008, 12:19)  А Flags у вас объявлен как volatile? Flags объявлен глобально, без volatile. volatile в данном случае здесь ни при чем. Но на всякий случай проверил: с volatile проблема осталась. На мой взгляд проблема как-то связана с прерываниями. Если за время обработки прерывания от таймера1 произошло несколько прерываний от АЦП (которые имеют низкий приоритет), то после окончания обработки прерывания от таймера1 попадаем в обработчик прерывания от АЦП. В момент между считываниями ADCL и ADCH возможна ситуация, когда происходит следующее преобразование АЦП, и предыдущий результат теряется. Но не обнуляется ведь! Это только моя версия происходящего. Какие будут еще ваши предположения? PS. Чем объяснить такую строгую периодичность: после трех правильных данных идут три нулевых? PS2. Версию, что таймер своими шумами влияет на работу АЦП, я тоже отбрасываю. Может быть нехватка стека? Но я не использую ресурсоемких функций. И пробовал увеличить CSTACK(0x100), RSTACK(0x64). Не помогло.
|
|
|
|
|
Apr 15 2008, 14:07
|

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

|
Цитата(alux @ Apr 15 2008, 15:38)  volatile в данном случае здесь ни при чем. Но Flags должен быть volatile, также как и tmp. Лучше сразу писать правильно, чем ждать, когда начнется "при чем". Есть еще одно потенциальное место для бага: Flags &= ~DISPLAY; Оно компилируется примерно в такое: Код register Tmp = Flags; (1) Tmp = Tmp & DISPLAY; (2) Flags = Tmp; (3) Что произойдет, если между командами 1 и 3 произойдет прерывание, изменяющее Flags? Обращения к подобным переменным надо делать атомарными, т.е. с запретом прерываний. Цитата(alux @ Apr 15 2008, 15:38)  Но не обнуляется ведь! Попробуйте присваивать tmp в прерывании константу, т.е. исключите АЦП из получения результата.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 15 2008, 16:12
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(Сергей Борщ @ Apr 15 2008, 17:07)  Попробуйте присваивать tmp в прерывании константу, т.е. исключите АЦП из получения результата. Присвоил переменным Flags, value, tmp квалификатор volatile. В прерывании АЦП делаю tmp=123;. В итоге на терминал выводится последовательность 123 без промежуточных нулей. Цитата(Сергей Борщ @ Apr 15 2008, 17:07)  Обращения к подобным переменным надо делать атомарными, т.е. с запретом прерываний. В главном цикле при обнулении флага сделал так: Код oldState = __save_interrupt(); __disable_interrupt(); Flags &= ~DISPLAY; // Critical section goes here __restore_interrupt(oldState); .................. Еще вычитал в документации, что для неразрывного кода используется ключевое слово __monitor. Но оно, насколько я понял, относится к функциям. PS. В общем, обнуление флага сделал в критической секции. Проблема осталась. Мне кажется проблема кроется в чем-то другом. Мои идеи иссякли.  PS2. Эксперимент с присвоением константы 123 переменной tmp показывает, что проблема кроется в АЦП? Т.е. так, как я описывал выше? PS3. Прошу прощения за свою невнимательность... Проблемы, как таковой и не было!!! Если мерять реальное напряжение (у меня меряется напряжение на фотодатчике), то все нормально - никаких нулей нет! При отсутствии отраженного сигнала (напряжение минимально), получаю промежуточные нули. Видимо, это действительно связано с шумами таймера, которое отражается в виде меандра амплитудой около 30 (в кодах АЦП). Спасибо, СергейБорщ, SasaVitebsk, что указали на потенциальный источник ошибок.
Сообщение отредактировал alux - Apr 15 2008, 17:13
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|