Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: mega88PA и АЦП в Free Running mode
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
arttab
в режиме одиночного преобразования АЦП выдает нормальные значения, а после переделки проги на постоянное преобразование (пока не запретишь) получаю FF. прерывания АЦП выкл.

опора АЦП от встроенного в мк опорника 1.1В

делаю так:

__disable_interrupt();

установки АЦП:
ADMUX = (1<<REFS0)|(1<<REFS1)|(0<<MUX0)|(0<<MUX1)|(0<<MUX2)|(0<<MUX3)|(1<<ADLAR);
ADCSRA =(1<<ADEN)|(1<<ADPS0)|(0<<ADPS1)|(0<<ADPS2); //|(1<<ADATE) //2for1MHz 001
ADCSRB = (0<<ACME)&(0<<ADTS2)&(0<<ADTS1)&(0<<ADTS0);

задержка на устаканивание:
for (unsigned char z=0; z<10; z++){
__delay_cycles(350000/8/10*F_MHZ); //
WATCHDOG_RESET;}


SETBIT(DDRB, 6); // для отладки ножкой буду дрыгать

SETBIT (ADCSRA, _ADC_Start); // запускаю АЦП

ADC_CONTROL_auto(); // Жду результата
//
unsigned char ADC_CONTROL_auto(void)
{
SETBIT(PORTB, 6); // Çàïóñê ÀÖ ïðåîáðàçîâàíèÿ;
while( !TSTBIT(ADCSRA, _ADC_Flag)); // Îæèäàíèå ôëàãà ïðåðûâàíèÿ - îêîí÷àíèÿ ïðåîáðàçîâàíèÿ;
CLRBIT(PORTB, 6);
return ADCH; // ×òåíèå ðåçóëüòàòà ïðåîáðàçîâàíèÿ;
}
//

// И делаю выборку значеий
for (char j = 0; j <_NUMB_OF_MEG; j++)
{
res_of_meg[j] = ADC_CONTROL_auto(); // Ìàññèâ èçìåðåííîãî çíà÷åíèÿ êàëèáðîâêè //
}


выключаю АЦП
ADCSRA = 0<<ADEN;


переделывал на одиночные режим работы - все ок. сигнал меняю - отчеты идут нормальные, а так FF только


есть errata но она при вкл. компоратора (я его использую в др. части проги), а я перед каждым использованием АЦП конфигурю АЦП.

что у меня с "лыжами"? почему не едут? wacko.gif
Сергей Борщ
QUOTE (arttab @ Apr 18 2011, 07:38) *
прерывания АЦП выкл.
В этом случае надо принудительно сбрасывать ADIF записью в него единицы после чтения результата. Правда не понимаю, как его не сбрасывание может приводить к чтению FF - по идее, у вас просто буфер должен заполниться результатом первого измерения.
arttab
спасибо. завтра попробую.
hd44780
CvAVR предлагает вот такой код:

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
arttab
вы уверены что это free runтing режим, а не одиночное преобразование с ручным запуском?

в русском переводе нашел что нужно вычитывать оба регистра результата, причем младший первым.

еще поковыряюсь по этому вопросу.
Палыч
Цитата(arttab @ Apr 20 2011, 08:22) *
в русском переводе нашел что нужно вычитывать оба регистра результата, причем младший первым.
Для двухбайтных регистров, обычно, есть три определения: младший (L), старший (H) и словный (W или "пусто").
Цитата(hd44780 @ Apr 18 2011, 14:22) *
return ADCW;
В этом случае транслятор сам разбирается с порядком чтения/записи.
arttab
получилось при такой инициализации:

void ADC_init_prescaler_on_2_auto(void)
{
ADMUX = (1<<REFS0)|(1<<REFS1)|(0<<MUX0)|(0<<MUX1)|(0<<MUX2)|(0<<MUX3)|(1<<ADLAR); //was chanel 011. just 000

ADCSRB = (0<<ACME)&(0<<ADTS2)&(0<<ADTS1)&(0<<ADTS0);
ADCSRA = (1<<ADATE);
ADCSRA |=(1<<ADEN)|(1<<ADPS0)|(0<<ADPS1)|(0<<ADPS2); //2for1MHz 001 деление тактирующей частоты на 16;
}

обработчик:
#pragma optimize=none
unsigned char ADC_CONTROL_auto(void)
{
unsigned char t;
SETBIT(PORTB, 6); // Запуск АЦ преобразования;
while( !TSTBIT(ADCSRA, _ADC_Flag)); // Ожидание флага прерывания - окончания преобразования;
CLRBIT(PORTB, 6);
t= ADCL;
return ADCH;
Сергей Борщ
QUOTE (arttab @ Apr 20 2011, 10:56) *
получилось при такой инициализации:
1) Совершенно непонятно, зачем взводить ADATE отдельной командной.
2) Чтение ADCL излишне.
QUOTE
Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH.

3) А ADIF вы все же не сбрасываете. Что получилось в результате - непонятно, но явно не то, чего вы ожидатете.
QUOTE
ADIF is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, ADIF is cleared by writing a logical one to the flag.

Ну и запуск преобразования происходит совсем не в том месте, где стоит соответствующий комментарий.
=GM=
Цитата(arttab @ Apr 20 2011, 06:56) *
получилось при такой инициализации:
ADCSRA = (1<<ADATE);
ADCSRA |=(1<<ADEN)|(1<<ADPS0)|(0<<ADPS1)|(0<<ADPS2); //2for1MHz 001 деление тактирующей частоты на 16;

Непонятно, как вам удалось запустить ацп. Для запуска первого преобразования во free running mode надо бы установить бит ADSC в регистре ADCSRA. Ну и ADIF надо сбрасывать ручками после каждого преобразования.
Index
arttab !!! ИЗВИНИ !!! что в твоей теме вопрос задаю, но..

У меня проблема с АЦП на девайсе ATmega328P. Не запускаются непрерывные преобразования АЦП, ни free running, ни от Timer0 Overflow. Одиночные, это пожалуста.

Инициализировал так:

ldi r16, (0<<REFS1)|(1<<REFS0)|(0<<ADLAR)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0)
ldi r17, (0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0)
ldi r18, (1<<ADEN)|(0<<ADSC)|(1<<ADATE)|(0<<ADIF)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)

sts ADMUX, r16
sts ADCSRB, r17
sts ADCSRA, r18

Первое преобразование запускал так:

lds r16, ADCSRA
sbr r16, (1<<ADSC)
sts ADCSRA, r16

Первое преобразование заканчивается, вызывается обработчик прерывания АЦП, флаг прерывания АЦП сбрасывается аппаратно и ... все больше обработчик по окончании нового преробразования не вызывается, а следовательно новое преобразование и не запускается автоматически.

Что делать?
=GM=
При первом запуске попробуйте после чтения регистра ADCSRA
lds r16, ADCSRA

очистить ADIF (бит 4) в регистре r16, потом завершите остальное

sbr r16, (1<<ADSC)
sts ADCSRA, r16
Index
=GM=
хорошо, попробую

Пока выход такой .. в обработчике прерывания о таймера (Timer0 Overflow) вручную запускаю новое преобразование установкой бита ADSC.



Fusion
Инициализация АЦП для меги 644:
Код
adcinit:

; REFS1=1  REFS0=1 (Internal 2.56V Voltage Reference with external capacitor at AREF pin), ADLAR=1(Left), MUX = 0
ldi temp, (1<<REFS1) | (0<<REFS0) | (1<<ADLAR) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0)
sts ADMUX, temp

; ADEN=1(ADCenable), ADSC=1(Start), ADATE=1(Auto Trigger Enable) ADPS: 010 (/4; 5 mHz)
ldi temp,(1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (0<<ADPS2) | (1<<ADPS1) | (0 <<ADPS0)
sts ADCSRA, temp

ldi temp, 0b01000000; Free Running mode
sts ADCSRB, temp

ldi temp, 0b10000000; Digital Input Disable
sts DIDR0, temp

ret


Взято из рабочего проекта.
Free Running.
Результат забирается командой lds temp, ADCH.
Готовность Ацп не проверяется - просто задержка NOP.
defunct
Что-то я не пойму, какой смысл использовать ADC free-running режим без прерываний?
=GM=
То есть, без прерываний вообще не жизнь? И работать по флагу готовности ацп религия не позволяет.
Fusion
Это я максимально разгонял АЦП.
Мне всего 7 бит надо было для индикатора 176*132.
Получилось за 13 тактов при 20мГц тактовой процессора АЦП еще не сильно врет)
Даже флаг готовности не проверял - просто считывал в цикле и добавлял нопы до 13 тактов на результат.
Вот картинка видеосигнала период 64 мкс (всего 160 точек)
defunct
Цитата(=GM= @ Apr 21 2011, 18:51) *
То есть, без прерываний вообще не жизнь? И работать по флагу готовности ацп религия не позволяет.

Не хочу никого обидеть, но так работать - просто глупо.

Правильных пути всего два
1 - DMA
2 - прерывание

DMA в AVR нет, остается только один правильный путь.

Free-running он на то и free-running, АЦП себе что-то преобразует, как только результат готов, АЦП дает прерывание, читаем ADC, ADIF сбрасывается сам.
Таким образом постоянно имеем актуальное значение с АЦП при практически нулевых затратах ресурса CPU.

А что имеем при работе "по флагу"?
hd44780
Цитата(defunct @ Apr 22 2011, 02:18) *
А что имеем при работе "по флагу"?


Флаг готовности АЦП позволяет работать без прерываний АЦП. Например, когда надо считать АЦП в обработчике другого прерывания.

Я таким режимом иногда пользуюсь.
=GM=
Цитата(defunct @ Apr 21 2011, 22:18) *
А что имеем при работе "по флагу"?

По флагу получается минимальное время опроса, а можно и вообще без опроса работать. В одном проекте мне понадобилось максимально быстро провести несколько серий чтений ацп, по 10 в серии, с тем, чтобы минимизировать потребление, вот код
Код
  CLKPR=0x03;                    //Fclk/8
  rxmode();                      //wake up procedure
  ADCSRA=0x80;                    //ADEN,ADATE=0,Fosc/2
  for(delay=0;delay<127;delay++) asm volatile ("nop\n\t"::);
  ADCSRA |= _BV(ADSC);                //start of conversion
  for(i=0;i<10;i++)
  {
   for(delay=0;delay<4;delay++) asm volatile ("nop\n\t"::);
   adcval +=ADCW;                    //current ADC 10-bit sample
  }
  ADCSRA=0x00;                    //disable ADC
  stbmode();                    //of the receiver
  CLKPR=0x80;                    //clkpce=1

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