Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ОДнократное преобразование в ATMEGA8
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
virtuality
Вот пример программы:
Код
char lcd_buffer[33];    
int temp=0;

#asm
    .equ __lcd_port=0x18
#endasm
#include<lcd.h>
#include<stdio.h>
#include <90s8535.h>
#include <delay.h>

#define ADC_VREF_TYPE 0x00

interrupt [ADC_INT] void adc_isr(void)
{
temp=ADCW;
delay_ms(20);
ADCSR|=0x40;
     lcd_clear();
     sprintf(lcd_buffer,"%imV",(temp*5-temp/10));
     lcd_puts(lcd_buffer);    
}

void main(void)
{


ADCSR=0x8E;
#asm("sei")
ADMUX=0;

ADCSR|=0x40;
lcd_init(16);
    while (1)
       {
       }
      
}



В принципе все понятно, но как мне сделать однократное преобразование по команде ?
defunct
одиночное преобразование можно и без прерываний обойтись:

Код
#define ADC_EN_MASK  (1 << ADEN)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)  

int ReadAdc(void)
{
   ADCSRA = ADC_EN_MASK|(1 << ADSC);
   while ( ADCSRA & (1 << ADIF) );
   return ADCW;
}



Цитата
interrupt [ADC_INT] ....
...
delay_ms(20);
...

Задержка внутри обработчика прерывания, тем более не маленькая это если мягко сказать - "не по спортивному". Лучше так никогда не делать.
virtuality
А где в вашем коде выбор канала? Или он по умлочанию равен нулю?
Yura_K
Цитата
lcd_clear();
sprintf(lcd_buffer,"%imV",(temp*5-temp/10));
lcd_puts(lcd_buffer);

Лучше все это вынести в while.
Цитата
В принципе все понятно, но как мне сделать однократное преобразование по команде ?

В том же while при появлении команды запускать преобразование АЦП. А какая сложность (или я чего-то не понимаю)?
virtuality
Yura_K,

простите, но я полный лох. Очень понятный и конкретный код привел defunct, но если компилятор отказывается принимать ADEN и ADIF, я ничего не могу поделать, кроме как снова обратиться за разъяснением. Чтение мануалов не помогло. В них все удивительно складно.
WHALE
вы пишите,что работаете с мега8,а подключаете #include <90s8535.h>-очепятка?
а чтобы прошел код defunct,добавьте(лучше в хидер)
#define ADEN 7
#define ADPS0 0
#define ADPS1 1
#define ADPS2 2
#define ADIF 4
Удачи!
defunct
Цитата(virtuality @ May 18 2006, 19:20) *
А где в вашем коде выбор канала? Или он по умлочанию равен нулю?

Выбор канала можете разместить там же где он у Вас сейчас (в main).

А насчет ADIF, ADEN и ADSC
не знаю как в CodeVision подключить названия битов (в IAR это делается с помощью General Options -> System -> Enable bit definitions in I/O include files)

Но это не беда даже если в CV этого нет,
можно самостоятельно описать номера бит руководствуясь даташитом (описание регистра ADCSRA)

Код
#define ADEN  7
#define ADSC  6
#define ADATE 5
#define ADIF  4
#define ADIE  3
#define ADPS2 2
#define ADPS1 1
#define ADPS0 0
virtuality
Сделал. Компилятор не ругается. Но в ходе отладки установлено, что программа виснет в цикле while ( ADCSRA & (1 << ADIF) );

Стал я дальше ковырять.
Ну вот это мне совсем не понятно...
Залез я в генератор кода в CodeVision. Сгенерировал.
Установил источником опорного напряжения AVCC.
В коде появилась такая строчка : #define ADC_VREF_TYPE 0x40

ОДнако ниже есть еще вот что: ADMUX=ADC_VREF_TYPE;

Что же это получается.... Я думал что ADMUX - это номер канала ADC0,
ADC1... То есть тот пин, куда подается измеряемое напряжение.

Так... надо подучить матчасть. Почитал я все что нашел на эту тему,
некоторые моменты остались непонятны. Если несложно проясните их для меня.


1. Для чего необходима установка частоты АЦП? Правильно ли я думаю, чтоэ
АЦП работает как отдельный блок, помещая результат в регистр, из которого мы читаем впоследсвии?
Или же АЦП спит, а когда мы ставим бит в ADSC он включается, конвертирует, возвращает результат?
ТОгда в этом случает непонятно для чего нужен этот параметр - частота.

2. Источник опорного напряжения. Что надо сделать? Подключить к плюсу AREF и AVCC? И что лучше выбрать потом - AREF или внутренний опорник?


P.S. ПРошу прощения, если кому мои вопросы покажутся глупыми.
defunct
Цитата(virtuality @ May 18 2006, 22:42) *
Сделал. Компилятор не ругается. Но в ходе отладки установлено, что программа виснет в цикле while ( ADCSRA & (1 << ADIF) );

Прошу прощения, ошибся:

while ( (ADCSRA & (1 << ADIF))==0 ) ;


Цитата
ОДнако ниже есть еще вот что: ADMUX=ADC_VREF_TYPE;



ADC_VREF_TYPE = 0x0; // ARef
ADC_VREF_TYPE = 0x40; // AVcc
ADC_VREF_TYPE = 0xC0; // internal ref

Вам сгодится последний 0xC0 (при этом Pin ARef нужно оставить неподключенным),
про ADMUX написано на стр. 202-203.

Цитата
1. Для чего необходима установка частоты АЦП?

Для того чтобы обеспечить оптимальное время преобразования взависимости от кварца.
Если установить частоту преобразования сильно низкую, то за время одиночного преобразования сигнал на входе может многократно измениться и результат преобразования получится недостоверным. Если же частоту преобразования поставить сильно высокую, АЦП также даст неверный результат. Необходимо подбирать предделитель, который задается битами ADPS2..0 регистра ADCSRA так, чтобы частота преобразования была в районе 100-150 khz (10-15ksps).
beer_warrior
Цитата
1. Для чего необходима установка частоты АЦП? Правильно ли я думаю, чтоэ
АЦП работает как отдельный блок, помещая результат в регистр, из которого мы читаем впоследсвии?
Или же АЦП спит, а когда мы ставим бит в ADSC он включается, конвертирует, возвращает результат?
ТОгда в этом случает непонятно для чего нужен этот параметр - частота.


В Мегах(и большинстве других МК) АЦП последовательного приближения - т.е. набираеться код на ЦАП и сравниваеться с входным напряжением с помощью компаратора (схема на странице 193),естественно сразу код подобрать нельзя поэтому он вдвигаеться в хитрый регистр обозначенный на схеме как CONVERSION LOGIC. Для этого нужно некоторое количество тактовых импульсов.Подробнее об том можно почитать в книжках по аналоговой технике.
Частота выбираеться из соображений компромиса между быстордействием и точностью.(Чем больше время тем ближе будет напряжение на входном конденсаторе к истинному напряжению на входе).
Сам АЦП представляет из себя автомат управляемый внутренней логикой т.е срабатывает триггер, АЦП выполняет заданную последовательность операций - выборка - подбор кода - выдача в регистр и устанавливает бит готовности. Если стоит режим Free Running,
каждое новое преобразование начинаеться по завершению предыдущего (как бы генерит прерывание сам для себя).

Насчет VREF - в большинстве случаев достаточно внутреннего источника, т.к. АЦП 10-битный и годиться скорее очень для оценки питающих напряжений, температуры, аналоговых органов упраления, а не для точных измерений. В таких случаюх лучще применять специализированный кристалл.
virtuality
ОК. Спасибо! Более или менее разобрался. Заменил, как предложил Defunct - программа не виснет. ПРоблема пока только в проверке результатов - вывести некуда ))).

Моя задача - я уже писал в соседней теме -фотореле. От ацп большой точности не требуется - надо лишь отличить 0,05-0,15 В от 1-1,5 вольт. Я вначале решил использовать компаратор. ОДнако, так как конечно устройство собираюсь проектировать на ATTiny13 (сейчас с мега8 ковыряюсь, потому что макетка на нем собрана). При использоваии компаратора необходимо задействовть 2 линии - в тини13 их 6 и мне как раз одной не хватает. Поэтому я решил использовать АЦП.

Контроллер должен зажечь лазер, после этого снять показания через АЦП с фотодиода, и только после этого лазер выключается. Т.Е.
Цитата
то за время одиночного преобразования сигнал на входе может многократно измениться и результат преобразования получится недостоверным
мне не грозит.

Внутренний опорник в случае tiny13 - единственный вариант. Но у него напряжение 2,5 вольт. Не сгорит ли он если на него подать напряжение равное напряжению питания?
WHALE
опорник точно не сгорит,ему все равно,что на входе ацп.и вход ацп не сгорит тоже,Uпитания для него норма.но все,что выше опорного напряжения,вы не увидите,поэтому лучше выберите в качестве опорного напряжения питания и подключите конденсатор на вывод Aref.
otrog
Цитата(virtuality @ May 19 2006, 07:26) *
надо лишь отличить 0,05-0,15 В от 1-1,5 вольт.
.......................
Но у него напряжение 2,5 вольт.

У Вас диапазон входного напряжения как раз лежит ниже напряжения внутреннего опорника, так что все будет работать. А если на входе будет напряжение выше Uоп, но ниже Uпит, то на выходе АЦП будет число 1023. Только и всего - ничего не сгорит.

PS Кстати на чем пишите? У меня CodeWizard от CodeVision выдал следующюю заготовку:
[code]#include <mega8.h>

#define ADC_VREF_TYPE 0xC0

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE;
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}


// Declare your global variables here

void main(void)
{
// Declare your local variables here
// ..................................................................
// ADC initialization
// ADC Clock frequency: 500,000 kHz
// ADC Voltage Reference: Int., cap. on AREF
ADMUX=ADC_VREF_TYPE;
ADCSRA=0x81;

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