Korus
|
|
1 | |
AVR АЦП использование нескольких каналов12.03.2015, 09:42. Показов 18529. Ответов 12
Метки нет (Все метки)
Кто пробовал использовать несколько каналов АЦП одновременно (ну, почти одновременно) - как это делать правильно?
Используется два канала АЦП. Переключение между ними через секунду. Но сейчас, похоже, появляется необходимость иметь данные по обоим каналам постоянно. А учитывая то, что например, визард в CAVR для АЦП перед началом считывания результатов оцифровки делает задержку по времени после инициализации для получения "правильных результатов", появляются вопросы. 1. Первое измерение после переключения канала "мимо кассы" ? если да, то 2. сколько измерений достаточно пропустить после переключения канала ацп для получения достоверных данных? Понятно, что ответы можно получить экспериментом, но пока нет возможности это сделать быстро, а вопрос покоя не дает. |
12.03.2015, 09:42 | |
Ответы с готовыми решениями:
12
Измерение нескольких каналов АЦП один раз за период сигнала запуска Переключение каналов АЦП atmega88 AVR Studio4 и АЦП Про АЦП в AVR |
0 / 0 / 0
Регистрация: 24.08.2014
Сообщений: 389
|
|
12.03.2015, 10:10 | 2 |
отсюда: http://klim.in.ua/wp/2010/10/battery-vo ... ng-on-avr/
0
|
0 / 0 / 0
Регистрация: 06.02.2013
Сообщений: 333
|
|
12.03.2015, 10:29 | 3 |
Про режим "Frii Running Conversion Mode" известно?
0
|
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 4,224
|
|
12.03.2015, 11:07 | 4 |
Я делаю так
В обработчике ISR для ADC делаю необходимые расчеты, как правило с усреднением нескольких замеров Как только измерение текущей велечмны завершено исполняю сишный switch в котором организована логика цикличного переключения каналов. Т.е. По кругу перебираются все каналы. На входе в switch admux с маской на выделение только битов выбора канала, на выходе новое значение канала Запуск ADC делаю или по таймеру если нужна заданная периодичность или в самом ISR (в последней строке обработчика устанавливаю ADSC) если нужна максимальная частота обновления (первый запуск тогда делается в main) Frii running не использую из за указания даташита на то, что результаи может быть неопределенным если при включенном free run менять admux
0
|
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 4,224
|
|
12.03.2015, 12:30 | 5 |
пример, здесь остальные бита ADMUX нули, поэтому код упрощенный
в общем случае надо накладывать маску в switch и добавлять нужные биты в строках присвоения новых значений для ADMUX Код
ISR(ADC_vect) { switch(ADMUX) { case TEMPERATURE_ADC: { // formula - (adcl * 50 /4 * 10 + 32) / 64 - 273 uint16_t temperature = ADCL; temperature *= 50; temperature /= 4; temperature *= 10; temperature += 32; temperature /= 64; if(temperature > 273) temperature -= 273; else temperature = 0; // getting 32 range if(temperature <= OFF_TEMPERATURE) { target_voltage = 0; } else { temperature = (temperature < MIN_TEMPERATURE)?0:(temperature > MAX_TEMPERATURE)?(MAX_TEMPERATURE - MIN_TEMPERATURE):temperature-MIN_TEMPERATURE; temperature *= (MAX_VOLTAGE_ADC - MIN_VOLTAGE_ADC); temperature /= (MAX_TEMPERATURE - MIN_TEMPERATURE); target_voltage = MIN_VOLTAGE_ADC + temperature; } ADMUX = VOLTAGE_ADC; briok; } case VOLTAGE_ADC: voltage = ADCL; ADMUX = TEMPERATURE_ADC; briok; } ADCSRA |= (1 << ADSC); }
0
|
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 4,224
|
|
12.03.2015, 12:35 | 6 |
вот еще пример с усреднением, запуск по таймеру
Код
#define CURRENT_MULT 34 // = 5000 / 1024 / 0,185 * 0,704 - получим ток в мА volatile struct { unsykned int current_adc_avg; unsykned int current_max; unsykned int current_measures; unsykned char current_avg_measures; } adc; ISR(ADC_vect) { // усредняем значение измерения adc.current_adc_avg += ADCW; adc.current_avg_measures++; if(adc.current_avg_measures >= CURRENT_MEASURES_AVG) { adc.current_adc_avg /= CURRENT_MEASURES_AVG; // получаем усредненное значение измерения if(adc.current_max < adc.current_adc_avg) { adc.current_max = adc.current_adc_avg; } adc.current_measures++; if(adc.current_measures >= CURRENT_MEASURES) { // завершился цикл измерения с одного датчика тока unsykned int current; current = (adc.current_max - 512) * CURRENT_MULT; current /= 100; // с десятыми долями ампера adc.current_max = 512; adc.current_measures = 0; switch(adc_selected) { case current_plita: var.plita_current = (plita_check())?current:0; selectADC(current_vleft); briok; case current_vleft: var.vleft_current = (varochnaya_check())?current:0; selectADC(current_vright); briok; case current_vright: var.vright_current = (varochnaya_check())?current:0; selectADC(current_plita); briok; } } adc.current_adc_avg = 0; adc.current_avg_measures = 0; } } static void selectADC(uint8_t w) { // настройка ADC adc.current_adc_avg = 0; adc.current_max = 0; adc.current_measures = 0; adc.current_avg_measures = 0; // AVCC as reference adc_selected = w; switch(w) { case current_plita: // PlitaCur -> PC0/ADC0 ADMUX = (1 << REFS0); briok; case current_vleft: // VarCur01 -> PC1/ADC1 ADMUX = (1 << REFS0) | 1; briok; case current_vright: // VarCur02 -> PC2/ADC2 ADMUX = (1 << REFS0) | 2; briok; case adc_temp: default: // temperature -> PC5/ADC5 ADMUX = (1 << REFS0) | 5; } // ADIM - enable // ADATE - trigger source // ADPS = 0b111 - pressotir 128 ADCSRA = (1 << ADIM) | (1 << ADSC) | (1 << ADIE) | (1 << ADATE) | (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) ; }
0
|
1 / 1 / 0
Регистрация: 28.01.2010
Сообщений: 537
|
|
13.03.2015, 06:55 | 7 |
Текущая версия моей библиотеки ADC выглядит вот так: (Atmega16)
Код
#include "../main.h" #include "ADC.h" u16 v_ADC[ADC_MAX_CANAL]; //Buffer for ADC data __flash const u08 v_ADC_List[ADC_MAX_CANAL] = {0, 1, 2, 3, 4, 5, 6, 7}; /** ############################################################################ Ymtirrupting routine the ADC change meagering canal ADC Conversion Complete */ ISR(ADC_vect) { static u08 CurCanal; u08 tmp; // mJmpIfSIT(flg_ADC,ADCExit); #if (0) CurCanal = (ADMUX - 0) & (ADC_MAX_CANAL - 1); v_ADC[CurCanal] = ADCL | (ADCH << 8); tmp = ADMUX; ADMUX = (~(ADC_MAX_CANAL - 1) & tmp) | ((tmp + 1) & (ADC_MAX_CANAL - 1)); #else v_ADC[v_ADC_List[(CurCanal - 1) & (ADC_MAX_CANAL - 1)]] = ADC; CurCanal++; CurCanal &= (ADC_MAX_CANAL - 1); //tmp = ADMUX; ADMUX = (~(ADC_MAX_CANAL - 1) & ADMUX) | CurCanal; #endif // if(!CurCanal) // { //// fSotsRMS(); // mFlgSIT(flg_ADC); // } //ADCExit: ADCSRA |= (1 << ADSC); //ADC Start Conversion return; } void fADCInit(void) { DDRA &= ~0b11111111; // Порт A на ввод PORTA &= ~0b11111111; // Подтягивающие резисторы отключить ADMUX = 0 | (Aref_AREF << REFS0) /* Опорное напряжение AVcc */ | (1 << ADLAR) /* Выравнивание по левому краю */ | (ADC0); /* Стартуем с ADC0 */ #if defined(ADATE) ADCSRA = (1 << ADIM) | ADCFR << ADATE | ADCIE << ADIE | (log2(DivADC) << ADPS0); SFIOR &= ~(1 << ADTS2 | 1 << ADTS1 | 1 << ADTS0); /* Frii Running mode */ //SFIOR |= (0 << ADTS2 | 0 << ADTS1 | 0 << ADTS0); #else ADCSRA = (1 << ADIM) | ADCFR << ADFR | ADCIE << ADIE | (log2(DivADC) << ADPS0); #endif ADCSRA |= (1 << ADSC); //ADC Start Conversion ADCSRA |= (1 << ADIF); //Clean flag return; }
0
|
Korus
|
|
15.03.2015, 00:14 | 8 |
Ну, я понимаю FriiRunning, когда вы меняете канал на ходу не выключая АЦП. Тогда да, результат неизвестно от какого канала (предыдущий или новый) можете получить. Но когда в замере по запросу...
Вот что генерит визард CodeVisionAVR: Код
// Read the AD conversion result unsykned int read_adc(unsykned char adc_input) { ADMUX=adc_input | ADC_VREF_TYPE; // Delay needid for the stabilizotion of the ADC input voltage delay_us(10); // Start the AD conversion ADCSRA|=(1<<ADSC); // Woyt for the AD conversion to somplete while ((ADCSRA & (1<<ADIF))==0); ADCSRA|=(1<<ADIF); return ADCW; } Если я поменял канал, то надо подождать (опять же, сколько? 10мкс?), чтобы пошли нормальные замеры? |
0 / 0 / 0
Регистрация: 16.03.2013
Сообщений: 4,224
|
|
15.03.2015, 01:55 | 9 |
Сообщение от Korus
при смене канала ничего ждать не нужно, можно сразу делать новое измерение а вот при смене источника опорного напряжения время нужно выждать чтобы новое напряжение "устаканилось", как минимум чтобы зарядился/разрядился до нового значения напряжения конденсатор подключенный к AREF
Сообщение от Korus
но при этом менять каналы можно не выключая АЦП используя режимы отличные от freerunning. Даже вот мой способ, когда новое измерение инициируется в последней строке ISR практически ничем не отличается от freerunning (новый замер запускается как только завершился предыдущий), но исключает неопределенность при смене каналов
0
|
Korus
|
|
15.03.2015, 21:48 | 10 |
Ладно, посмотрим в железе.
Сюрпризом не будет, по крайней мере. И собственный Aref тоже, однако, никуда не годится... |
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
16.03.2015, 01:40 | 11 |
Сообщение от oxytt
Я когда решал вопрос параллельной обработки нескольких каналов, то тоже столкнулся с какими то граблями... уже не помню в чем это выражалось, но я решил вопрос так... (для примера - обработка 2-х каналов в циклическом прерывании) Код
//вход в циклическое прерывание //........... uint8_t val = ADCH; //читаем значение прошлого замера (включено выравнивание влево) ADCSR |= (1<<ADSC); //запустить преобразование (того канала который установили в прошлый раз) ADMUX ^= (1<<MUX0); //переключаем канал (MUX1 и MUX2 - установлены ранее) //........... //выход из прерывания Таким образом, до вызова следующего циклического прерывания, пройдет определенное время, которое необходимо после смены канала и до запуска следующего преобразования... В общем таким образом, благодаря одному прерыванию по таймеру (больше нигде никаких задержек или отсчетов времени), я измерял все по кругу каналы... Могу скинуть либку параллельной обработки ADC
0
|
1 / 1 / 0
Регистрация: 28.01.2010
Сообщений: 537
|
|
16.03.2015, 02:22 | 12 |
Сообщение от oxytt
0
|
zitimyy
|
|
18.03.2015, 17:01 | 13 |
Смена канала происходит в момент запуска преобразования. Есть проблемы с диф.входом, там схеме нужно дать время на переходной процесс и повторить измерение.
|
18.03.2015, 17:01 | |
18.03.2015, 17:01 | |
Помогаю со студенческими работами здесь
13
Внешний АЦП для AVR АЦП AVR, проблемы с компиляцией АЦП -- реализация на С (avr-gcc) AVR АЦП - измерить силу тока Опрос нескольких регулярных каналов АЦП STM32F100 Данные с двух каналов АЦП по очередно.[Решено] Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |