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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Переключение между каналами АЦП, ATmega32
B_Sergey_N
сообщение Sep 28 2008, 18:41
Сообщение #1


Участник
*

Группа: Новичок
Сообщений: 17
Регистрация: 28-07-08
Из: г. Санкт-Петербург
Пользователь №: 39 246



Всем привет.
Как можно переключаться между каналами АЦП? К примеру, мне необходимо:
сделать преобразование, прочитать один канал (Vbg), затем опять сделать преобразование и прочитать канал ADC0.

Выкладываю код, переключения между каналами не происходит.

Код
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000

int i, flag, t;

void main(void)
{

DDRA |= (1 << 1)|(1 << 2)|(1 << 6)|(1 << 7);         // Инициализация светодиодов

ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Установка частоты преобразования 125KHz

ADCSRA |= (1 << ADEN);              // Вкл. АЦП

ADCSRA |= (1 << ADIE);              // Разрешение прерывания от компаратора
sei();


    for(;;)
    {
        
    flag = 1;
    ADMUX |= (1 << 1)|(1 << 2)|(1 << 3)|(1 << 4);     // Выбор входного канала АЦП - Vbg
                ADCSRA |= (1 << ADSC);        // Запуск преобразования
        

                                flag = 0;
        ADMUX |= 0;             // Выбор входного канала АЦП - ADC0
        ADCSRA |= (1 << ADSC);        // Запуск преобразования
    }

}

//********************************************************************************//

ISR(ADC_vect)
{
        
         if (flag == 1)
            {
             i = ADCL;        // Чтение младших 8 битов первыми
             i += (int)ADCH << 8;    // Чтение старших 2 битов, умножение их на 256 и сложение с мл. б.
            
            if (i < 255)
            {
            // Питание контроллера падает
            _delay_ms(200);

            PORTA |= (1 << 6);
        
            _delay_ms(200);
        
            PORTA &= ~(1 << 6);
            }
            }

    
    if (flag == 0)
    {
        
    t = ADCL;        // Чтение младших 8 битов первыми
    t += (int)ADCH << 8;    // Чтение старших 2 битов, умножение их на 256 и сложение с мл. б.
        
        if (t < 830)
        {
        _delay_ms(200);

        PORTA |= (1 << 1);
        
        _delay_ms(200);
        
        PORTA &= ~(1 << 1);
        }
            
            else
            {
                
                _delay_ms(200);

                PORTA |= (1 << 2);
        
                _delay_ms(200);
        
                PORTA &= ~(1 << 2);
            }

    }


}


Не знаю, необходим ли reti из прерывания?
Go to the top of the page
 
+Quote Post
Николай Иванович...
сообщение Sep 28 2008, 19:02
Сообщение #2


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

Группа: Новичок
Сообщений: 139
Регистрация: 26-09-08
Пользователь №: 40 510



Не забывайте делать задержку после включения ADC битом ADEN на время затухания переходных процессов, задержку после переключения канала, необходимую для разряда Sample-Hold-ёмкости, чтобы избежать взаимовлияния каналов. Если же у Вас выходное сопротивление источника сигнала низкое то по-любому результаты первого после переключения канала АЦП лучше выбросить
Go to the top of the page
 
+Quote Post
smac
сообщение Sep 28 2008, 21:23
Сообщение #3


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

Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003



Цитата(B_Sergey_N @ Sep 28 2008, 22:41) *
...
Выкладываю код, переключения между каналами не происходит.


Я конечно не специалист в С, но
1. По-моему у Вас в основном цикле (тот что for) не происходит ожидания результата преобразования (прерывание не успевает вызваться), а сразу присваивается 0 переменной flag и далее следует переключение канала. К сожалению не скажу на память, что происходит если переключить канал не дожидась окончания преобразования, но уверен, что результат преобразования точно будет некорректным. Таким образом, при вызове прерывания в первый раз, скорее всего флаг уже равен 0, (далее распределение флага случайно) и канал уже переключен.
2. Использование больших задержек в прерывании (как минимум 2х200 мс) - это очень плохо.
3. Зачем соблюдать порядок чтения результата АЦП при написании программ на С? Как правило компилятор сам будет соблюдать порядок. Еслия не ошибаюсь прочитать результат можно так i=ADCW
4. По-моему (см. первую строку моего поста) компилятор сам заботится о корректном выходе из процедуры обработки прерывания, так что ставить reti самостоятельно, наверное, не стоит.

Сообщение отредактировал smac - Sep 28 2008, 21:24
Go to the top of the page
 
+Quote Post
SysRq
сообщение Sep 28 2008, 22:36
Сообщение #4


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



0) F_CPU следует определить в makefile, или до включения delay.h;
1) Здесь прерывание следует использовать лишь в том случае, если между запуском АЦ-преобразования и собстно его завершением вы занимаетесь какой-то другой полезной работой;
2) Прерывание будет срабатывать не по вашей задумке, т.к., как уже подметил smac, или необходимо ждать завершения текущего преобразования перед сменой флага и канала (просто ждать нельзя, см пункт 2 -- теряется целесообразность вообще прерывания), либо исключить ситуацию что флаг меняется до срабатывания прерывания (например, АЦ-преобразование по второму каналу пусть запускается из прерывания, после оконцания работы с 1-м каналом). Регистры АЦП-блока буферизуются (если идет АЦ-преобразование, то запись в регистры не повлияет на текущее преобразование), и таким образом у вас преобразование выполнится для одного канала, а результаты воспримутся как для другого...

Примерчик простой реализация преобразования без прерываний:
CODE

/* ATMega103 (128 with M103C programmed */

#define BIT(x) (1 << (x))

WORD DoADC(BYTE _ADMUX)
{
WORD value;

ADMUX = _ADMUX;

_delay_ms(250); // Wait till signals are stabilized

ADCSR |= BIT(ADSC); // Start conversion
while(ADCSR & BIT(ADSC)); // Wait till conversion done

*((BYTE *) &value) = ADCL; // Read lower byte
*(((BYTE *) &value) + 1) = ADCH; // Read higher byte

return value;
}

void GetVoltages(void)
{
ADCSR = BIT(ADEN) | BIT(ADSC) | BIT(ADPS2) | BIT(ADPS1) | BIT(ADPS0); // Enable ADC, start dummy conversion to init ADC
while(ADCSR & BIT(ADSC)); // Wait till dummy conversion done

voltage1 = DoADC(0x00); // AREF, single ended input - PORTF0
voltage2 = DoADC(BIT(MUX0)); // AREF, single ended input - PORTF1
voltage3 = DoADC(BIT(MUX1)); // AREF, single ended input - PORTF2
voltage4 = DoADC(BIT(MUX1) | BIT(MUX0)); // AREF, single ended input - PORTF3

ADCSR = 0; // disable ADC
}
Go to the top of the page
 
+Quote Post
domowoj
сообщение Sep 29 2008, 02:09
Сообщение #5


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

Группа: Участник
Сообщений: 1 548
Регистрация: 20-12-07
Из: г.Новосибирск
Пользователь №: 33 486



Я не силен в СИ, но после каждого ночала преобразования я бы "засыпал" -
ADC Noise Reduction - и преобр. точнее и наверняка.
И еще. Первое преобразование нужно делать "холостое".

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

Сообщение отредактировал domowoj - Sep 29 2008, 01:16


--------------------
И на камнях растут деревья!
Go to the top of the page
 
+Quote Post
VladimirYU
сообщение Sep 29 2008, 09:47
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782



Цитата(B_Sergey_N @ Sep 28 2008, 22:41) *
Всем привет.
Как можно переключаться между каналами АЦП? К примеру, мне необходимо:
сделать преобразование, прочитать один канал (Vbg), затем опять сделать преобразование и прочитать канал ADC0.

Выкладываю код, переключения между каналами не происходит.

[code]
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000

int i, flag, t;

void main(void)
{

.......

flag = 0;
[b]ADMUX |= 0; // Выбор входного канала АЦП - ADC0
ADCSRA |= (1 << ADSC); // Запуск преобразования
}

}


Может в этом и ничего страшного нет в Вашем случае, но в глаза бросилось.
Go to the top of the page
 
+Quote Post
hainiken
сообщение Oct 4 2008, 20:15
Сообщение #7


Участник
*

Группа: Новичок
Сообщений: 16
Регистрация: 4-10-08
Пользователь №: 40 693



по ДШ вроде 125 мкС мин. паузу рекомендуют, а напрактике чато делают "холостое" преобраование.
Go to the top of the page
 
+Quote Post
singlskv
сообщение Oct 4 2008, 20:38
Сообщение #8


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Николай Иванович Приходько @ Sep 28 2008, 23:02) *
Не забывайте делать задержку после включения ADC битом ADEN на время затухания переходных процессов,
Странно, а я думал что эта задержка уже включена в первое преобразование.
Цитата
задержку после переключения канала, необходимую для разряда Sample-Hold-ёмкости, чтобы избежать взаимовлияния каналов.
Не подскажите в какой момент времени после переключения канала в ADMUX,
соответствующий пин подключаеться к Sample-Hold ?
Цитата
Если же у Вас выходное сопротивление источника сигнала низкое то по-любому результаты первого после переключения канала АЦП лучше выбросить
А если выходное сопротивление ИСТОЧНИКА очень высокое, то первый результат верный ?


Цитата(domowoj @ Sep 29 2008, 06:09) *
АЦП можно переключать сразу после начала предыдущего преобр.
включится он по окончании предыдущего преобр.
А как Вы определяете начало очередного преобразования ?

Цитата(hainiken @ Oct 5 2008, 00:15) *
по ДШ вроде 125 мкС мин. паузу рекомендуют

125 мкС это требование при переключении только дифференциальных каналов.

2 B_Sergey_N
1.flag используется и в прерывании и в основной проге, исчем по форуму слово volatile
2. задержки по много мс в прерывании не есть хорошо
3. ADMUX |= 0; просто не меняет ничего
Go to the top of the page
 
+Quote Post
domowoj
сообщение Oct 5 2008, 14:22
Сообщение #9


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

Группа: Участник
Сообщений: 1 548
Регистрация: 20-12-07
Из: г.Новосибирск
Пользователь №: 33 486



УВХ начинает работать вместе с АЦП, на то оно и УВХ (или аналоговое запоминающее устройство)
и ему до лампочки что запоминать, а аналоговый MUX уже подал на вход сигнал (это по определению).
К тому же АЦП последовательного приближения начинает преобразование со старших разрядов.


--------------------
И на камнях растут деревья!
Go to the top of the page
 
+Quote Post
singlskv
сообщение Oct 5 2008, 15:47
Сообщение #10


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(domowoj @ Oct 5 2008, 18:22) *
УВХ начинает работать вместе с АЦП, на то оно и УВХ (или аналоговое запоминающее устройство)
и ему до лампочки что запоминать, а аналоговый MUX уже подал на вход сигнал (это по определению).
Не очень понял что Вы этим хотели сказать ? Что УВХ всегда подключен к какому-то пину ?
Или что после занесения значения в ADMUX соответствующий пин подключается к УВХ ?
Или что после ADCSRA |= (1 << ADSC); уже началось преобразование и можно
менять ADMUX ?

Разъясните что Вы имели в виду...
Go to the top of the page
 
+Quote Post
domowoj
сообщение Oct 5 2008, 16:21
Сообщение #11


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

Группа: Участник
Сообщений: 1 548
Регистрация: 20-12-07
Из: г.Новосибирск
Пользователь №: 33 486



На конденцаторе хранения УВХ напряж.запоминается в момент ADCSRA |= (1 << ADSC)
при этом ADMUX уже переключен на нужный канал.
Если же мультиплексор переключить после ADCSRA |= (1 << ADSC), то он пеключится после окончания
текущего преобразования.

И не нужно заботиться об времени установления входного аналогового сигнала при переключении мультиплексора, в любом случае времени для запоминания в УВХ хватит.


--------------------
И на камнях растут деревья!
Go to the top of the page
 
+Quote Post
singlskv
сообщение Oct 5 2008, 16:43
Сообщение #12


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(domowoj @ Oct 5 2008, 20:21) *
На конденцаторе хранения УВХ напряж.запоминается в момент ADCSRA |= (1 << ADSC)
при этом ADMUX уже переключен на нужный канал.
Если же мультиплексор переключить после ADCSRA |= (1 << ADSC), то он пеключится после окончания текущего преобразования.
Это не совсем так, реальный запуск преобразования начинается не в момент
подачи ADCSRA |= (1 << ADSC), а через некоторое время после этого.
Это время зависит от выбранного прескейлера и от времени начального включения АЦП битом ADEN.
Те если по-простому, АЦП запустится через 0 - (N-1) тактов проца после ADCSRA |= (1 << ADSC),
где N - это прескайлер АЦП. То есть переключение каналов безопасно делать только
после реального начала преобразования.
Go to the top of the page
 
+Quote Post
B_Sergey_N
сообщение Oct 5 2008, 17:31
Сообщение #13


Участник
*

Группа: Новичок
Сообщений: 17
Регистрация: 28-07-08
Из: г. Санкт-Петербург
Пользователь №: 39 246



Большое спасибо всем за ответы!!! Особенно спасибо SysRq, я воспользовался его предложением.
Все-таки на мой взгляд без прерываний жить легче =). Вечно у меня с ними какие-то проблемы! ))
Go to the top of the page
 
+Quote Post
rudy_b
сообщение Oct 5 2008, 18:23
Сообщение #14


Знающий
****

Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458



Что-то я не понимаю, вы про какой проц говорите? Если записать новое значение в мультиплексор в процессе преобразования, оно запомнится, но реально занесется в регистр мультиплексора только на последнем такте. И нельзя переписывать мультиплексор сразу после запуска, нужно, чтобы прошел хотя-бы один такт АЦП.
Там есть только одно противное место. Если для измерения на разных каналах используются разные источники Uref, то при переключении их следует дожидаться перезаряда емкости фильтра Uref, иначе получите ерунду.

Сообщение отредактировал rudy_b - Oct 5 2008, 18:26
Go to the top of the page
 
+Quote Post
singlskv
сообщение Oct 5 2008, 18:34
Сообщение #15


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(rudy_b @ Oct 5 2008, 22:23) *
Что-то я не понимаю, вы про какой проц говорите? Если записать новое значение в мультиплексор в процессе преобразования, оно запомнится, но реально занесется в регистр мультиплексора только на последнем такте. И нельзя переписывать мультиплексор сразу после запуска, нужно, чтобы прошел хотя-бы один такт АЦП.
Там есть только одно противное место. Если для измерения на разных каналах используются разные источники Uref, то при переключении их следует дожидаться перезаряда емкости фильтра Uref, иначе получите ерунду.
Мысль высказанная про отсутствие УВХ в AVR была свежей... smile.gif
Но Вы быстро исправились, а в остальном логика работы примерно как Вы и описали.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th June 2025 - 14:19
Рейтинг@Mail.ru


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