реклама на сайте
подробности

 
 
> ATmega128 проблема переключения каналов АЦП, проскок данных из соседнего канала
pokk
сообщение Sep 18 2014, 00:33
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028



Здравствуйте, не как не могу разобраться с данной проблемой.
Ацп работает в режиме автоматического перезапуска с частотой 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;
}


Сообщение отредактировал IgorKossak - Sep 19 2014, 15:02
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Genadi Zawidowsk...
сообщение Sep 18 2014, 08:54
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Цитата
с переключением канала в обработчике и потом в том же обработчике запуск преобразования.


Для 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;
}
}


Сообщение отредактировал IgorKossak - Sep 19 2014, 15:03
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 29th July 2025 - 20:39
Рейтинг@Mail.ru


Страница сгенерированна за 0.01388 секунд с 7
ELECTRONIX ©2004-2016