|
|
|
ADC на 328 атмеге оцифровка с не тех входов |
|
|
|
Sep 20 2017, 12:18
|
студент
Группа: Свой
Сообщений: 571
Регистрация: 3-07-08
Из: Russia
Пользователь №: 38 712
|
Привет всем! попытаюсь описать свою проблему. Есть 2 аналоговых канала. Оба замеряют напряжение и подключены на ADC7 и ADC0 контроллера. обработчик прерывания написан так: Код #define ADC_VREF_TYPE ((0<<REFS1) | (0<<REFS0) | (0<<ADLAR)) //AREF - reference #define ADMUX_0 (ADC_VREF_TYPE|0) #define ADMUX_7 (ADC_VREF_TYPE|7) DIDR0 = (0<<ADC5D)|(0<<ADC4D)|(0<<ADC3D)|(0<<ADC2D)|(0<<ADC1D)|(0<<ADC0D); ADMUX = ADMUX_0; //AREF pin ADCSRA = (1<<ADEN) |(1<<ADSC) |(1<<ADATE)|(0<<ADIF) |(1<<ADIE) |(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); ADCSRB = (0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);// отказываемся от источника запуска преобразования
ISR(ADC_vect) { static u08 i = 0; adcData[i] = ADCW;// Read the AD conversion result switch(i) { case 0: { ADMUX = ADMUX_7; //res i = 1; }break; case 1: { ADMUX = ADMUX_0; //m_s i = 0; }break; } _delay_us(10);// Delay needed for the stabilization of the ADC input voltage ADCSRA|=(1<<ADSC); } проблема в том, что adcData[0] оцифровывает значение с канала ADC7, а adcData[1] с канала ADC0, т.е наоборот...В чем косяк понять не могу, ведь я могу сменить вход adc только при окончании текущего преобразования и до запуска слудующего. Попав в обработчик я полагаю, что текущее преобразование уже закончено и новое не запустится, пока не взведу флаг ADSC.
--------------------
С Уважением...
|
|
|
|
|
Sep 20 2017, 13:48
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (Fynjisx @ Sep 20 2017, 15:18) В чем косяк понять не могу, ведь я могу сменить вход adc только при окончании текущего преобразования и до запуска слудующего Не совсем так, читайте описание внимательнее. Вы можете писать биты выбора канала когда угодно, но если преобразование уже началось, то сработают они только после его окончания. У вас же происходит следующее: вы запускаете АЦП в свободнобегущем режиме, т.е. взведение бита ADSC запускает первое преобразование, а дальше АЦП само автоматически начинает следующее преобразование сразу после окончания предыдущего. У вас заканчивается преобразование, скажем, канала 0, генерится прерывание и тут же запускается следующее. Вы попадаете в прерывание, переключаете канал, но это переключение будет принято во внимание только перед следующим преобразованием, поскольку очередное преобразование уже началось. У вас есть два выхода: либо сразу после первой установки ADSC записать в ADMUX номер канала для следующего преобразования и дальше уже ADSC не трогать, либо записать в ADATE ноль и тогда АЦП будет ожидать от вас ADSC перед началом каждого преобразования. QUOTE (Fynjisx @ Sep 20 2017, 15:18) CODE .... _delay_us(10);// Delay needed for the stabilization of the ADC input voltage ..... } Ужас. Уберите __delay_us() и больше так никогда не делайте. Во-первых АЦП само добавляет необходимое количество тактов к времени выборки при смене канала, а во-вторых задержки в прерывании - это просто глупо. Пока вы сидите в этой задержке все остальные прерывания заблокированы.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 21 2017, 04:28
|
студент
Группа: Свой
Сообщений: 571
Регистрация: 3-07-08
Из: Russia
Пользователь №: 38 712
|
Цитата(Сергей Борщ @ Sep 20 2017, 17:48) ...вы запускаете АЦП в свободнобегущем режиме, т.е. взведение бита ADSC запускает первое преобразование, а дальше АЦП само автоматически начинает следующее преобразование сразу после окончания предыдущего. У вас заканчивается преобразование, скажем, канала 0, генерится прерывание и тут же запускается следующее. Вы попадаете в прерывание, переключаете канал, но это переключение будет принято во внимание только перед следующим преобразованием, поскольку очередное преобразование уже началось. У вас есть два выхода: либо сразу после первой установки ADSC записать в ADMUX номер канала для следующего преобразования и дальше уже ADSC не трогать, либо записать в ADATE ноль и тогда АЦП будет ожидать от вас ADSC перед началом каждого преобразования. Вы молодец Сергей, я тоже пришел к такому выводу после долгих мучений, что вся проблема во free run mode и в прерывании нахожусь когда наверняка следуещее уже шпарит. Просто в даташите это не было описано. В последствии я убрал DATE бит, и запускаю каждое следующее уже в конце обработчика. Цитата(Сергей Борщ @ Sep 20 2017, 17:48) Ужас. Уберите __delay_us() и больше так никогда не делайте. Во-первых АЦП само добавляет необходимое количество тактов к времени выборки при смене канала, а во-вторых задержки в прерывании - это просто глупо. Пока вы сидите в этой задержке все остальные прерывания заблокированы. Логично рассуждаете, готов сделать так, но почему тогда в датише описана эта задержка....Ах да, там скорее всего наверное дан пример однократных запусков, т.к к ней комментарий объяснял ее внедрение для устаканивания напряжения на выходе мультиплексора при смене входного канала. Большое спасибо Сергей...
--------------------
С Уважением...
|
|
|
|
|
Sep 21 2017, 06:46
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (Fynjisx @ Sep 21 2017, 07:28) Просто в даташите это не было описано Было, и даже с картинкой:
QUOTE (Fynjisx @ Sep 21 2017, 07:28) Логично рассуждаете, готов сделать так, но почему тогда в датише описана эта задержка... Ах да, там скорее всего наверное дан пример однократных запусков, т.к к ней комментарий объяснял ее внедрение для устаканивания напряжения на выходе мультиплексора при смене входного канала. Что-то я не нашел такого объяснения. Я тоже глупость спорол (перечитал еще раз, освежил в памяти): дополнительная задержка делается автоматически только при первом преобразовании после взведения ADEN: QUOTE The first conversion after the ADC is switched on (ADEN in ADCSRA is set) takes 25 ADC clock cycles in order to initialize the analog circuitry После смены канала дополнительная задержка не нужна просто потому, что конденсатор устройства выборки-хранения (УВХ, sampling capacitor) подключается к входной цепи только на время выборки. Это время в описании не указано, но оно прибито гвоздями, на него мы повлиять не можем никак. Единственное, что мы можем сделать - это обеспечить настолько низкое выходное сопротивление измеряемой цепи, чтобы за время выборки запоминающий конденсатор УВХ успел зарядиться до входного напряжения с погрешностью не более половины веса младшего значащего разряда или же уменьшить тактовую частоту АЦП настолько, чтобы времени выборки стало достаточно для имеющегося выходного сопротивления источника сигнала. Для 12-битного преобразования на максимальной частоте выходное сопротивление источника сигнала должно быть меньше 10 кОм (это указано в документации), для меньшей разрядности или частоты его можно посчитать.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|