|
|
  |
Вопрос по АЦП, Free running mode |
|
|
|
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)
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|