Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ATmega128 проблема переключения каналов АЦП
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
pokk
Здравствуйте, не как не могу разобраться с данной проблемой.
Ацп работает в режиме автоматического перезапуска с частотой 12 кГц и тактовая частотой АЦП 156 кГц (1 такт АЦП 64 такта процессора). Прерывания внутри АЦП разрешены для работы таймера. Приведённый ниже код работает, переключение каналов происходит. Буфер накапливается и значения АЦП по USART забирается (с периодом 300мс). Но примерно пару раз в минуту данные идут не с того канала в частности в обработке канала I2_MAIN проскакивают значения из канала I_42_MAIN почему такое происходит?
При убирании задержки в 200 тактов(для записи MUX) или запрет прерывания в обработчике АЦП, таких частых проскоков не наблюдается. Как это может быть связанно ? Без задержки в 200 тактов такое происходили но с периодичностью в минут 30.
CODE
////=============ADCinitialization==================================================
=================
////ADCSRA=0;
//ADMUX=2; //I1
//ADCSRA=(1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
//
//ADC_I42
//ADMUX=1; //slave in
//ADCSRA=(1<<ADEN) | (1<<ADSC) | (1<<ADFR) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
////================================================================================
============
interrupt [ADC_INT] void adc_isr(void){
#asm("sei")
switch(adc_main){
case I1_MAIN:{
adc_main=I_42_MAIN; // Переход на измерения следующего канала
ADC_BUF->test_int[4]=ADCW; //записали в буфер(данный буфер выдаётся в UART по запросу)
ADMUX_TEMP=3; //I2 переключаемся на канал I2 через итерацию(для установления переходных процессов) с задержкой в 200 тактов
//ADC_I28
break;
}
case I_42_MAIN:{
adc_main=I2_MAIN; // Переход на измерения следующего канала
ADC_BUF->test_int[3]=ADCW; //записали в буфер(данный буфер выдаётся в USART по запросу)
ADMUX_TEMP=1; //I28 переключаемся на канал I28 через итерацию (для установления переходных процессов) с задержкой в 200 тактов
break;
}
case I2_MAIN:{
// Правильно значение АПЦ равно 647 в основном оно так и приходит но время от времени (пару раз в минуту)
// Проскакивает значение с АЦП c предыдущего канала.
// функция DEBUGER заносит в очередь ошибку(и значение АЦП) для отправки по USART

if(ADCW>700){DEBUGER("ADCW_HIGEST=",0,ADCW,var2);}
if(ADCW<600){
DEBUGER("ADC_INT_ADCW=",0,ADCW,var2);
LED_GREEN_DOWN();
test_I2[test_I2_index]=ADCH;
test_I2[test_I2_index+1]=ADCL;
test_I2_index++;
if(test_I2_index>14){test_I2_index=0;}
}
ADC_BUF->test_int[1]=ADCW;
adc_main=I28_SLAVE;
ADMUX_TEMP=2; //I
//ADC_I42
break;
}
case I28_SLAVE:{
adc_main=I1_MAIN;
ADC_BUF->test_int[5]=ADCW;
ADMUX_TEMP=1;
break;
}
default:{
adc_main=I1_MAIN;
DEBUGER("adc_main=error",0,0,MESEGER);
}
}

#include <nop2.c> // задержка 200 nop
ADMUX=ADMUX_TEMP;
}
RabidRabbit
У Вас на одну выборку приходится 13*64 = 832 периода тактирования процессора. Вам хватает этого, чтобы выполнить код обработчика прерывания от АЦП? Да ещё при включенных вложенных прерываниях? На мой взгляд, включение прерываний в обработчике - это обращение к тёмной стороне силы, джедаи так не делают sm.gif
pokk
Обработчик АЦП успевает выполнится В AVR studio пробегался там было максимум 200 а так в основном около 100(это был другой код там было 6 каналов и обработка их ). А вот на счёт таймера не знаю там у меня программный 1-wire сидит а у него временные задержки маленькие. Хотя там всё на case сделано по идее должно быстро работать. Сейчас по пробую как-нибудь в таймере замерить время выполнения его.
demiurg_spb
Если мне не изменяет память, то после смены канала первое преобразование надо выкидывать, т.к. оно не валидно.
Я конечно могу путать и вводить вас в заблуждение, но что-то такое всплывает на задворках памяти.
Еще не так давно Сергей Борщь говорил, что все траблы с АЦП AVR идут из-за несоответствия электрических характеристик схемы включения параметрам, указанным в даташите.
Превышен входной-выходной ток или ёмкость на аналоговых пинах... В общем почитайте даташит внимательно ещё раз.
RabidRabbit
Цитата(demiurg_spb @ Sep 18 2014, 10:36) *
Если мне не изменяет память, то после смены канала первое преобразование надо выкидывать, т.к. оно не валидно.

Путаете, у Вас смешалось:
1. First Analog Comparator conversion may be delayed
If the device is powered by a slow rising VCC, the first Analog Comparator conversion will
take longer than expected on some devices.
Problem Fix/Workaround
When the device has been powered or reset, disable then enable theAnalog Comparator
before the first conversion.

и
The value of these bits selects which combination of analog inputs are connected to the ADC.
These bits also select the gain for the differential channels. See Table 98 for details. If these bits
are changed during a conversion, the change will not go in effect until this conversion is
complete (ADIF in ADCSRA is set).

Я бы всё же не заморачивался с FreeRunning, а ценой некоторого снижения sample rate воспользовался одиночными преобразованиями с переключением канала в обработчике и потом в том же обработчике запуск преобразования.
Genadi Zawidowski
Цитата
с переключением канала в обработчике и потом в том же обработчике запуск преобразования.


Для ATMega я делал - в режиме с ручным запуском, после переключения мультиплексора для простоты одно преобразование выбрасывается. Неэкономно по времени, зато гарантировано (преобразование длится дольше чем время, которое по даташиту требуется выждать после переключения). Зато, нет задержек в прерывании.
CODE
static uint_fast8_t adc_state;
enum
{
ADCST_SETADDRESS,
ADCST_CONVERSION
};

ISR(ADC_vect)
{
switch (adc_state)
{
case ADCST_SETADDRESS:
(void) ADCH; // на этом цикле игнорируем результат
adc_state = ADCST_CONVERSION; // на следующем прерывании - используем результат и устанавливаем след. адрес
ADCSRA |= (1U << ADSC); // Start the AD conversion
break;

case ADCST_CONVERSION:
// на этом цикле используем результат
#if HARDWARE_ADCBITS == 8
// Read the 8 most significant bits
// of the AD conversion result
hardware_set_adc_data(adcinputs [adc_input], ADCH);
#else
// Read the AD conversion result
hardware_set_adc_data(adcinputs [adc_input], ADCW);
#endif
// Select next ADC input
if (++ adc_input >= ADCINPUTS_COUNT)
{
spool_adcdonebundle();
}
else
{
// Select next ADC input
ADMUX = adcinputs [adc_input] | ATMEGA_ADC_VREF_TYPE;
adc_state = ADCST_SETADDRESS; // на следующем прерывании - игнорируем результат
ADCSRA |= (1U << ADSC); // Start the AD conversion
}
break;
}
}
pokk
В общем замерил осциллографом время выполнения обработчика АЦП с разрешёнными прерываниями получилось что колеблется от 357 тактов до 588.
Genadi Zawidowski, у меня нету не каких задержек а АЦП. Я выставляю mux за одну итерацию преобразования, думаю что возможно в этом и есть косяк но не понятно почему он прыгает то есть то нету.
Genadi Zawidowski
А АЦП у Вас точно остановлен в момент преключения мультиплексора?

Перечитал ещё раз даташит... Получается, что не надо ждать после переключения мультиплексора в single-ended включении и режиме однократного преобразования?
pokk
Я понял из документации что АЦП работает так (если не правильно поправте меня)

Изначально у нас инициализирован (подключен канала) I1 и установлен режим Free Running после первого входа в обработчик прерывания
выдерживаем паузу в два такта АЦП( на обновление регистров) и устанавливаем значение MUX на канал I2 далее идёт оцифровка значения I1. Так как MUX изменили в процессе преобразовании то судя по даташиту канал переключится на последнем такте преобразования (т.е при входе в следующий обработчик во время первых двух тактов). по этому после второго входа в обработчик прерывания в регистрах ADCW будет значение соответствующее I1 и будет дан старт на переключение каналов I2 и оцифровку.

Пока это всё писал пару раз переосмыслил как это всё работает и походу запутался.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.