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

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
Буратино
сообщение Jun 30 2009, 18:49
Сообщение #31


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

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



Код
#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");  //выход после нажатия кнопки, например.
   ...
   }
}


измеряет неправильно только один раз (после первого нажатия кнопки), потом виснет в циклах ожидания окончания преобразования. Шота я совсем запутался. Как говорит мой сосед : с мыслью нужно переспать. НУжно наверное отдохнуть.

Сообщение отредактировал Буратино - Jun 30 2009, 18:50


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jun 30 2009, 19:03
Сообщение #32


дятел
*****

Группа: Свой
Сообщений: 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 в основной проге нужно делать с выключенными прерываниями

ну и покажите наконец схему...
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Jun 30 2009, 19:32
Сообщение #33


Гуру
******

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



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

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

Ну, и кроме того, не видно к какой слип входит процессор.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jun 30 2009, 20:04
Сообщение #34


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

Группа: Свой
Сообщений: 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В! (проверю завтра предметно)

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

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

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

Сообщение отредактировал Буратино - Jun 30 2009, 20:05


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Jun 30 2009, 20:29
Сообщение #35


Гуру
******

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



Я лично точно также измеряю абсолютное напряжение на датчике.

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

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

Если емкость до конца не зарядится - то результат будет неверным.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jul 1 2009, 05:45
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 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. При инициализации АЦП Вы старт преобразования зачем делаете? Убрать первое после смены опоры преобразование?
Go to the top of the page
 
+Quote Post
dimka76
сообщение Jul 1 2009, 08:10
Сообщение #37


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.

Отсюда у вас первое ошибочное измерение.
И при смене опоры первое измерение тоже ошибочное. Вот вам и второе ложное измерение.


--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jul 1 2009, 08:30
Сообщение #38


Гуру
******

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



Цитата(dimka76 @ Jul 1 2009, 11:10) *
MUXn и REFS1:0 биты имеют буферизацию. И новые значения вступают в силу после одного такта АЦП. Отсюда у вас первое ошибочное измерение. И при смене опоры первое измерение тоже ошибочное. Вот вам и второе ложное измерение.
Все эти биты размещены в одном регистре ADMUX и изменяются в программе один раз. Биты REFS1:0 собственно и определяют опору - поэтому одно действие вызвать два ложных измерения, имхо, не может. Да и между инициализацией АЦП и просыпанием из спячки (когда производится измерение АЦП) пройдёт больше одного такта АЦП.
Возможно, что неверное измерение АЦП при выходе из спячки возникает из-за выключения/включения АЦП битом ADEN. В документации никаких предупреждений по использованию ADEN не нашёл, а сам я таким образом АЦП ни разу не использовал - поэтому это ИМХО.
Go to the top of the page
 
+Quote Post
dimka76
сообщение Jul 1 2009, 08:41
Сообщение #39


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);
}

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

А это мое ИМХО smile.gif


--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jul 1 2009, 08:53
Сообщение #40


Гуру
******

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



Цитата(dimka76 @ Jul 1 2009, 11:41) *
А после первого преобразование обнаружится, что и опора сменилась. Вот и еще одно потерянное преобразование.
Недоставерный результат преобразования после смены опоры связан, скорее всего, с переходными процессами на входе DAC АЦП. К концу первого преобразования переходные процессы закончатся и никто смену опоры уже не обнаружит.
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Jul 1 2009, 10:13
Сообщение #41


Гуру
******

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



Не путайте товарища. Какие еще 70 микросекунд...
Цитата
Note that VREF is a high
impedance source, and only a capacitive load should be connected in a system.

Повесьте на этот вывод электролит и ждать готовности будуте очень долго.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jul 1 2009, 10:30
Сообщение #42


Гуру
******

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



Цитата(DpInRock @ Jul 1 2009, 13:13) *
Не путайте товарища. Какие еще 70 микросекунд...
Извините, но это Вы путаете опорное напряжение с Bandgap Reference. Последнее - это внутренний источник напряжения, который может быть подключен на вход АЦП для измерения.
Кстати, внимательное прочтение DS показало, что Vbg - вещь довольно неточная: при типичном значении Vbg=1.1V может принимать значения от 1.0 до 1.2 вольта (для m168). Т.е. предложенным методом ошибка измерения (без калибровки) может достигать 9%.
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Jul 1 2009, 11:24
Сообщение #43


Гуру
******

Группа: Участник
Сообщений: 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)
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jul 1 2009, 11:29
Сообщение #44


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

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



Всем спасибо. Работает 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, 11:50


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jul 1 2009, 12:03
Сообщение #45


Гуру
******

Группа: Свой
Сообщений: 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. Может быть от партии к партии МК оно разное, от температуры, питающего напряжения, фиг его знает от чего ещё...
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st June 2025 - 22:40
Рейтинг@Mail.ru


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