B_Sergey_N 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба Всем привет. Как можно переключаться между каналами АЦП? К примеру, мне необходимо: сделать преобразование, прочитать один канал (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 из прерывания? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Николай Иванович Приходько 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба Не забывайте делать задержку после включения ADC битом ADEN на время затухания переходных процессов, задержку после переключения канала, необходимую для разряда Sample-Hold-ёмкости, чтобы избежать взаимовлияния каналов. Если же у Вас выходное сопротивление источника сигнала низкое то по-любому результаты первого после переключения канала АЦП лучше выбросить Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
smac 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 (изменено) · Жалоба ... Выкладываю код, переключения между каналами не происходит. Я конечно не специалист в С, но 1. По-моему у Вас в основном цикле (тот что for) не происходит ожидания результата преобразования (прерывание не успевает вызваться), а сразу присваивается 0 переменной flag и далее следует переключение канала. К сожалению не скажу на память, что происходит если переключить канал не дожидась окончания преобразования, но уверен, что результат преобразования точно будет некорректным. Таким образом, при вызове прерывания в первый раз, скорее всего флаг уже равен 0, (далее распределение флага случайно) и канал уже переключен. 2. Использование больших задержек в прерывании (как минимум 2х200 мс) - это очень плохо. 3. Зачем соблюдать порядок чтения результата АЦП при написании программ на С? Как правило компилятор сам будет соблюдать порядок. Еслия не ошибаюсь прочитать результат можно так i=ADCW 4. По-моему (см. первую строку моего поста) компилятор сам заботится о корректном выходе из процедуры обработки прерывания, так что ставить reti самостоятельно, наверное, не стоит. Изменено 28 сентября, 2008 пользователем smac Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NullPointer 0 28 сентября, 2008 Опубликовано 28 сентября, 2008 · Жалоба 0) F_CPU следует определить в makefile, или до включения delay.h; 1) Здесь прерывание следует использовать лишь в том случае, если между запуском АЦ-преобразования и собстно его завершением вы занимаетесь какой-то другой полезной работой; 2) Прерывание будет срабатывать не по вашей задумке, т.к., как уже подметил smac, или необходимо ждать завершения текущего преобразования перед сменой флага и канала (просто ждать нельзя, см пункт 2 -- теряется целесообразность вообще прерывания), либо исключить ситуацию что флаг меняется до срабатывания прерывания (например, АЦ-преобразование по второму каналу пусть запускается из прерывания, после оконцания работы с 1-м каналом). Регистры АЦП-блока буферизуются (если идет АЦ-преобразование, то запись в регистры не повлияет на текущее преобразование), и таким образом у вас преобразование выполнится для одного канала, а результаты воспримутся как для другого... Примерчик простой реализация преобразования без прерываний: /* 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 } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
domowoj 0 29 сентября, 2008 Опубликовано 29 сентября, 2008 (изменено) · Жалоба Я не силен в СИ, но после каждого ночала преобразования я бы "засыпал" - ADC Noise Reduction - и преобр. точнее и наверняка. И еще. Первое преобразование нужно делать "холостое". Каналы АЦП можно переключать сразу после начала предыдущего преобр. включится он по окончании предыдущего преобр. Изменено 29 сентября, 2008 пользователем domowoj Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladimirYU 0 29 сентября, 2008 Опубликовано 29 сентября, 2008 · Жалоба Всем привет. Как можно переключаться между каналами АЦП? К примеру, мне необходимо: сделать преобразование, прочитать один канал (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) { ....... flag = 0; [b]ADMUX |= 0; // Выбор входного канала АЦП - ADC0 ADCSRA |= (1 << ADSC); // Запуск преобразования } } Может в этом и ничего страшного нет в Вашем случае, но в глаза бросилось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
hainiken 0 4 октября, 2008 Опубликовано 4 октября, 2008 · Жалоба по ДШ вроде 125 мкС мин. паузу рекомендуют, а напрактике чато делают "холостое" преобраование. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 4 октября, 2008 Опубликовано 4 октября, 2008 · Жалоба Не забывайте делать задержку после включения ADC битом ADEN на время затухания переходных процессов,Странно, а я думал что эта задержка уже включена в первое преобразование. задержку после переключения канала, необходимую для разряда Sample-Hold-ёмкости, чтобы избежать взаимовлияния каналов.Не подскажите в какой момент времени после переключения канала в ADMUX, соответствующий пин подключаеться к Sample-Hold ? Если же у Вас выходное сопротивление источника сигнала низкое то по-любому результаты первого после переключения канала АЦП лучше выброситьА если выходное сопротивление ИСТОЧНИКА очень высокое, то первый результат верный ? АЦП можно переключать сразу после начала предыдущего преобр. включится он по окончании предыдущего преобр. А как Вы определяете начало очередного преобразования ? по ДШ вроде 125 мкС мин. паузу рекомендуют 125 мкС это требование при переключении только дифференциальных каналов. 2 B_Sergey_N 1.flag используется и в прерывании и в основной проге, исчем по форуму слово volatile 2. задержки по много мс в прерывании не есть хорошо 3. ADMUX |= 0; просто не меняет ничего Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
domowoj 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба УВХ начинает работать вместе с АЦП, на то оно и УВХ (или аналоговое запоминающее устройство) и ему до лампочки что запоминать, а аналоговый MUX уже подал на вход сигнал (это по определению). К тому же АЦП последовательного приближения начинает преобразование со старших разрядов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба УВХ начинает работать вместе с АЦП, на то оно и УВХ (или аналоговое запоминающее устройство) и ему до лампочки что запоминать, а аналоговый MUX уже подал на вход сигнал (это по определению). Не очень понял что Вы этим хотели сказать ? Что УВХ всегда подключен к какому-то пину ? Или что после занесения значения в ADMUX соответствующий пин подключается к УВХ ? Или что после ADCSRA |= (1 << ADSC); уже началось преобразование и можно менять ADMUX ? Разъясните что Вы имели в виду... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
domowoj 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба На конденцаторе хранения УВХ напряж.запоминается в момент ADCSRA |= (1 << ADSC) при этом ADMUX уже переключен на нужный канал. Если же мультиплексор переключить после ADCSRA |= (1 << ADSC), то он пеключится после окончания текущего преобразования. И не нужно заботиться об времени установления входного аналогового сигнала при переключении мультиплексора, в любом случае времени для запоминания в УВХ хватит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба На конденцаторе хранения УВХ напряж.запоминается в момент ADCSRA |= (1 << ADSC) при этом ADMUX уже переключен на нужный канал. Если же мультиплексор переключить после ADCSRA |= (1 << ADSC), то он пеключится после окончания текущего преобразования. Это не совсем так, реальный запуск преобразования начинается не в момент подачи ADCSRA |= (1 << ADSC), а через некоторое время после этого. Это время зависит от выбранного прескейлера и от времени начального включения АЦП битом ADEN. Те если по-простому, АЦП запустится через 0 - (N-1) тактов проца после ADCSRA |= (1 << ADSC), где N - это прескайлер АЦП. То есть переключение каналов безопасно делать только после реального начала преобразования. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
B_Sergey_N 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба Большое спасибо всем за ответы!!! Особенно спасибо SysRq, я воспользовался его предложением. Все-таки на мой взгляд без прерываний жить легче =). Вечно у меня с ними какие-то проблемы! )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 2 5 октября, 2008 Опубликовано 5 октября, 2008 (изменено) · Жалоба Что-то я не понимаю, вы про какой проц говорите? Если записать новое значение в мультиплексор в процессе преобразования, оно запомнится, но реально занесется в регистр мультиплексора только на последнем такте. И нельзя переписывать мультиплексор сразу после запуска, нужно, чтобы прошел хотя-бы один такт АЦП. Там есть только одно противное место. Если для измерения на разных каналах используются разные источники Uref, то при переключении их следует дожидаться перезаряда емкости фильтра Uref, иначе получите ерунду. Изменено 5 октября, 2008 пользователем rudy_b Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 5 октября, 2008 Опубликовано 5 октября, 2008 · Жалоба Что-то я не понимаю, вы про какой проц говорите? Если записать новое значение в мультиплексор в процессе преобразования, оно запомнится, но реально занесется в регистр мультиплексора только на последнем такте. И нельзя переписывать мультиплексор сразу после запуска, нужно, чтобы прошел хотя-бы один такт АЦП. Там есть только одно противное место. Если для измерения на разных каналах используются разные источники Uref, то при переключении их следует дожидаться перезаряда емкости фильтра Uref, иначе получите ерунду. Мысль высказанная про отсутствие УВХ в AVR была свежей... :) Но Вы быстро исправились, а в остальном логика работы примерно как Вы и описали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться