|
|
  |
ADC Mega168. Измерение напряжения "наоборот". |
|
|
|
Jun 30 2009, 19:03
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Палыч @ 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 в основной проге нужно делать с выключенными прерываниями ну и покажите наконец схему...
|
|
|
|
|
Jun 30 2009, 20:04
|

Профессионал
    
Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215

|
Цитата(DpInRock @ Jun 30 2009, 23:32)  А у кого вы научились так АЦП опрашивать? Вот отчего бы не взять способ из даташита? просмотрел главу с ацп, но примеров не нашел. Цитата(DpInRock @ Jun 30 2009, 23:32)  Уберите ненужные прерывания наконец. Тем более, не видно описаний переменных. Если слова volatile в программе не присутствует, то фигня будет... Ну, и кроме того, не видно к какой слип входит процессор. переменная "value_ADC" объявлена,как глобальная и volatile. энергосберегающий режим: SMCR = (1<<SM1)|(1<<SE); Я вот тут подумал, Что ошибка измерения всегда одинаковая и составляет что-то около 1,1В! (проверю завтра предметно) Я завтра соберу вместе все рекомендации, запишу в столбик и поправлю код, но все же может есть возможность в железе проверить у кого? Ведь хорошая штука получается, но у меня шото не работающая  Цитата(singlskv @ Jun 30 2009, 23:03)  ну и покажите наконец схему... схему чего? всего устройства? обвязки АЦП? Если второе, то повторяю - нет ничего вообще! ну разве только керамика в 10n на AREFe (но вопросу она не помогла) и 100n на питании проца.
Сообщение отредактировал Буратино - Jun 30 2009, 20:05
--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
|
|
|
|
|
Jul 1 2009, 05:45
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(Буратино @ 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. При инициализации АЦП Вы старт преобразования зачем делаете? Убрать первое после смены опоры преобразование?
|
|
|
|
|
Jul 1 2009, 08:10
|

developer
   
Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032

|
Вот еще одна шибка. 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. Отсюда у вас первое ошибочное измерение. И при смене опоры первое измерение тоже ошибочное. Вот вам и второе ложное измерение.
--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
|
|
|
|
|
Jul 1 2009, 08:41
|

developer
   
Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032

|
Цитата(Палыч @ 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); } В первой строчке он изменяет мультиплексор. В третий дает старт АЦП. АЦП стартанет не с этим состояние мультиплексора, а в это состояние он придет после первого преобразования. А после первого преобразование обнаружится, что и опора сменилась. Вот и еще одно потерянное преобразование. А это мое ИМХО
--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
|
|
|
|
|
Jul 1 2009, 11:24
|

Гуру
     
Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515

|
А вот и нет. Цитата 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. Бангап также подключается (проходит) через АРЕФ. И емкость на этом выводе убьет быстродействие. Кстати и это напряжение есть функция питающего напряжения. А раз опора - питающее напряжение - то точность хуже не станет. Вернее станет, но не настолько.
--------------------
On the road again (Canned Heat)
|
|
|
|
|
Jul 1 2009, 11:29
|

Профессионал
    
Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215

|
Всем спасибо. Работает ниже приведу код: Код ... 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" программа не работает. Вообще виснет и фик его знает где. Всем большое спасибо! Палычу и DpInRock - вселенский респект! По поводу точности могу сказать следующее: С закороченым AVCC на VBAT, без конденсатора на AREF - больше, чем на 0,04-0,08 вольта АЦП не врал. (это при том, что я меряю 3,6вольтовую сборку аккумов) Мои цели, такой точностью, замечательно достигаются.
Сообщение отредактировал Буратино - Jul 1 2009, 11:50
--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
|
|
|
|
|
Jul 1 2009, 12:03
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(Буратино @ 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. Может быть от партии к партии МК оно разное, от температуры, питающего напряжения, фиг его знает от чего ещё...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|