|
|
  |
ОДнократное преобразование в ATMEGA8 |
|
|
|
May 18 2006, 14:33
|
Частый гость
 
Группа: Свой
Сообщений: 83
Регистрация: 17-05-06
Пользователь №: 17 190

|
Вот пример программы: Код 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) { } } В принципе все понятно, но как мне сделать однократное преобразование по команде ?
|
|
|
|
|
May 18 2006, 15:54
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
одиночное преобразование можно и без прерываний обойтись: Код #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); ... Задержка внутри обработчика прерывания, тем более не маленькая это если мягко сказать - "не по спортивному". Лучше так никогда не делать.
|
|
|
|
|
May 18 2006, 16:44
|
Частый гость
 
Группа: Свой
Сообщений: 185
Регистрация: 5-05-06
Из: Ekaterinburg, Russia
Пользователь №: 16 821

|
Цитата lcd_clear(); sprintf(lcd_buffer,"%imV",(temp*5-temp/10)); lcd_puts(lcd_buffer); Лучше все это вынести в while. Цитата В принципе все понятно, но как мне сделать однократное преобразование по команде ? В том же while при появлении команды запускать преобразование АЦП. А какая сложность (или я чего-то не понимаю)?
--------------------
Чудес не бывает - бывает мало знаний и опыта!
|
|
|
|
|
May 18 2006, 17:20
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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
|
|
|
|
|
May 18 2006, 19:42
|
Частый гость
 
Группа: Свой
Сообщений: 83
Регистрация: 17-05-06
Пользователь №: 17 190

|
Сделал. Компилятор не ругается. Но в ходе отладки установлено, что программа виснет в цикле 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. ПРошу прощения, если кому мои вопросы покажутся глупыми.
|
|
|
|
|
May 18 2006, 20:43
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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).
|
|
|
|
|
May 18 2006, 20:51
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата 1. Для чего необходима установка частоты АЦП? Правильно ли я думаю, чтоэ АЦП работает как отдельный блок, помещая результат в регистр, из которого мы читаем впоследсвии? Или же АЦП спит, а когда мы ставим бит в ADSC он включается, конвертирует, возвращает результат? ТОгда в этом случает непонятно для чего нужен этот параметр - частота. В Мегах(и большинстве других МК) АЦП последовательного приближения - т.е. набираеться код на ЦАП и сравниваеться с входным напряжением с помощью компаратора (схема на странице 193),естественно сразу код подобрать нельзя поэтому он вдвигаеться в хитрый регистр обозначенный на схеме как CONVERSION LOGIC. Для этого нужно некоторое количество тактовых импульсов.Подробнее об том можно почитать в книжках по аналоговой технике. Частота выбираеться из соображений компромиса между быстордействием и точностью.(Чем больше время тем ближе будет напряжение на входном конденсаторе к истинному напряжению на входе). Сам АЦП представляет из себя автомат управляемый внутренней логикой т.е срабатывает триггер, АЦП выполняет заданную последовательность операций - выборка - подбор кода - выдача в регистр и устанавливает бит готовности. Если стоит режим Free Running, каждое новое преобразование начинаеться по завершению предыдущего (как бы генерит прерывание сам для себя). Насчет VREF - в большинстве случаев достаточно внутреннего источника, т.к. АЦП 10-битный и годиться скорее очень для оценки питающих напряжений, температуры, аналоговых органов упраления, а не для точных измерений. В таких случаюх лучще применять специализированный кристалл.
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
May 19 2006, 03:26
|
Частый гость
 
Группа: Свой
Сообщений: 83
Регистрация: 17-05-06
Пользователь №: 17 190

|
ОК. Спасибо! Более или менее разобрался. Заменил, как предложил Defunct - программа не виснет. ПРоблема пока только в проверке результатов - вывести некуда ))). Моя задача - я уже писал в соседней теме -фотореле. От ацп большой точности не требуется - надо лишь отличить 0,05-0,15 В от 1-1,5 вольт. Я вначале решил использовать компаратор. ОДнако, так как конечно устройство собираюсь проектировать на ATTiny13 (сейчас с мега8 ковыряюсь, потому что макетка на нем собрана). При использоваии компаратора необходимо задействовть 2 линии - в тини13 их 6 и мне как раз одной не хватает. Поэтому я решил использовать АЦП. Контроллер должен зажечь лазер, после этого снять показания через АЦП с фотодиода, и только после этого лазер выключается. Т.Е. Цитата то за время одиночного преобразования сигнал на входе может многократно измениться и результат преобразования получится недостоверным мне не грозит. Внутренний опорник в случае tiny13 - единственный вариант. Но у него напряжение 2,5 вольт. Не сгорит ли он если на него подать напряжение равное напряжению питания?
|
|
|
|
|
May 19 2006, 06:38
|
Местный
  
Группа: Свой
Сообщений: 232
Регистрация: 22-02-06
Из: Воронеж
Пользователь №: 14 589

|
Цитата(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; Успехов.
Сообщение отредактировал otrog - May 19 2006, 06:50
--------------------
Истина рождается в спорах; но когда страсти кипят, истина испаряется.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|