Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ADC Mega168. Измерение напряжения "наоборот".
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Буратино
Есть устройство с автономным питанием. Для того ,Чтоб не использовать ключей, делителей и прочей обвязки - измеряю напряжение на аккумуляторе по сл. алгоритму:

AREF = AVCC = Vbat
Данные АЦП: N = 1024*Vop/Vbat
т.е. Vbat = Vop*1024/N

вот инициализация ADC:
void adc_init(void)
{
ADMUX = (1<<REFS0)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1);
ADCSRB = 0x00;
ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0);
}


Вот прерывание:
#pragma vector= ADC_vect
__interrupt void ADC_vect_isr (void)
{
//conversion complete, read value (int) using...
value_ADC=ADCL; //Read 8 low bits first (important)
value_ADC|=(int)ADCH << 8; //read 2 high bits and shift into top byte
}



В тексте программы:
...
__disable_interrupt();adc_init();ADCSRA |= (1<<ADEN); __enable_interrupt();
DelayMs(5);
f_bat=(1.22*1024/value_ADC);
V_BAT=(f_bat*100);
__disable_interrupt();ADCSRA &= ~(1<<ADEN); __enable_interrupt();
...



не могу понять, почему иногда считает ADC неверно!? Где ошибка?
Я не использую никакой обвязки. То есть, на ногах проца имеющих отношение к преобразованию ничего не "висит". Может быть в этом проблема?
AVСС тоже в воздухе. Если измерять напряжение на этом выводе, то там меньше, чем на питании проца.
Сори за очередные глупые вопросы, но оч. нужна помощь. Спасибо.
rezident
Цитата(Буратино @ Jun 29 2009, 16:53) *
Я не использую никакой обвязки. То есть, на ногах проца имеющих отношение к преобразованию ничего не "висит". Может быть в этом проблема?
AVСС тоже в воздухе. Если измерять напряжение на этом выводе, то там меньше, чем на питании проца.
Все неиспользуемые пины должны быть настроены как GPIO с функцией вывода лог.0. AVCC нельзя отставлять неподключенным ни в коем случае! Либо напрямую к питанию подключить, либо через LC или RC-фильтр.
Буратино
Цитата(rezident @ Jun 29 2009, 16:14) *
Все неиспользуемые пины должны быть настроены как GPIO с функцией вывода лог.0. AVCC нельзя отставлять неподключенным ни в коем случае! Либо напрямую к питанию подключить, либо через LC или RC-фильтр.


Присоединил AVCC напрямую к батарее. ADC стал завышать напряжение (что в принципе можно и устранить вычитанием константы), но временами, проскакивают ошибки. laughing.gif

Вот еще что:
если делать несколько циклов "ацепирования", ну например через одну секунду десять раз, то ошибка появляется на первом, втором измерении, а все последующие - ок.
rezident
А в чем заключается ошибка "ацепирования"?
Ой, просмотрел
Код
измеряю напряжение на аккумуляторе по сл. алгоритму:

AREF = AVCC = Vbat
а можно схему посмотреть? Судя по тому что процитировано, вы измеряете напряжение питания относительно... самого напряжения питания? cranky.gif laughing.gif
Палыч
Цитата(Буратино @ Jun 29 2009, 16:49) *
Присоединил AVCC напрямую к батарее. ADC стал завышать напряжение (что в принципе можно и устранить вычитанием константы), но временами, проскакивают ошибки.
Завышает напряжение, наверное, потому, что согласно DS при MUX3..0=1110 к АЦП подключается 1.1V (Vbg). У Вас же в формуле 1.22

Цитата(Буратино @ Jun 29 2009, 16:49) *
если делать несколько циклов "ацепирования", ну например через одну секунду десять раз, то ошибка появляется на первом, втором измерении, а все последующие - ок.
То, что в первом измерении неверный результат - ему верить нельзя (в DS об этом прямо сказано: "The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result."). Со вторым неверным - хуже... У Вас REFS10=01 (т.е. "AVCC with external capacitor at AREF pin"). Про конденсатор в первом посте нет ни слова...
Буратино
Цитата(rezident @ Jun 29 2009, 19:02) *
А в чем заключается ошибка "ацепирования"?

Результат измерения "скачет": то 3,96В (правильно), то 2,78В (ошибка)

Цитата(rezident @ Jun 29 2009, 19:02) *
А можно схему посмотреть?

Нет никакой схемы! Вообще ничего (ну конденсатор 100н на питании проца, 1мкФ+10к на ресете, кварц и два по 27пФ это все). По идее АЦП измеряет напряжение питания относительно внутренней опоры.



Цитата(Палыч @ Jun 29 2009, 19:12) *
Завышает напряжение, наверное, потому, что согласно DS при MUX3..0=1110 к АЦП подключается 1.1V (Vbg). У Вас же в формуле 1.22

То, что в первом измерении неверный результат - ему верить нельзя (в DS об этом прямо сказано: "The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result."). Со вторым неверным - хуже... У Вас REFS10=01 (т.е. "AVCC with external capacitor at AREF pin"). Про конденсатор в первом посте нет ни слова...


Поставил в формулу 1,1В, Припаял к AREF электролит на 10мкФ, потом 100н. Теперь меряет так:
Показания прибора: 3,87В
Результат преобразования: 3,96В

Однако ошибка остается. Мне кажется, что она появляется после перехода из энергосберегающего режима (Power Down) в активный режим.
Результат ошибочного преобразования: 2,72-2,99В
rezident
Цитата(Буратино @ Jun 29 2009, 22:58) *
Нет никакой схемы! Вообще ничего. По идее АЦП измеряет напряжение питания относительно внутренней опоры.
Т.е. в качестве опоры для АЦП используется напряжение на AVCC или AREF, а напряжение от встроенного ИОН подается на измерительный вход? Я не очень хорошо знаю архитектуру ATmega128 и поэтому только предполагаю, что это возможно. Если так, то в таком случае скорее всего нарушены ADC Conversion Time.
Буратино
Чувство такое, будто внутри процессора проходит переходной процесс. Длится он (для емкости на AREF в 10мкФ ) несколько (1-2) секунд. Потом все "устаканивается" и очередные измерения проходят четко и точно.
Не понимаю maniac.gif
singlskv
Цитата(Палыч @ Jun 29 2009, 19:12) *
То, что в первом измерении неверный результат - ему верить нельзя (в DS об этом прямо сказано: "The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result.").
Как надоело читать эту глупость... sad.gif
Вам перевести "в предпоследний раз" что там написано ?
Перевод почти дословный:
"Если между преобразованиями сменилось опорное напряжение, то следующее измерение после такого изменения может быть не точным,
и пользователь должен это иметь в виду."

Хде Вы тут увидели смену опоры ? wassat.gif
DpInRock
В даташите АЦП посвещено нескольк страниц. И те не хотим читать.
1. Старший бит ADCSRA установить в 1 в самом начале и БОЛЬШЕ НИКОГДА НЕ СБРАСЫВАТЬ.
2. AREF не надо 10 микрофарад. Керамика 10 нанофарад. И больше этот вывод НИКУДА НЕ ПОДКЛЮЧАТЬ!!!!
3. Устанавливать только 6-й бит (старт измерений) по мере необходимости.
4. Если уж читаете содержимое регистрв АЦП в прерывании - делайте свои переменные, куда пишите ADCH-L - volatile.

Строго соблюдайте эти правила и будет вам щастье.

Ну и естественно, схема подключения к питанию микроконтроллера - согласно даташита. И никак иначе.
singlskv
Цитата(DpInRock @ Jun 30 2009, 04:56) *
Строго соблюдайте эти правила и будет вам щастье.

+5. Соблюдайте тайминги по времени переключения канала.

или делайте это только тогда когда это гарантированно режимом работы...
Палыч
Цитата(singlskv @ Jun 30 2009, 03:41) *
"Если между преобразованиями сменилось опорное напряжение, то следующее измерение после такого изменения может быть не точным,и пользователь должен это иметь в виду."
Хде Вы тут увидели смену опоры ? wassat.gif
Точнее, наверное, перевести так: "Первое измерение после смены опорного напряжения может быть неточным..." А вот - и смена опоры:
Цитата
ADMUX = (1<<REFS0)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1);
Палыч
Цитата(Буратино @ Jun 29 2009, 20:21) *
Нет никакой схемы! Вообще ничего (ну конденсатор 100н на питании проца, 1мкФ+10к на ресете, кварц и два по 27пФ это все).
Между VCC и AVCC производитель рекомендует ставить индуктивность и на AVCC - конденсатор.
Цитата(DpInRock @ Jun 30 2009, 03:56) *
1. Старший бит ADCSRA установить в 1 в самом начале и БОЛЬШЕ НИКОГДА НЕ СБРАСЫВАТЬ.
У автора, как я понимаю, МК переводится в энергосберегающий режим. При переходе в этот режим рекомендуется сбрасывать ADEN для уменьшения энергопотребления (как я понимаю: у автора вопроса питание устройства - от батареи, и лишнее потребление ему не к чему).
DpInRock
Код
AREF = AVCC = Vbat

Тут уже говорилось автору, что он вот так ничего не измерит.
То, что у него есть какой-т там результат, говорит о том, что автор неизвестно чего измеряет на самом деле.
И ни о каких энергосберегающих режимах речи не идет. Тем более с конденсатором в 10 микрофарад на AREF. Это выход опорника, мкротоковый и заряжать 10 микрфарад он будет очень долго.

Если уж экономить на резистивных делителях, то стоит замерять собственный уровень логической единицы поданный на измерительный вход через делитель. Тогда этот делитель можно отключать для экономии.
Палыч
Цитата(DpInRock @ Jun 30 2009, 10:31) *
Тут уже говорилось автору, что он вот так ничего не измерит.
То, что у него есть какой-т там результат, говорит о том, что автор неизвестно чего измеряет на самом деле.

Ну, почему же? Автор измеряет внутреннее напряжение 1.1В, используя в качестве опорного AVCC. Кстати, для точности измерения Vбат (которое равно VCC) индуктивность между VCC и AVCC, наверное, ставить не нужно.
Цитата(DpInRock @ Jun 30 2009, 10:31) *
И ни о каких энергосберегающих режимах речи не идет.

Выше автор говорил: "Мне кажется, что она появляется после перехода из энергосберегающего режима (Power Down) в активный режим."
Цитата(DpInRock @ Jun 30 2009, 10:31) *
Тем более с конденсатором в 10 микрофарад на AREF. Это выход опорника, мкротоковый и заряжать 10 микрфарад он будет очень долго.
Об этом уже сказали выше, и, надеюсь, автор вопроса этому внял...

Может быть, измерения неверные ещё и из-за того, что напряжение на батарее проседает при увеличении потребляемого тока в момент просыпания? Не лучше ли проверить измерения, запитав устройство от хорошего источника питания?
Буратино
поставил 10н на AREF, попробовал отключить вообще энергосберегающий режим, запитал схему от стабилизированного источника питания - результат один и тот-же: Первое измерение - результат не верный. Спустя секунду - встречаются правильные данные, спустя две секунды - ок.
Все последующие измерения - ок.

между AREF и землей-10н
AVCC замкнуто с питанием VBAT
100н на питании процессора.

Может быть есть у вас возможность в железе посмотреть?

Провел серию измерений: первые два - ошибочны, 300 последующих - точные.
Палыч
Цитата(Буратино @ Jun 30 2009, 11:48) *
Первое измерение - результат не верный. Спустя секунду - встречаются правильные данные, спустя две секунды - ок.
Все последующие измерения - ок.

Провел серию измерений: первые два - ошибочны, 300 последующих - точные.
Вы измерение делаете один раз в секунду? Или в цикле - подряд? Или каждую секунду - серию измерений? "Первые два - ошибочны" - это какие два?
Буратино
Цитата(Палыч @ Jun 30 2009, 13:18) *
Вы измерение делаете один раз в секунду? Или в цикле - подряд? Или каждую секунду - серию измерений? "Первые два - ошибочны" - это какие два?


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

первый раз - ошибка
второй раз - ошибка (иногда правильно)
все последующие - точно.

если сделать паузу в несколько секунд - все повторяется:

первый раз - ошибка
второй раз - ошибка (иногда правильно)
все последующие - точно.
DpInRock
Относительно чего ПЕРВЫЙ РАЗ? Например, после сброса, после выхода из слипа?
Вообще - первое преобразование практически всегда неточно.
И "ПЕРВЫМ" называется такое преобразование, перед которым трогали ADMUX, выключали питание ADC.

Также имеет значение емкость на AREF. Чтобы что-то быстро замерить и уйти в слип эту емкость надо делать как можно меньше. Иначе после переключения мультиплексора эта емкость будет очень долго заряжаться. И результат будет неверным, пока емкость не зарядится до конца.

Проверьте напряжение на рефе перед ПЕРВЫМ нажатием (то, которое дает ошибку).
rezident
А может кто-то наконец внятно объяснить что и относительно чего измеряется? А то из datasheet мне это как-то неочевидно.
Палыч
Цитата(rezident @ Jun 30 2009, 13:10) *
А может кто-то наконец внятно объяснить что и относительно чего измеряется? А то из datasheet мне это как-то неочевидно.
Измеряется Bandgap Reference (в m168 Vbg=1.1V) относительно AVCC. Это измерение - такая фича: нужно, собственно, измерить AVCC (оно же VCC) - поэтому измерение "наоборот". Интересное решение для измерения питающего напряжения, когда жесткая нехватка ног на МК...
Буратино
Цитата(DpInRock @ Jun 30 2009, 13:59) *
Относительно чего ПЕРВЫЙ РАЗ? Например, после сброса, после выхода из слипа?
Вообще - первое преобразование практически всегда неточно.
И "ПЕРВЫМ" называется такое преобразование, перед которым трогали ADMUX, выключали питание ADC.

Также имеет значение емкость на AREF. Чтобы что-то быстро замерить и уйти в слип эту емкость надо делать как можно меньше. Иначе после переключения мультиплексора эта емкость будет очень долго заряжаться. И результат будет неверным, пока емкость не зарядится до конца.

Проверьте напряжение на рефе перед ПЕРВЫМ нажатием (то, которое дает ошибку).


Один раз в секунду проссыпаюсь из режима Power Down, и делаю вот так:
__disable_interrupt();adc_init();ADCSRA |= (1<<ADEN); __enable_interrupt();
DelayMs(5);
f_bat=(1.1*1024/value_ADC);
V_BAT=(f_bat*100);
__disable_interrupt();ADCSRA &= ~(1<<ADEN); __enable_interrupt();
и снова в спячку

Напряжение на AREF всегда равно питанию.
dimka76
Цитата(rezident @ Jun 30 2009, 14:10) *
А может кто-то наконец внятно объяснить что и относительно чего измеряется? А то из datasheet мне это как-то неочевидно.


Схема я думаю примерно такая
Нажмите для просмотра прикрепленного файла

И меряется Bandgap Reference.
При изменении AVCC (которое и опорное) изменяются значения АЦП. Ведь Bandgap Reference = const
rezident
Цитата(Палыч @ Jun 30 2009, 16:25) *
Измеряется Bandgap Reference (в m168 Vbg=1.1V) относительно AVCC.
ОК. Теперь понятно. Судя из названия, это напряжение подается только на момент измерения? Или присутствует на (внутреннем) входе мультиплексора постоянно (и в режиме энергосбережения тоже)?
dimka76
Цитата(Буратино @ Jun 30 2009, 14:26) *
первый раз - ошибка
второй раз - ошибка (иногда правильно)
все последующие - точно.


ну так и делайте серию например из 5-10 измерений, первые три отбрасывать, остальные усреднять и в спячку.
Палыч
Цитата(rezident @ Jun 30 2009, 13:35) *
Судя из названия, это напряжение подается только на момент измерения? Или присутствует на (внутреннем) входе мультиплексора постоянно (и в режиме энергосбережения тоже)?
Кстати! Bandgap Reference включен, если 1) включен BOD или 2) включен компаратор или 3) включен АЦП. После включения ADEN нужно дождаться выхода на рабочий режим Bandgap Reference (это, наверное, десятки мкс - под рукой нет DS чтобы проверить). Поэтому нельзя выставлять ADEN и ADSC вместе!
Буратино
Цитата(Палыч @ Jun 30 2009, 14:51) *
Кстати! Bandgap Reference включен, если 1) включен BOD или 2) включен компаратор или 3) включен АЦП. После включения ADEN нужно дождаться выхода на рабочий режим Bandgap Reference (это, наверное, десятки мкс - под рукой нет DS чтобы проверить). Поэтому нельзя выставлять ADEN и ADSC вместе!


все что понял попробовал. BOD у меня включен, после инициализации АЦП делаю паузу, потом запускаю преобразование, но на первых измерениях всегда ошибка. Блин, ну что в ADC может давать такой "фифект"?
defunct
Цитата(singlskv @ Jun 30 2009, 03:41) *
Перевод почти дословный:
"Если между преобразованиями сменилось опорное напряжение, то следующее измерение после такого изменения может быть не точным,
и пользователь должен это иметь в виду."

Неточный у вас перевод. Не должен иметь в виду, а рекомендуется выбрасывать этот (первый после смены reference) результат измерения.

Цитата(Буратино @ Jun 30 2009, 16:29) *
все что понял попробовал. BOD у меня включен, после инициализации АЦП делаю паузу, потом запускаю преобразование, но на первых измерениях всегда ошибка. Блин, ну что в ADC может давать такой "фифект"?

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

ADCSRA = (1 < ADEN);
ADCSRA |= (1 << ADSC) | (1 << ADIF);
while( !(ADCSRA & ADIF)); // <-- дождаться первого результата и выбросить его
ADCSRA |= (1 << ADSC) | (1 << ADIF); <<-- еще раз оцифровать
while( !(ADCSRA & ADIF)); // <-- дождаться второго результата преобразования

result = ADC; <-- пользовать этот результат второго преобразования
Палыч
Цитата(Буратино @ Jun 30 2009, 16:29) *
все что понял попробовал. BOD у меня включен, после инициализации АЦП делаю паузу, потом запускаю преобразование, но на первых измерениях всегда ошибка. Блин, ну что в ADC может давать такой "фифект"?
Вы бы программу привели: что у Вас получилось после переделок? И потом: "на первых измерения" - как понимать? Вы делаете после просыпания из спячки серию измерений и первое измерение в серии - неверное? Или первое измерение после подачи питания на устройство?
DpInRock
Замечание по ходу. Использование ADC_isr в данном случае ничего не дает, кроме увеличения размера программы.
Алгоритм такой.
Выход из слипа.
Замер.
Отброс первого.
Замер.
Слип.

И никаких прерываний.
Буратино
Код
#pragma vector= ADC_vect
__interrupt void ADC_vect_isr (void)
{  
                                                        
  value_ADC=ADCL;                          
  value_ADC|=(int)ADCH << 8;          
}

//ADC initialize
// Conversion time: 104uS
void adc_init(void)
{
ADMUX = (1<<REFS0)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1);
ADCSRB = 0x00;
ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0);
}

main(void)
{
   ...
   adc_init();
   ...
   ...
   while(1)
   {

   ...
       ADCSRA = (1<<ADEN);
       ADCSRA |= (1 << ADSC) | (1 << ADIF);
       while( !(ADCSRA & ADIF));  
       ADCSRA |= (1 << ADSC) | (1 << ADIF);
       while( !(ADCSRA & ADIF));
       f_bat=(1.1*1024/value_ADC);
       V_BAT=(f_bat*100);
       ADCSRA &= ~(1<<ADEN);
   ...
   asm("sleep");  //выход после нажатия кнопки, например.
   ...
   }
}


измеряет неправильно только один раз (после первого нажатия кнопки), потом виснет в циклах ожидания окончания преобразования. Шота я совсем запутался. Как говорит мой сосед : с мыслью нужно переспать. НУжно наверное отдохнуть.
singlskv
Цитата(Палыч @ Jun 30 2009, 09:36) *
Точнее, наверное, перевести так: "Первое измерение после смены опорного напряжения может быть неточным..." А вот - и смена опоры:
Нету там смены опоры, REFSx устанавливаются только 1 раз за всю прогу...,
другое дело что включение/выключение заново все переинициализирует и требует перезарядки конденсатора на AREF,
а с измерительным конденсатором все путем(при соблюдении требований даташита по входному сопротивлению),
первый цикл после включения занимает не 13 а 25 тактов fADC.





Цитата(Буратино @ Jun 30 2009, 14:26) *
Один раз в секунду проссыпаюсь из режима Power Down, и делаю вот так:
__disable_interrupt();adc_init();ADCSRA |= (1<<ADEN); __enable_interrupt();
DelayMs(5);
f_bat=(1.1*1024/value_ADC);
V_BAT=(f_bat*100);
__disable_interrupt();ADCSRA &= ~(1<<ADEN); __enable_interrupt();
и снова в спячку

value_ADC объявлено как volatile ?
чтение value_ADC в основной проге нужно делать с выключенными прерываниями

ну и покажите наконец схему...
DpInRock
А у кого вы научились так АЦП опрашивать? Вот отчего бы не взять способ из даташита?
Что заставляет так сильно усложнять жизнь и портить элементарный алгоритм?

Уберите ненужные прерывания наконец. Тем более, не видно описаний переменных. Если слова volatile в программе не присутствует, то фигня будет...

Ну, и кроме того, не видно к какой слип входит процессор.
Буратино
Цитата(DpInRock @ Jun 30 2009, 23:32) *
А у кого вы научились так АЦП опрашивать? Вот отчего бы не взять способ из даташита?

просмотрел главу с ацп, но примеров не нашел.

Цитата(DpInRock @ Jun 30 2009, 23:32) *
Уберите ненужные прерывания наконец. Тем более, не видно описаний переменных. Если слова volatile в программе не присутствует, то фигня будет...
Ну, и кроме того, не видно к какой слип входит процессор.

переменная "value_ADC" объявлена,как глобальная и volatile.
энергосберегающий режим: SMCR = (1<<SM1)|(1<<SE);

Я вот тут подумал, Что ошибка измерения всегда одинаковая и составляет что-то около 1,1В! (проверю завтра предметно)

Я завтра соберу вместе все рекомендации, запишу в столбик и поправлю код, но все же может есть возможность в железе проверить у кого? Ведь хорошая штука получается, но у меня шото не работающаяsad.gif

Цитата(singlskv @ Jun 30 2009, 23:03) *
ну и покажите наконец схему...

схему чего? всего устройства? обвязки АЦП?
Если второе, то повторяю - нет ничего вообще! ну разве только керамика в 10n на AREFe (но вопросу она не помогла) и 100n на питании проца.
DpInRock
Я лично точно также измеряю абсолютное напряжение на датчике.

На AREF должен быть только конденсатор и БОЛЬШЕ НИЧЕГО!!!! Конденсатор - маленькой емкости. Если нет такого (в наличии) - вообще ничего не ставьте. У меня в такой схеме стоит 100 ПИКОФАРАД.
ADMUX=0x4E. Навечно.

Далее после прoсыпа.
ADCSRA=0x87;
//Тут - задержка на заряд емкости на AREF
//
ADCSRA=0xC7;
while((ADCSRA&(1<<ADSC))!=0);
Battery=ADCL;Battery=Battery+(ADCH<<8);

Если емкость до конца не зарядится - то результат будет неверным.
Палыч
Цитата(Буратино @ Jun 30 2009, 21:49) *
Код
#pragma vector= ADC_vect
__interrupt void ADC_vect_isr (void)
{  
  value_ADC=ADCL;                          
  value_ADC|=(int)ADCH << 8;          
}

void adc_init(void)
{
  ...
  ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0);
}

main(void)
{
   ...
   adc_init();
   ...
   while(1)
   {
   ...
       ADCSRA = (1<<ADEN);
       ADCSRA |= (1 << ADSC) | (1 << ADIF);
   ...
   }
}

Чего-то Вы немного промахнулись.
1. В main включать ADEN нужно, примерно, так
ADCSRA |= (1<<ADEN);
или как-то так
ADCSRA = (1<<ADEN)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0);
В общем, нужно выставить ADEN и при этом не сбросить другие, нужные биты настроек!
2. Вы встроили пример от defunct, но этот пример не использует прерываний (по готовности), а остальная часть Вашей программы осталась неизменной. Вы уж решите для себя: будите использовать прерывания или нет? Честно говоря, необходимости в прерываниях от АЦП в Вашем случае я не вижу.
3. Bandgap Reference (если он выключен) выходит на режим за 70 мкс. Значит, между установкой в единицу ADEN и стартом преобразования должна быть задержка.
4. Мелочь, конечно, но считать значение АЦП, обычно, лучше так
value_ADC= ADC;

P.S. При инициализации АЦП Вы старт преобразования зачем делаете? Убрать первое после смены опоры преобразование?
dimka76
Вот еще одна шибка.
MUXn и REFS1:0 биты имеют буферизацию. И новые значения вступают в силу после одного такта АЦП.
DS стр. 249
Цитата
The MUXn and REFS1:0 bits in the ADMUX Register are single buffered through a temporary
register to which the CPU has random access.

Цитата
Note that the conversion starts on the following rising ADC clock edge after
ADSC is written. The user is thus advised not to write new channel or reference selection values
to ADMUX until one ADC clock cycle after ADSC is written.

Отсюда у вас первое ошибочное измерение.
И при смене опоры первое измерение тоже ошибочное. Вот вам и второе ложное измерение.
Палыч
Цитата(dimka76 @ Jul 1 2009, 11:10) *
MUXn и REFS1:0 биты имеют буферизацию. И новые значения вступают в силу после одного такта АЦП. Отсюда у вас первое ошибочное измерение. И при смене опоры первое измерение тоже ошибочное. Вот вам и второе ложное измерение.
Все эти биты размещены в одном регистре ADMUX и изменяются в программе один раз. Биты REFS1:0 собственно и определяют опору - поэтому одно действие вызвать два ложных измерения, имхо, не может. Да и между инициализацией АЦП и просыпанием из спячки (когда производится измерение АЦП) пройдёт больше одного такта АЦП.
Возможно, что неверное измерение АЦП при выходе из спячки возникает из-за выключения/включения АЦП битом ADEN. В документации никаких предупреждений по использованию ADEN не нашёл, а сам я таким образом АЦП ни разу не использовал - поэтому это ИМХО.
dimka76
Цитата(Палыч @ Jul 1 2009, 12:30) *
Все эти биты размещены в одном регистре ADMUX и изменяются в программе один раз. Биты REFS1:0 собственно и определяют опору - поэтому одно действие вызвать два ложных измерения, имхо, не может. Да и между инициализацией АЦП и просыпанием из спячки (когда производится измерение АЦП) пройдёт больше одного такта АЦП.


Вот код автора
Код
void adc_init(void)
{
ADMUX = (1<<REFS0)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1);
ADCSRB = 0x00;
ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0);
}

В первой строчке он изменяет мультиплексор.
В третий дает старт АЦП.
АЦП стартанет не с этим состояние мультиплексора, а в это состояние он придет после первого преобразования.
А после первого преобразование обнаружится, что и опора сменилась. Вот и еще одно потерянное преобразование.

А это мое ИМХО smile.gif
Палыч
Цитата(dimka76 @ Jul 1 2009, 11:41) *
А после первого преобразование обнаружится, что и опора сменилась. Вот и еще одно потерянное преобразование.
Недоставерный результат преобразования после смены опоры связан, скорее всего, с переходными процессами на входе DAC АЦП. К концу первого преобразования переходные процессы закончатся и никто смену опоры уже не обнаружит.
DpInRock
Не путайте товарища. Какие еще 70 микросекунд...
Цитата
Note that VREF is a high
impedance source, and only a capacitive load should be connected in a system.

Повесьте на этот вывод электролит и ждать готовности будуте очень долго.
Палыч
Цитата(DpInRock @ Jul 1 2009, 13:13) *
Не путайте товарища. Какие еще 70 микросекунд...
Извините, но это Вы путаете опорное напряжение с Bandgap Reference. Последнее - это внутренний источник напряжения, который может быть подключен на вход АЦП для измерения.
Кстати, внимательное прочтение DS показало, что Vbg - вещь довольно неточная: при типичном значении Vbg=1.1V может принимать значения от 1.0 до 1.2 вольта (для m168). Т.е. предложенным методом ошибка измерения (без калибровки) может достигать 9%.
DpInRock
А вот и нет.
Цитата
the reference voltage can be made
more immune to noise by connecting a capacitor between the AREF pin and ground. VREF can
also be measured at the AREF pin with a high impedance voltmeter.

Бангап также подключается (проходит) через АРЕФ. И емкость на этом выводе убьет быстродействие.

Кстати и это напряжение есть функция питающего напряжения. А раз опора - питающее напряжение - то точность хуже не станет. Вернее станет, но не настолько.
Буратино
Всем спасибо. Работает rolleyes.gif
ниже приведу код:
Код
...
static volatile unsigned  int value_ADC;
...

void adc_init(void)
{
   ADMUX = (1<<REFS0)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1);
   ADCSRB = 0x00;
   ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS0);
}


main(void)
{    
   unsigned char V_BAT;
   float f_bat;
   ...
   adc_init();
   ...  

   while(1)
   {  
       ...
       for (i=0;i<5;i++)
       {
       ADCSRA=0x87;
       DelayMs(1);      
       while((ADCSRA&(1<<ADSC))!=0);
       ADCSRA=0xC7;
       }
       value_ADC= ADC;
       f_bat=(1.1*1024/value_ADC);
       V_BAT=(f_bat*100) - 250; // отнимаю 250 для того, чтоб результат уложился в восемь бит (так нужно)
       ...
   }
}


Не понял: почему если объявить "value_ADC" локально и, как "unsigned int" программа не работает. Вообще виснет и фик его знает где. 07.gif

Всем большое спасибо! Палычу и DpInRock - вселенский респект!
По поводу точности могу сказать следующее: С закороченым AVCC на VBAT, без конденсатора на AREF - больше, чем на 0,04-0,08 вольта АЦП не врал. (это при том, что я меряю 3,6вольтовую сборку аккумов) Мои цели, такой точностью, замечательно достигаются.
Палыч
Цитата(Буратино @ Jul 1 2009, 14:29) *
Код
...
   while(1)
   {  
       ...
       for (i=0;i<5;i++)
       {
       ADCSRA=0x87;
       DelayMs(1);      
       while((ADCSRA&(1<<ADSC))!=0);
       ADCSRA=0xC7;
       }
       ...
   }
}
Ну-у-у... Странная конструкция... Вы пять раз запускаете преобразование, и только последний результат берёте (да и тот сразу после последнего пуска!)... За что боролись? Вроде бы получить верное измерение с первого (ну, может быть, со второго) раза. Выключения АЦП (сброса ADEN) в программе не наблюдается... Регистр ADCSRA в main портится: в init задаётся (1<<ADEN)|(1<<ADPS2)|(1<<ADPS0) в main (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0). Присваивать регистрам константы (типа 0x87, 0xC7) - моветон!
Имхо, если АЦП не выключать, то этот кусок программы можно записать так
Код
...
   while(1)
   {  
       ...
       for (i=0;i<5;i++)
       {
       ADCSRA|= (1<<ADSC);
       while((ADCSRA&(1<<ADSC))!=0);
       }
       ...
   }
}
(Р.S. думаю, что и for здесь лишний, раз не выключаете АЦП) Или ADEN всё-таки сбрасывается\устанавливается, но не приведено здесь?

Цитата(Буратино @ Jul 1 2009, 14:29) *
По поводу точности могу сказать следующее: С закороченым AVCC на VBAT, без конденсатора на AREF - больше, чем на 0,04 вольта АЦП не врал.
Из документации не видно от чего зависит истинное значение Vbg. Может быть от партии к партии МК оно разное, от температуры, питающего напряжения, фиг его знает от чего ещё...
Буратино
вот:
Код
...
static volatile unsigned  int value_ADC;
...

void adc_init(void)
{
   ADMUX = (1<<REFS0)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1);
   ADCSRB = 0x00;
   ADCSRA = (1<<ADPS2)|(1<<ADPS0);
}


main(void)
{    
   unsigned char V_BAT;
   float f_bat;
   ...
   adc_init();
   ...  

   while(1)
   {  
       ...
       ADCSRA |= (1<<ADEN);
      
       ADCSRA|= (1<<ADSC);
       while((ADCSRA&(1<<ADSC))!=0);
       value_ADC= ADC;
       f_bat=(1.1*1024/value_ADC);
       V_BAT=(f_bat*100);    
      
       ADCSRA &= ~(1<<ADEN);        
    
      ...
      asm("sleep");                         //выход по прерыванию INT0
      ...

   }
}
Палыч
Цитата(Буратино @ Jul 1 2009, 15:46) *
вот:
А, результат работы этого?
Буратино
Цитата(Палыч @ Jul 1 2009, 19:56) *
А, результат работы этого?


Точный процесс аналого-цифрового преобразования с первого раза.
Правда в расчетах V_BAT=(f_bat*100); я делаю V_BAT=(f_bat*100)-250; для того, чтоб разместить значение в "unsigned char". Так нужно. А в коде не стал на этом акцентировать внимание.
Палыч
Цитата(Буратино @ Jul 1 2009, 19:27) *
Код
   unsigned char V_BAT;
   float f_bat;
   ......
   f_bat=(1.1*1024/value_ADC);
   V_BAT=(f_bat*100)-250;
Плавающая запятая - не напрягает? Или ресурсов - валом? Наверное лучше было бы как-то так:

V_BAT=(112640L / value_ADC) - 250;
Буратино
Цитата(Палыч @ Jul 2 2009, 09:14) *
Плавающая запятая - не напрягает? Или ресурсов - валом? Наверное лучше было бы как-то так:

V_BAT=(112640L / value_ADC) - 250;



Да, спасибо.
И еще последнее: все таки после "ADCSRA |= (1<<ADEN);" в реальной программе проходит время. Около 2-5ms.
Включается "ацепометр" сразу после выхода из режима сна, потом проделывается определенная работа ,и только потом запускается сам процесс преобразования "ADCSRA|= (1<<ADSC);"
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.